1 java gotcha's by rick mercer with help from the book: java™ puzzlers: traps, pitfalls, and...

46
1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

Upload: abigail-newman

Post on 20-Jan-2016

233 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

1

Java Gotcha's

By Rick Mercer with help from the book:Java™ Puzzlers: Traps, Pitfalls, and Corner Cases

Joshua Bloch and Neal Gafter

Page 2: 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

Page 3: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

3

Oddity// Does this method return true if n is odd?

public boolean isOdd(int n) {

return n % 2 == 1;

}

Page 4: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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

Page 5: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

5

Simple Arithmetic @Test

public void simpleArithmetic() {

// Does this assertion pass?

assertEquals(444, 123 + 32l);

}

Page 6: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

6

Ö

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

Page 7: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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.

}

Page 8: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

8

Ö

Answer Only a.

java.lang.AssertionError:

expected:<Ha> but was:<169>

Page 9: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

9

Operator Precedence

@Testpublic 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", "Animals equal: " + pig == dog);}

Page 10: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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)));

Page 11: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

From a 227 Student

// Part of escape obstacle course in findExitif(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?

11

Page 12: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

Ö

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

12

Page 13: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

From a 127B Student

@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?

13

Page 14: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

Ö

No n is not decremented until after the function call f(n--) results in a StackOverflowError Use f(n-1)

14

Page 15: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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

Page 16: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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 €

Page 17: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

17

assertEquals('@', '\u0040');

assertEquals('A', '\u0041');

assertEquals('B', '\u0042');

assertEquals('`', '\u0060');

assertEquals('a', '\u0061');

assertEquals('b', '\u0062');

assertEquals('€', '\u20ac');

Page 18: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

18

Is “true” true?

@Test

public void trueOr() {

// Does this assertion pass?

assertEquals("Compare 5 to 4", "true", 5 > 4);

}

Page 19: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

19

Ö

Answer No

"true" is not true However, JUnit show this:

java.lang.AssertionError:

Compare 5 to 4 expected:<true> but was:<true>

Page 20: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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"); } }

Page 21: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

21

Ö

twothree

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; }

Page 22: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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; }

22

Page 23: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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);

}

Page 24: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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

Page 25: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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]); //? _____

Page 26: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

O

0

1

1

With array

0 5

1 4

1 3

26

Page 27: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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); }}

Page 28: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

28

Ö

Answer: YesHello world 0 null

This is an initializer, a method with no heading;

{ }

Page 29: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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);

}

Page 30: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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);

Page 31: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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("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()); }

Page 32: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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());

Page 33: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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");

Page 34: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

34

Ö

A

B

C

Finally blocks always execute unless System.exit(0) is encountered first

Page 35: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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");

Page 36: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

36

Ö

B

C

Page 37: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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");

Page 38: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

38

Ö

B

C

Page 39: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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");

Page 40: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

40

Ö

A

Page 41: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

41

To intern or not to intern

Which assertion(s) pass? a)1 and 2 b)1 onlyc)2 onlyd)Neither

@Test public void stringIntern() { String s1 = "UofA"; String s2 = new String("UofA"); assertTrue(s1.equals(s2)); // 1 assertTrue(s1 == s2); // 2 }

String data = new String("123"); String moreData = new String("123"); System.out.println(data==moreData);

Page 42: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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

Page 43: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

43

To intern or not to intern@Testpublic 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.}

Page 44: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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

Page 45: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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. }

Page 46: 1 Java Gotcha's By Rick Mercer with help from the book: Java™ Puzzlers: Traps, Pitfalls, and Corner Cases Joshua Bloch and Neal Gafter

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