0% found this document useful (0 votes)
252 views

Java Puzzlers' Greatest Hits: Joshua Bloch Neal Gafter

This document summarizes a book titled "Java Puzzlers' Greatest Hits" which contains puzzles about the Java programming language. It presents 8 puzzles involving unexpected behavior in Java code. Each puzzle shows a short program, asks the reader to predict its output, reveals the actual output and explains the underlying issue. The puzzles cover topics like primitive type promotions, switch statement behavior, constructor definitions and more. The goal is to expose subtle bugs and surprises in the Java language.

Uploaded by

rohitpr1111
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
252 views

Java Puzzlers' Greatest Hits: Joshua Bloch Neal Gafter

This document summarizes a book titled "Java Puzzlers' Greatest Hits" which contains puzzles about the Java programming language. It presents 8 puzzles involving unexpected behavior in Java code. Each puzzle shows a short program, asks the reader to predict its output, reveals the actual output and explains the underlying issue. The puzzles cover topics like primitive type promotions, switch statement behavior, constructor definitions and more. The goal is to expose subtle bugs and surprises in the Java language.

Uploaded by

rohitpr1111
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 70

Java Puzzlers’ TM

Greatest Hits

Joshua Bloch
Neal Gafter

1 Java Puzzlers’ Greatest Hits


Introduction

• Eight more Java programming language puzzles


TM

Short program with curious behavior


What does it print? (multiple choice)
The mystery revealed
How to fix the problem
The moral
• Covers language and core libraries
No GUI or enterprise

2 Java Puzzlers’ Greatest Hits


1. “A Big Delight in Every Byte”

class Delight {
public static void main(String[] args) {
for (byte b = Byte.MIN_VALUE;
b < Byte.MAX_VALUE; b++) {
if (b == 0x90)
System.out.print("Joy! ");
}
}
}

3 Java Puzzlers’ Greatest Hits


What Does It Print?

class Delight {
public static void main(String[] args) {
for (byte b = Byte.MIN_VALUE;
b < Byte.MAX_VALUE; b++) {
if (b == 0x90)
System.out.print("Joy! ");
}
}
}

(a) Joy!
(b) Joy! Joy!
(c) Nothing
(d) None of the above

4 Java Puzzlers’ Greatest Hits


What Does It Print?

(a) Joy!
(b) Joy! Joy!
(c) Nothing
(d) None of the above
Program compares a byte with an int;
byte is promoted with surprising results

5 Java Puzzlers’ Greatest Hits


Another Look

class Delight {
public static void main(String[] args) {
for (byte b = Byte.MIN_VALUE;
b < Byte.MAX_VALUE; b++) {
if (b == 0x90) // (b == 144)
System.out.print("Joy! ");
}
}
}
// (byte)0x90 == -112
// (byte)0x90 != 0x90

6 Java Puzzlers’ Greatest Hits


You Could Fix it Like This…

• Cast int to byte


if (b == (byte)0x90)
System.out.println("Joy!");
• Or convert byte to int, suppressing sign
extension with mask
if ((b & 0xff) == 0x90)
System.out.println("Joy!");

7 Java Puzzlers’ Greatest Hits


…But This is Even Better

public class Delight {


private static final byte TARGET = 0x90; // Won’t compile!
public static void main(String[] args) {
for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++)
if (b == TARGET)
System.out.print("Joy!");
}
}

Delight.java:2: possible loss of precision


found : int
required: byte
private static final byte TARGET = 0x90; // Won’t compile!
^

8 Java Puzzlers’ Greatest Hits


The Best Solution, Debugged

public class Delight {


private static final byte TARGET = (byte) 0x90; // Fixed
public static void main(String[] args) {
for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++)
if (b == TARGET)
System.out.print("Joy!");
}
}

9 Java Puzzlers’ Greatest Hits


The Moral

• a byte isn’t an int


• Be careful when mixing primitive types
• Compare like-typed expressions
Cast or convert one operand as necessary
Declared constants help keep you in line

10 Java Puzzlers’ Greatest Hits


2. “No Pain, No Gain”

public class Rhymes {


private static Random rnd = new Random();
public static void main(String[] args) {
StringBuffer word = null;
switch(rnd.nextInt(2)) {
case 1: word = new StringBuffer('P');
case 2: word = new StringBuffer('G');
default: word = new StringBuffer('M');
}
word.append('a');
word.append('i');
word.append('n');
System.out.println(word);
}
} Thanks to Mike “madbot” McCloskey

11 Java Puzzlers’ Greatest Hits


What Does It Print?

public class Rhymes {


private static Random rnd = new Random();
public static void main(String[] args) {
StringBuffer word = null;
switch(rnd.nextInt(2)) {
case 1: word = new StringBuffer('P');
case 2: word = new StringBuffer('G');
default: word = new StringBuffer('M');
}
word.append('a');
word.append('i');
word.append('n');
System.out.println(word);
}
}
(a) Pain, Gain, or Main (varies randomly)
(b) Pain or Main (varies randomly)
(c) Main (always)
(d) None of the above
12 Java Puzzlers’ Greatest Hits
What Does It Print?

(a) Pain, Gain, or Main (varies randomly)


(b) Pain or Main (varies randomly)
(c) Main (always)
(d) None of the above: ain (always)

The program has three separate bugs.


One of them is quite subtle.

13 Java Puzzlers’ Greatest Hits


Another Look

public class Rhymes {


private static Random rnd = new Random();
public static void main(String[] args) {
StringBuffer word = null;
switch(rnd.nextInt(2)) { // No breaks!
case 1: word = new StringBuffer('P');
case 2: word = new StringBuffer('G');
default: word = new StringBuffer('M');
}
word.append('a');
word.append('i');
word.append('n');
System.out.println(word);
}
}

14 Java Puzzlers’ Greatest Hits


You Could Fix it Like This…

public class Rhymes {


private static Random rnd = new Random();
public static void main(String[] args) {
StringBuffer word = null;
switch(rnd.nextInt(3)) {
case 1: word = new StringBuffer("P"); break;
case 2: word = new StringBuffer("G"); break;
default: word = new StringBuffer("M"); break;
}
word.append('a');
word.append('i');
word.append('n');
System.out.println(word);
}
}

15 Java Puzzlers’ Greatest Hits


But This is Even Better

public class Rhymes {


public static void main(String args[]) {
String a[] = { "Main", "Pain", "Gain" };
System.out.println(randomElement(a));
}
private static Random rnd = new Random();
private static String randomElement(String[] a) {
return a[rnd.nextInt(a.length)];
}
}

16 Java Puzzlers’ Greatest Hits


The Moral

• Use common idioms


If you must stray, consult the documentation
• Chars are not strings; they’re more like ints
• Remember breaks in switch statement
• Watch out for fence-post errors
• Watch out for sneaky puzzlers

17 Java Puzzlers’ Greatest Hits


3. “The Name Game”

public class Names {


private final Map m = new IdentityHashMap();
public void Names() {
m.put("Mickey", "Mouse");
m.put("Mickey", "Mantle");
}
public int size() { return m.size(); }
public static void main(String args[]) {
Names names = new Names();
System.out.println(names.size());
}
}

18 Java Puzzlers’ Greatest Hits


What Does It Print?

public class Names {


private final Map m = new IdentityHashMap();
public void Names() {
m.put("Mickey", "Mouse");
m.put("Mickey", "Mantle");
}
public int size() { return m.size(); }
public static void main(String args[]) {
Names names = new Names();
System.out.println(names.size());
}
}

(a) 0
(b) 1
(c) 2
(d) It varies

19 Java Puzzlers’ Greatest Hits


What Does It Print?

(a) 0
(b) 1
(c) 2
(d) It varies

No programmer-defined constructor.
(IdentityHashMap is a red herring.)

20 Java Puzzlers’ Greatest Hits


Another Look

public class Names {


private final Map m = new IdentityHashMap();
public void Names() { // Not a constructor!
m.put("Mickey", "Mouse");
m.put("Mickey", "Mantle");
}
public int size() { return m.size(); }
public static void main(String args[]) {
Names names = new Names(); // Invokes default!
System.out.println(names.size());
}
}

21 Java Puzzlers’ Greatest Hits


How Do You Fix It?

public class Names {


private final Map m = new HashMap();
public Names() { // No return type
m.put("Mickey", "Mouse");
m.put("Mickey", "Mantle");
}
public int size() { return m.size(); }
public static void main(String args[]) {
Names names = new Names();
System.out.println(names.size());
}
}

22 Java Puzzlers’ Greatest Hits


The Moral

• Method can have same name as constructor


Don’t ever do it
• Obey naming conventions
field, method(), Class, CONSTANT
• IdentityHashMap not a general-purpose Map
Uses identity in place of equality
Don’t use it unless you know it’s what you want
Useful for topology-preserving transformations
• (String literals are interned)

23 Java Puzzlers’ Greatest Hits


4. “Larger Than Life”

public class Elvis {


public static final Elvis INSTANCE = new Elvis();
private final int beltSize;

private static final int CURRENT_YEAR =


Calendar.getInstance().get(Calendar.YEAR);

private Elvis() { beltSize = CURRENT_YEAR - 1930; }


public int beltSize() { return beltSize; }

public static void main(String[] args) {


System.out.println("Elvis wears size " +
INSTANCE.beltSize() + " belt.");
}
}

24 Java Puzzlers’ Greatest Hits


What Does It Print?

public class Elvis {


public static final Elvis INSTANCE = new Elvis();
private final int beltSize;

private static final int CURRENT_YEAR =


Calendar.getInstance().get(Calendar.YEAR);

private Elvis() { beltSize = CURRENT_YEAR - 1930; }


public int beltSize() { return beltSize; }

public static void main(String[] args) {


System.out.println("Elvis wears size " +
INSTANCE.beltSize() + " belt.");
}
}
(a) Elvis wears size 0 belt.
(b) Elvis wears size 76 belt.
(c) Elvis wears size -1930 belt.
(d) None of the above.
25 Java Puzzlers’ Greatest Hits
What Does It Print?

(a) Elvis wears size 0 belt.


(b) Elvis wears size 76 belt.
(c) Elvis wears size -1930 belt.
(d) None of the above.

The value of CURRENT_YEAR is used before it is


initialized, due to circularity in class initialization.

26 Java Puzzlers’ Greatest Hits


Another Look

// Static initialization proceeds top to bottom.


public class Elvis {
// Recursive initialization returns immediately!
public static final Elvis INSTANCE = new Elvis();
private final int beltSize;

private static final int CURRENT_YEAR =


Calendar.getInstance().get(Calendar.YEAR);

private Elvis() { beltSize = CURRENT_YEAR - 1930; }


public int beltSize() { return beltSize; }

public static void main(String[] args) {


System.out.println("Elvis wears size " +
INSTANCE.beltSize() + " belt.");
}
}

27 Java Puzzlers’ Greatest Hits


How Do You Fix It?

public class Elvis {


private final int beltSize;

private static final int CURRENT_YEAR =


Calendar.getInstance().get(Calendar.YEAR);

// Make instance after other initialization complete


public static final Elvis INSTANCE = new Elvis();

private Elvis() { beltSize = CURRENT_YEAR - 1930; }


public int beltSize() { return beltSize; }

public static void main(String[] args) {


System.out.println("Elvis wears size " +
INSTANCE.beltSize() + " belt.");
}
}

28 Java Puzzlers’ Greatest Hits


The Moral

• Watch out for circularities in static initialization


One or more classes may be involved
Circularities aren’t necessarily wrong but…
Constructors can run before class fully initialized
Static fields can be read before they’re initialized

• Several common patterns are susceptible


Singleton (Effective Java, Item 2)
Typesafe Enum (Effective Java, Item 21)
Service Provider Framework (Effective Java, Item 1)

29 Java Puzzlers’ Greatest Hits


5. “All Strung Out”

public class Puzzling {


public static void main(String[] args) {
String s = new String("blah");
System.out.println(s);
}
}
class String {
private final java.lang.String s;
public String(java.lang.String s) {
this.s = s;
}
public java.lang.String toString() {
return s;
}
}
Thanks to Mike “madbot” McCloskey

30 Java Puzzlers’ Greatest Hits


What Does It Print?

public class Puzzling {


public static void main(String[] args) {
String s = new String("blah");
System.out.println(s);
}
}
class String {
private final java.lang.String s;
public String(java.lang.String s) {
this.s = s;
}
public java.lang.String toString() {
return s;
}
}
(a) Won’t compile
(b) blah
(c) Throws an exception
(d) Other

31 Java Puzzlers’ Greatest Hits


What Does It Print?

(a) Won’t compile


(b) blah
(c) Throws an exception at runtime
(d) Other

NoSuchMethodError is thrown because the


Puzzling class is missing a main method.

32 Java Puzzlers’ Greatest Hits


Another Look

public class Puzzling {


public static void main(String[] args) {
String s = new String("blah");
System.out.println(s);
}
}
class String {
private final java.lang.String s;
public String(java.lang.String s) {
this.s = s;
}
public java.lang.String toString() {
return s;
}
}

33 Java Puzzlers’ Greatest Hits


How Do You Fix It?

public class Puzzling {


public static void main(String[] args) {
MyString s = new MyString("blah");
System.out.println(s);
}
}
class MyString {
String s;
public MyString(String s) {
this.s = s;
}
public String toString() {
return s;
}
}

34 Java Puzzlers’ Greatest Hits


The Moral

• Avoid name reuse in all its guises


hiding, shadowing, overloading, obscuring
• Don’t even think about reusing platform
class names!

35 Java Puzzlers’ Greatest Hits


6. “Lazy Initialization”

public class Lazy {


private static boolean initialized = false;
static {
Thread t = new Thread(new Runnable() {
public void run() {
initialized = true;
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
public static void main(String[] args) {
System.out.println(initialized);
}
}

36 Java Puzzlers’ Greatest Hits


What Does It Print?

public class Lazy {


private static boolean initialized = false;
static {
Thread t = new Thread(new Runnable() {
public void run() {
initialized = true;
} (a) true
}); (b) false
t.start();
try { (c) It varies
t.join(); (d) None of the above
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
public static void main(String[] args) {
System.out.println(initialized);
}
}

37 Java Puzzlers’ Greatest Hits


What Does It Print?

(a) true
(b) false
(c) It varies
(d) None of the above: it deadlocks

Intuition: You wouldn’t believe us if we told you.

38 Java Puzzlers’ Greatest Hits


Another Look
public class Lazy {
private static boolean initialized = false;
static {
Thread t = new Thread(new Runnable() {
public void run() {
initialized = true; // Deadlocks here!
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
public static void main(String[] args) {
System.out.println(initialized);
}
}

39 Java Puzzlers’ Greatest Hits


How Do You Fix It?

• Do the initialization in the main thread


If it hurts when you do that, don’t do that!

40 Java Puzzlers’ Greatest Hits


The Moral

• Avoid background threads in class initialization


• Keep class initialization simple

41 Java Puzzlers’ Greatest Hits


7. “Long Division”

public class LongDivision {


private static final long MILLIS_PER_DAY
= 24 * 60 * 60 * 1000;
private static final long MICROS_PER_DAY
= 24 * 60 * 60 * 1000 * 1000;

public static void main(String[] args) {


System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
}

42 Java Puzzlers’ Greatest Hits


What Does It Print?

public class LongDivision {


private static final long MILLIS_PER_DAY
= 24 * 60 * 60 * 1000;
private static final long MICROS_PER_DAY
= 24 * 60 * 60 * 1000 * 1000;

public static void main(String[] args) {


System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
}

(a) 5
(b) 1000
(c) 5000
(d) Throws an exception
43 Java Puzzlers’ Greatest Hits
What Does It Print?

(a) 5
(b) 1000
(c) 5000
(d) Throws an exception

Computation does overflow

44 Java Puzzlers’ Greatest Hits


Another Look

public class LongDivision {


private static final long MILLIS_PER_DAY
= 24 * 60 * 60 * 1000;
private static final long MICROS_PER_DAY
= 24 * 60 * 60 * 1000 * 1000; // >> Integer.MAX_VALUE

public static void main(String[] args) {


System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
}

45 Java Puzzlers’ Greatest Hits


How Do You Fix It?

public class LongDivision {


private static final long MILLIS_PER_DAY
= 24L * 60 * 60 * 1000;
private static final long MICROS_PER_DAY
= 24L * 60 * 60 * 1000 * 1000;

public static void main(String[] args) {


System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
}

46 Java Puzzlers’ Greatest Hits


The Moral

• When working with large numbers, watch out


for overflow—it’s a silent killer
• Just because variable can hold result doesn’t
mean computation won’t overflow
• When in doubt, use larger type

47 Java Puzzlers’ Greatest Hits


8. “It’s Elementary”

public class Elementary {


public static void main(String[] args) {
System.out.println(12345 + 5432l);
}
}

48 Java Puzzlers’ Greatest Hits


What Does It Print?

public class Elementary {


public static void main(String[] args) {
System.out.println(12345 + 5432l);
}
}

(a) -22430
(b) 17777
(c) 66666
(d) None of the above

49 Java Puzzlers’ Greatest Hits


What Does It Print?

(a) -22430
(b) 17777
(c) 66666
(d) None of the above

Program doesn’t say what you think it does!

50 Java Puzzlers’ Greatest Hits


Another Look

public class Elementary {


public static void main(String[] args) {

12345
System.out.println( l);
+ 5432
}
}

1 - the numeral one


l - the lowercase letter el

51 Java Puzzlers’ Greatest Hits


How Do You Fix It?

public class Elementary {


public static void main(String[] args) {
System.out.println(12345 + 5432L);
}
}

52 Java Puzzlers’ Greatest Hits


The Moral

• Always use uppercase el (L) for long literals


Lowercase el makes the code unreadable
5432L is clearly a long, 5432l is misleading

• Never use lowercase el as a variable name


Not this: List l = new ArrayList();
But this: List list = new ArrayList();

• Don’t code like my brother

53 Java Puzzlers’ Greatest Hits


Some people say
seeing is believing…

54 Java Puzzlers’ Greatest Hits


Fraser 1908

55 Java Puzzlers’ Greatest Hits


Fraser 1908

56 Java Puzzlers’ Greatest Hits


Fraser 1908

57 Java Puzzlers’ Greatest Hits


Logvinenko 1999

58 Java Puzzlers’ Greatest Hits


Logvinenko 1999

59 Java Puzzlers’ Greatest Hits


Logvinenko 1999

60 Java Puzzlers’ Greatest Hits


Kitaoka 1998

61 Java Puzzlers’ Greatest Hits


Kitaoka 1998

62 Java Puzzlers’ Greatest Hits


Kitaoka 1998

63 Java Puzzlers’ Greatest Hits


Todorovic 1997

64 Java Puzzlers’ Greatest Hits


Todorovic 1997

65 Java Puzzlers’ Greatest Hits


Todorovic 1997

66 Java Puzzlers’ Greatest Hits


What’s going on here?

• Our brains construct what we see


• System evolved over millions of years
• This sort of art has only existed for hundreds
• Illusions methodically exploit artifacts in system
• Studying illusions yields deep insight into perception

67 Java Puzzlers’ Greatest Hits


Shameless Commerce Division

• 95 Puzzles
• 52 Illusions
• Tons of fun

68 Java Puzzlers’ Greatest Hits


Send Us Your Puzzlers!

[email protected]

69 Java Puzzlers’ Greatest Hits


Java Puzzlers’ TM

Greatest Hits

Joshua Bloch
Neal Gafter

70 Java Puzzlers’ Greatest Hits

You might also like