Java Gotchas By Rick Mercer with help from
Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter 1
n n 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 2
Oddity // Does this method return true if n is odd? public boolean is. Odd(int n) { return n % 2 == 1; } 3
Ö n 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 // 00011001 & 00000001 is 00000001 // Expression is 0 unless n is odd // if n is 24, n & 1 is 0 // 00011000 & 00000001 is 0000 4
Simple Arithmetic @Test public void simple. Arithmetic() { // Does this assertion pass? assert. Equals(444, 123 + 32 l); } 5
Ö n n n Eyes Deceive It is 123 + 32 L, which is 155 Use L instead of l for Long 6
The laughs are on me @Test public void simple. Chars() { // Which, if any, of these two assertions pass? assert. Equals("Ha", "H" + "a"); // a. assert. Equals("Ha", 'H' + 'a'); // b. } 7
Ö n Answer n Only a. java. lang. Assertion. Error: expected: <Ha> but was: <169> 8
Operator Precedence @Test public void string. Intern() { String pig = "length: 10"; String dog = "length: " + pig. length(); // Which, if any, of these two assertions pass? assert. Equals("Animals equal: false", "Animals equal: " + pig == dog); assert. Equals("Animals equal: true", "Animals equal: " + pig == dog); } 9
Ö n Neither. Precedence rules have + evaluating before ==. The actual value (2 nd arg to assert) is "Animals equal: " + pig == dog which evaluates to "Animals equal: pig" == dog which as an argument evaluates to false • assert. Equals uses the equals method when the type do not match, equals returns false "string". equals(true) is false • These asssertions pass • • assert. Equals("Animals equal: false", "Animals equal: " + (pig == dog)); assert. Equals("Animals equal: true", "Animals equal: " + (pig. equals(dog))); 10
From a 227 Student // Part of escape obstacle course in find. Exit if(escape = false) find. Exit(r-1, c); if(escape = false) find. Exit(r, c+1); n // row above // col to the right Can this recursive solution ever work? 11
Ö n No n n The boolean expressions are ALWAYS false An assignment statement evaluates to the value of the right value (expression to the right of =) n What is the value of boolean. Var = true 12
From a 127 B Student @Test public void test. Recursion() { assert. Equals(6, sum. Ints(3)); } int sum. Ints(int n) { if(n <= 1) return n; else return n * sum. Ints(n--); } n Can this recursive solution ever work? 13
Ö n No n n is not decremented until after the function call f(n--) results in a Stack. Overflow. Error Use f(n-1) 14
Output from this program? u 0070u 0075u 0062u 006 cu 0069u 0063u 0020u 0020 u 0063u 006 cu 0061u 0073u 0020u 0055u 0067u 006 cu 0079 u 007 bu 0070u 0075u 0062u 006 cu 0069u 0063u 0020u 0020u 0073u 0074u 0061u 0074u 0069u 0063 u 0076u 006 fu 0069u 0064u 0020u 006 du 0061u 0069u 006 eu 0028 u 0053u 0074u 0072u 0069u 006 eu 0067u 005 bu 005 du 0020u 0020u 0061u 0072u 0067u 0073u 0029u 007 b u 0053u 0079u 0073u 0074u 0065u 006 du 002 eu 006 fu 0075u 0074 u 002 eu 0070u 0072u 0069u 006 eu 0074u 006 cu 006 eu 0028u 0020 u 0022u 0048u 0065u 006 cu 006 fu 0020u 0077u 0022u 002 b u 0022u 006 fu 0072u 006 cu 0064u 0022u 0029u 003 bu 007 d 15
Ö n Answer: Hello World n u 0070 in hexadecimal is 112 in decimal or the character 'p' n n n Unicode not very readable Suggestion" avoid Unicode till you need it System. out. println(123. 45 + " u 20 ac" ); n 123. 45 € 16
assert. Equals('@', 'u 0040'); assert. Equals('A', 'u 0041'); assert. Equals('B', 'u 0042'); assert. Equals('`', 'u 0060'); assert. Equals('a', 'u 0061'); assert. Equals('b', 'u 0062'); assert. Equals('€', 'u 20 ac'); 17
Is “true” true? @Test public void true. Or() { // Does this assertion pass? assert. Equals("Compare 5 to 4", "true", 5 > 4); } 18
Ö n Answer n n n No "true" is not true However, JUnit show this: java. lang. Assertion. Error: Compare 5 to 4 expected: <true> but was: <true> 19
Output? @Test public void whoops. Forgot. To. Break() { int choice = 2; switch (choice) { case 1: System. out. println("one"); case 2: System. out. println("two"); case 3: System. out. println("three"); } } 20
Ö two three n Add breaks int choice = 2; switch (choice) { case 1: System. out. println("one"); break; case 2: System. out. println("two"); break; case 3: System. out. println("three"); break; } 21
BTW: n 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"); break; case "3": System. out. println("three"); break; } 22
Java plus @Test public void that. Darned. Post. Increment() { int j = 0; for (int i = 0; i < 10; i++) j = j++; // Does this assertion pass? assert. Equals(10, j); } 23
Ö n Answer: No j = j++; is postfix increment operator n 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 n n the assignment completes before the increment Use ++j; instead 24
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]); //? _____ 25
O 0 1 1 With array 0 5 1 4 1 3 26
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); } } 27
Ö n Answer: Yes Hello world 0 null n This is an initializer, a method with no heading; n { } 28
Add to 0 three times @Test public void test. Big. Int() { Big. Integer five = new Big. Integer("5"); Big. Integer fifty = new Big. Integer("50"); Big. Integer five. Hundred = new Big. Integer("500"); Big. Integer total = Big. Integer. ZERO; total. add(five); total. add(fifty); total. add(five. Hundred); // Does this assertion pass? assert. Equals(555, total); } 29
Ö n n n No Big. Integer, like String is immutable This will pass Big. Integer total = Big. Integer. ZERO; total = total. add(five); total = total. add(fifty); total = total. add(five. Hundred); // Does this assertion pass assert. Equals(555, total); 30
No Warning @Test public void test. Hash. Map() { Hash. Map<String, Big. Integer> hm = new Hash. Map<String, Big. Integer>(); hm. put("a", new Big. Integer("123456")); hm. put("b", new Big. Integer("1234567")); hm. put("c", new Big. Integer("1234567")); hm. put("a", new Big. Integer("654321")); Big. Integer a. Big. Int = hm. get("a"); // Does this assertion pass? assert. Equals(123456, a. Big. Int. int. Value()); } 31
Ö n 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 Big. Integer("123456")); Big. Integer bi = hm. put("a", new Big. Integer("9999")); // put returned the old value mapped to the key "a" assert. Equals(123456, bi. int. Value()); 32
Output? int n = 0; try { n = n / 0; } catch (Exception e) { System. out. println("A"); } finally { System. out. println("B"); } System. out. println("C"); 33
Ö A B C n Finally blocks always execute unless System. exit(0) is encountered first 34
Output? int n = 0; try { n = n / 999; } catch (Exception e) { System. out. println("A"); } finally { System. out. println("B"); } System. out. println("C"); 35
Ö B C 36
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"); 37
Ö B C 38
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"); 39
Ö A 40
String data = new String("123"); String more. Data = new String("123"); System. out. println(data==more. Data); To intern or not to intern Which assertion(s) pass? a) b) c) d) 1 and 2 1 only 2 only Neither @Test public void string. Intern() { String s 1 = "Uof. A"; String s 2 = new String("Uof. A"); assert. True(s 1. equals(s 2)); // 1 assert. True(s 1 == s 2); // 2 } 41
Ö 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 s 1 = "Uof. A"; String s 2 = "Uof. A"; assert. True(s 1. equals(s 2)); // 1 assert. True(s 1 == s 2); // 2 42
To intern or not to intern @Test public void Integer a Integer b Integer c Integer d Integer e Integer f test. Integer. Interns() { = -128; = 127; = 345; // Which, if assert. True(a assert. True(c assert. True(e } any, of these assertions fail? == b); // a. == d); // b. >= f); // c. == f); // d. 43
Ö n d only n n == 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 n Flyweight: Do not create a new Integer(1), just return a reference to that instance from the existing pool of Integers -128. . 127 n to save memory 44
Are Doubles interned? @Test public void test. Equals() { Double a = 4. 2; Double b = 4. 2; // Which, if any, of these assertions fail? assert. True(a >= b); // a. assert. True(a <= b); // b. assert. True(a. equals(b)); // c. assert. True(a == b); // d. assert. True(a. compare. To(b) == 0); // e. assert. True(a. compare. To(4. 2) == 0); // f. } 45
Ö assert. True(a == b); // d. fails n n The == compares reference values, not the numeric values Why does a == b evaluate to false? n There is no Double pool a and b refer to two different objects with the same value n == compares references, not the 4. 2 s n 46
- Slides: 46