Download presentation
Presentation is loading. Please wait.
Published byAbigail Newman Modified over 9 years ago
1
Java Gotcha's By Rick Mercer with help from the book:
Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter
2
Every programming language has its quirks.
Are you a code sleuth? Have you ever spent days chasing a bug caused by a trap or pitfall in Java or its libraries? Here are some diabolical puzzles
3
Oddity // Does this method return true if n is odd?
public boolean isOdd(int n) { return n % 2 == 1; }
4
Ö Yes, but it's wrong when n is negative // Try this
return n % 2 != 0; // or use bitwise AND operation (faster) return (n & 1) == 1; // n & 1 ands the rightmost bit with 1 // if n is 25, n & 1 is 1 // & is // Expression is 0 unless n is odd // if n is 24, n & 1 is 0 // & is
5
Simple Arithmetic @Test public void simpleArithmetic() {
// Does this assertion pass? assertEquals(444, l); }
6
Ö Eyes Deceive It is 123 + 32L, which is 155
Use L instead of l for Long
7
The laughs are on me @Test public void simpleChars() {
// Which, if any, of these two assertions pass? assertEquals("Ha", "H" + "a"); // a. assertEquals("Ha", 'H' + 'a'); // b. }
8
Ö Answer Only a. java.lang.AssertionError:
expected:<Ha> but was:<169>
9
Operator Precedence @Test public void stringIntern() {
String pig = "length: 10"; String dog = "length: " + pig.length(); // Which, if any, of these two assertions pass? assertEquals("Animals equal: false", "Animals equal: " + pig == dog); assertEquals("Animals equal: true", }
10
Ö Neither. Precedence rules have + evaluating before ==. The actual value (2nd arg to assert) is "Animals equal: " + pig == dog which evaluates to "Animals equal: pig" == dog which as an argument evaluates to false assertEquals uses the equals method when the type do not match, equals returns false "string".equals(true) is false These asssertions pass assertEquals("Animals equal: false", "Animals equal: " + (pig == dog)); assertEquals("Animals equal: true", "Animals equal: " + (pig.equals(dog)));
11
From a 227 Student Can this recursive solution ever work?
// Part of escape obstacle course in findExit if(escape = false) findExit(r-1, c); // row above findExit(r, c+1); // col to the right Can this recursive solution ever work?
12
Ö No The boolean expressions are ALWAYS false
An assignment statement evaluates to the value of the right value (expression to the right of =) What is the value of booleanVar = true
13
From a 127B Student Can this recursive solution ever work? @Test
public void testRecursion() { assertEquals(6, sumInts(3)); } int sumInts(int n) { if(n <= 1) return n; else return n * sumInts(n--); Can this recursive solution ever work?
14
Ö No n is not decremented until after the function call Use f(n-1)
f(n--) results in a StackOverflowError Use f(n-1)
15
Output from this program?
\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020\u0020 \u0063\u006c\u0061\u0073\u0073\u0020\u0055\u0067\u006c\u0079 \u007b\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020 \u0020\u0020\u0020\u0020\u0073\u0074\u0061\u0074\u0069\u0063 \u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028 \u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0020 \u0020\u0020\u0020\u0020\u0061\u0072\u0067\u0073\u0029\u007b \u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074 \u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0020 \u0022\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u0022\u002b \u0022\u006f\u0072\u006c\u0064\u0022\u0029\u003b\u007d\u007d
16
Ö Answer: Unicode not very readable
Hello World \u0070 in hexadecimal is 112 in decimal or the character 'p' Unicode not very readable Suggestion" avoid Unicode till you need it System.out.println( " \u20ac" ); €
17
'\u0040'); assertEquals('A', '\u0041'); assertEquals('B', '\u0042'); assertEquals('`', '\u0060'); assertEquals('a', '\u0061'); assertEquals('b', '\u0062'); assertEquals('€', '\u20ac');
18
Is “true” true? @Test public void trueOr() {
// Does this assertion pass? assertEquals("Compare 5 to 4", "true", 5 > 4); }
19
Ö Answer "true" is not true However, JUnit show this: No
java.lang.AssertionError: Compare 5 to 4 expected:<true> but was:<true>
20
Output? @Test public void whoopsForgotToBreak() { int choice = 2;
switch (choice) { case 1: System.out.println("one"); case 2: System.out.println("two"); case 3: System.out.println("three"); }
21
Ö Add breaks two three int choice = 2; switch (choice) { case 1:
System.out.println("one"); break; case 2: System.out.println("two"); case 3: System.out.println("three"); }
22
BTW: Java 7 allows String in a switch statement String choice = "2";
switch (choice) { case "1": System.out.println("one"); break; case "2": System.out.println("two"); case "3": System.out.println("three"); }
23
Java plus plus @Test public void thatDarnedPostIncrement() {
int j = 0; for (int i = 0; i < 10; i++) j = j++; // Does this assertion pass? assertEquals(10, j); }
24
Ö Answer: No Use ++j; instead j = j++; is postfix increment operator
j is 0 after the loop When you use a postfix operator as part of a larger expression, the expression's value is returned before the postfix operator is processed the assignment completes before the increment Use ++j; instead
25
Output? int j = 0; int k = 0; System.out.println(j++); //? _____
System.out.println(++k); //? _____ System.out.println(j); //? _____ int[] x = { 5, 4, 3 }; int i = 0; System.out.println(i + " " + x[i++]); //? _____ System.out.println(i + " " + x[i]); //? _____ System.out.println(i + " " + x[++i]); //? _____
26
O 0 1 With array
27
Is there any Output? public class Huh {
public static void main(String[] args) { new B(); } class B { int j; String s; { System.out.println("Hello world " + j + " " + s);
28
Ö Answer: Yes This is an initializer, a method with no heading; { }
Hello world 0 null This is an initializer, a method with no heading; { }
29
Add to 0 three times @Test public void testBigInt() {
BigInteger five = new BigInteger("5"); BigInteger fifty = new BigInteger("50"); BigInteger fiveHundred = new BigInteger("500"); BigInteger total = BigInteger.ZERO; total.add(five); total.add(fifty); total.add(fiveHundred); // Does this assertion pass? assertEquals(555, total); }
30
Ö No BigInteger, like String is immutable This will pass
BigInteger total = BigInteger.ZERO; total = total.add(five); total = total.add(fifty); total = total.add(fiveHundred); // Does this assertion pass assertEquals(555, total);
31
No Warning @Test public void testHashMap() {
HashMap<String, BigInteger> hm = new HashMap<String, BigInteger>(); hm.put("a", new BigInteger("123456")); hm.put("b", new BigInteger(" ")); hm.put("c", new BigInteger(" ")); hm.put("a", new BigInteger("654321")); BigInteger aBigInt = hm.get("a"); // Does this assertion pass? assertEquals(123456, aBigInt.intValue()); }
32
Ö No, the first mapping was destroyed
// Return old value if the key exists // return null if there was no mapping to the key hm.put("a", new BigInteger("123456")); BigInteger bi = hm.put("a", new BigInteger("9999")); // put returned the old value mapped to the key "a" assertEquals(123456, bi.intValue());
33
Output? int n = 0; try { n = n / 0; } catch (Exception e) {
System.out.println("A"); } finally { System.out.println("B"); } System.out.println("C");
34
Ö A B C Finally blocks always execute unless System.exit(0) is encountered first
35
Output? int n = 0; try { n = n / 999; } catch (Exception e) {
System.out.println("A"); } finally { System.out.println("B"); } System.out.println("C");
36
Ö B C
37
Output int n = 0; try { n = n / 999; } catch (Exception e) {
System.out.println("A"); System.exit(0); } finally { System.out.println("B"); } System.out.println("C");
38
Ö B C
39
Output int n = 0; try { n = n / 0; } catch (Exception e) {
System.out.println("A"); System.exit(0); } finally { System.out.println("B"); } System.out.println("C");
40
Ö A
41
To intern or not to intern
String data = new String("123"); String moreData = new String("123"); System.out.println(data==moreData); To intern or not to intern Which assertion(s) pass? 1 and 2 1 only 2 only Neither @Test public void stringIntern() { String s1 = "UofA"; String s2 = new String("UofA"); assertTrue(s1.equals(s2)); // 1 assertTrue(s1 == s2); // 2 }
42
Ö b) 1 only == compares reference values, with new, a new string is created. Without new, Java tries to find the characters in the string pool where all instances of String are stored. If found, Java returns a reference to the existing instance In Java, String is a Flyweight to save memory Both of these assertions pass: String s1 = "UofA"; String s2 = "UofA"; assertTrue(s1.equals(s2)); // 1 assertTrue(s1 == s2); // 2
43
To intern or not to intern
@Test public void testIntegerInterns() { Integer a = -128; Integer b = -128; Integer c = 127; Integer d = 127; Integer e = 345; Integer f = 345; // Which, if any, of these assertions fail? assertTrue(a == b); // a. assertTrue(c == d); // b. assertTrue(e >= f); // c. assertTrue(e == f); // d. }
44
Ö d only == compares reference values so you would think all 3 fail, but.... java.sun.com/docs/books/jls/download/langspec-3.0.pdf explicitly states that wrappers for values in the range -128 to 127 will be interned by any JVM. If you use the int literal, you get a reference to that existing instance Flyweight: Do not create a new Integer(1), just return a reference to that instance from the existing pool of Integers to save memory
45
Are Doubles interned? @Test public void testEqualEquals() {
Double a = 4.2; Double b = 4.2; // Which, if any, of these assertions fail? assertTrue(a >= b); // a. assertTrue(a <= b); // b. assertTrue(a.equals(b)); // c. assertTrue(a == b); // d. assertTrue(a.compareTo(b) == 0); // e. assertTrue(a.compareTo(4.2) == 0); // f. }
46
Ö The == compares reference values, not the numeric values
assertTrue(a == b); // d. fails The == compares reference values, not the numeric values Why does a == b evaluate to false? There is no Double pool a and b refer to two different objects with the same value == compares references, not the 4.2s
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.