1 / 46

Java Gotcha's

Java Gotcha's. By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter. Every programming language has its quirks. Are you a code sleuth?

aquila
Download Presentation

Java Gotcha's

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  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? • publicboolean 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 • // 00011001 & 00000001 is 00000001 • // Expression is 0 unless n is odd • // if n is 24, n & 1 is 0 • // 00011000 & 00000001 is 00000000

  5. Simple Arithmetic • @Test • publicvoid simpleArithmetic() { • // Does this assertion pass? • assertEquals(444, 123 + 32l); • }

  6. Ö • Eyes Deceive • It is 123 + 32L, which is 155 • Use L instead of l for Long

  7. The laughs are on me • @Test • publicvoid 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 • publicvoid 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", • "Animals equal: " + pig == dog); • }

  10. Ö • Neither. Precedence rules have + evaluating before ==. The actual value (2ndarg 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 // Part of escape obstacle course in findExit if(escape = false) findExit(r-1, c); // row above if(escape = false) 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 • @Test • publicvoidtestRecursion() { • assertEquals(6, sumInts(3)); • } • intsumInts(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 • 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: • 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(123.45 + " \u20ac" ); • 123.45 €

  17. assertEquals('@', '\u0040'); assertEquals('A', '\u0041'); assertEquals('B', '\u0042'); assertEquals('`', '\u0060'); assertEquals('a', '\u0061'); assertEquals('b', '\u0062'); assertEquals('€', '\u20ac');

  18. Is “true” true? • @Test • publicvoid trueOr() { • // Does this assertion pass? • assertEquals("Compare 5 to 4", "true", 5 > 4); • }

  19. Ö • Answer • No • "true" is not true • However, JUnit show this: • java.lang.AssertionError: • Compare 5 to 4 expected:<true> but was:<true>

  20. Output? • @Test • publicvoid 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. Ö • two • three • 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; • }

  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"); • break; • case"3": • System.out.println("three"); • break; • }

  23. Java plus plus • @Test • publicvoid thatDarnedPostIncrement() { • int j = 0; • for (int i = 0; i < 10; i++) • j = j++; • // Does this assertion pass? • assertEquals(10, j); • }

  24. Ö • Answer: No • 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 • 1 • With array • 0 5 • 1 4 • 1 3

  27. Is there any Output? • publicclass Huh { • publicstaticvoid main(String[] args) { • new B(); • } • } • class B { • intj; • String s; • { • System.out.println("Hello world " + j + " " + s); • } • }

  28. Ö • Answer: Yes • Hello world 0 null • This is an initializer, a method with no heading; • { }

  29. Add to 0 three times • @Test • publicvoid 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 • publicvoid testHashMap() { • HashMap<String, BigInteger> hm = • new HashMap<String, BigInteger>(); • hm.put("a", new BigInteger("123456")); • hm.put("b", new BigInteger("1234567")); • hm.put("c", new BigInteger("1234567")); • 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. 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 publicvoidstringIntern() { 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 • publicvoid 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 -128..127 • to save memory

  45. Are Doubles interned? • @Test • publicvoid 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. Ö • 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

More Related