54
Still More Java Puzzlers 1 Still More Java TM Puzzlers Joshua Bloch Neal Gafter

Java Puzzles

Embed Size (px)

Citation preview

Page 1: Java Puzzles

Still More Java Puzzlers1

Still MoreJavaTM Puzzlers

Joshua BlochNeal Gafter

Page 2: Java Puzzles

Still More Java Puzzlers2

Introduction

• Eight more JavaTM programming language puzzles─ 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, enterprise, or Tiger features

Page 3: Java Puzzles

Still More Java Puzzlers3

1. “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); }}

Page 4: Java Puzzles

Still More Java Puzzlers4

What Does It Print?

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

Page 5: Java Puzzles

Still More Java Puzzlers5

What Does It Print?

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

Computation does overflow

Page 6: Java Puzzles

Still More Java Puzzlers6

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

Page 7: Java Puzzles

Still More Java Puzzlers7

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

Page 8: Java Puzzles

Still More Java Puzzlers8

The Moral

• When working with large numbers watch out for overflow—it’s a silent killer

• Just because variable is big enough to hold resultdoesn’t mean computation is of correct type

• When in doubt, use long

Page 9: Java Puzzles

Still More Java Puzzlers9

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 madbot (also known as Mike McCloskey)

Page 10: Java Puzzles

Still More Java Puzzlers10

What Does It Print?

(a) Pain, Gain, or Main (varies at random)(b) Pain or Main (varies at random)(c) Main (always)(d) None of the above

Page 11: Java Puzzles

Still More Java Puzzlers11

What Does It Print?

(a) Pain, Gain, or Main (varies at random)(b) Pain or Main (varies at random)(c) Main (always)(d) None of the above: ain (always)

The program has three separate bugs.One of them is quite subtle.

Page 12: Java Puzzles

Still More Java Puzzlers12

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

Page 13: Java Puzzles

Still More Java Puzzlers13

How Do You Fix It?

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

Page 14: Java Puzzles

Still More Java Puzzlers14

The Moral

• Use common idioms─ If you must stray, consult the documentation

• Chars are not strings; they’re more like ints• Always remember breaks in switch statement• Watch out for fence-post errors• Watch out for sneaky puzzlers

Page 15: Java Puzzles

Still More Java Puzzlers15

3. “The Name Game”

public class NameGame { public static void main(String args[]) { Map m = new IdentityHashMap(); m.put("Mickey", "Mouse"); m.put("Mickey", "Mantle"); System.out.println(m.size()); }}

Page 16: Java Puzzles

Still More Java Puzzlers16

What Does It Print?

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

Page 17: Java Puzzles

Still More Java Puzzlers17

What Does It Print?

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

We’re using an IdentityHashMap, but stringliterals are interned (they cancel each other out)

Page 18: Java Puzzles

Still More Java Puzzlers18

Another Look

public class NameGame { public static void main(String args[]) { Map m = new IdentityHashMap(); m.put("Mickey", "Mouse"); m.put("Mickey", "Mantle"); System.out.println(m.size()); }}

Page 19: Java Puzzles

Still More Java Puzzlers19

How Do You Fix It?

public class NameGame { public static void main(String args[]) { Map m = new HashMap(); m.put("Mickey", "Mouse"); m.put("Mickey", "Mantle"); System.out.println(m.size()); }}

Page 20: Java Puzzles

Still More Java Puzzlers20

The Moral

• IdentityHashMap not a general-purpose Map─ Don’t use it unless you know it’s what you want─ Uses identity in place of equality─ Useful for topology-preserving transformations

• (String literals are interned)

Page 21: Java Puzzles

Still More Java Puzzlers21

4. “More of The Same”

public class Names { private Map m = new HashMap(); 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()); }}

Page 22: Java Puzzles

Still More Java Puzzlers22

What Does It Print?

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

Page 23: Java Puzzles

Still More Java Puzzlers23

What Does It Print?

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

No programmer-defined constructor

Page 24: Java Puzzles

Still More Java Puzzlers24

Another Look

public class Names { private Map m = new HashMap(); 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()); }}

Page 25: Java Puzzles

Still More Java Puzzlers25

How Do You Fix It?

public class Names { private 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()); }}

Page 26: Java Puzzles

Still More Java Puzzlers26

The Moral

• It is possible for a method to have the samename as a constructor

• Don’t ever do it

• Obey naming conventions─ field, method(), Class, CONSTANT

Page 27: Java Puzzles

Still More Java Puzzlers27

5. “Shades of Gray”

public class Gray { public static void main(String[] args){ System.out.println(X.Y.Z); }}

class X { static class Y { static String Z = "Black"; } static C Y = new C();}

class C { String Z = "White";}

Thanks to Prof. Dominik Gruntz, Fachhochschule Aargau

Page 28: Java Puzzles

Still More Java Puzzlers28

What Does It Print?

(a) Black(b) White(c) Won’t compile(d) None of the above

Page 29: Java Puzzles

Still More Java Puzzlers29

What Does It Print?

(a) Black(b) White(c) Won’t compile(d) None of the above

Field Y obscures member class Y (JLS 6.3.2)The rule: variable > type > package

Page 30: Java Puzzles

Still More Java Puzzlers30

Another Look

public class Gray { public static void main(String[] args){ System.out.println(X.Y.Z); }}

class X { static class Y { static String Z = "Black"; } static C Y = new C();}

class C { String Z = "White";}

The rule: variable > type > package

Page 31: Java Puzzles

Still More Java Puzzlers31

How Do You Fix It?

public class Gray { public static void main(String[] args){ System.out.println(Ex.Why.z); }}

class Ex { static class Why { static String z = "Black"; } static See y = new See();}

class See { String z = "White";}

Page 32: Java Puzzles

Still More Java Puzzlers32

The Moral

• Obey naming conventions─ field, method(), Class, CONSTANT─ Single-letter uppercase names reserved

for type variables (new in J2SE 1.5)

• Avoid name reuse, except overriding─ Overloading, shadowing, hiding, obscuring

Page 33: Java Puzzles

Still More Java Puzzlers33

6. “It’s Elementary”

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

Page 34: Java Puzzles

Still More Java Puzzlers34

What Does It Print?

(a) -22430(b) 59753(c) 10864(d) 108642

Page 35: Java Puzzles

Still More Java Puzzlers35

What Does It Print?

(a) -22430(b) 59753(c) 10864(d) 108642

Program doesn’t say what you think it does!

Page 36: Java Puzzles

Still More Java Puzzlers36

Another Look

public class Elementary { public static void main(String[] args) {

System.out.println(54321 + 5432l);

}}

1 - the numeral one

l - the lowercase letter el

Page 37: Java Puzzles

Still More Java Puzzlers37

How Do You Fix It?

We won’t insult your intelligence

Page 38: Java Puzzles

Still More Java Puzzlers38

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

Page 39: Java Puzzles

Still More Java Puzzlers39

7. “Down For The Count”

public class Count { public static void main(String[] args) { final int START = 2000000000; int count = 0; for (float f = START; f < START + 50; f++) count++; System.out.println(count); }}

Page 40: Java Puzzles

Still More Java Puzzlers40

What Does It Print?

(a) 0(b) 50(c) 51(d) None of the above

Page 41: Java Puzzles

Still More Java Puzzlers41

What Does It Print?

(a) 0(b) 50(c) 51(d) None of the above

The termination test misbehaves due to floatingpoint “granularity”

Page 42: Java Puzzles

Still More Java Puzzlers42

Another Look

public class Count { public static void main(String[] args) { final int START = 2000000000; int count = 0; for (float f = START; f < START + 50; f++) count++; System.out.println(count); }}

// (float) START == (float) (START + 50)

Page 43: Java Puzzles

Still More Java Puzzlers43

How Do You Fix It?

public class Count { public static void main(String[] args) { final int START = 2000000000; int count = 0; for (int f = START; f < START + 50; f++) count++; System.out.println(count); }}

Page 44: Java Puzzles

Still More Java Puzzlers44

The Moral

• Don’t use floating point for loop indices• Not every int can be expressed as a float• Not every long can be expressed as a double• If you must use floating point, use double

─ unless you’re certain that float provides enoughprecision and you have a compelling performanceneed (space or time)

Page 45: Java Puzzles

Still More Java Puzzlers45

8. “Line Printer”

public class LinePrinter { public static void main(String[] args) { // Note: \u000A is Unicode representation for newline char c = 0x000A; System.out.println(c); }}

Page 46: Java Puzzles

Still More Java Puzzlers46

What Does It Print?

(a) Two blank lines(b) 10(c) Won’t compile(d) It varies

Page 47: Java Puzzles

Still More Java Puzzlers47

What Does It Print?

(a) Two blank lines(b) 10(c) Won’t compile: Syntax error!(d) It varies

Unicode escape breaks comment in two

Page 48: Java Puzzles

Still More Java Puzzlers48

Another Look

// Unicode escapes are processed before comments!public class LinePrinter { public static void main(String[] args) { // Note: \u000A is unicode representation for newline char c = 0x000A; System.out.println(c); }}

// This is what the parser seespublic class LinePrinter { public static void main(String[] args) { // Note:is Unicode representation for newline char c = 0x000A; System.out.println(c); }}

Page 49: Java Puzzles

Still More Java Puzzlers49

How Do You Fix It?

public class LinePrinter { public static void main(String[] args) { // Escape sequences (like \n) are fine in comments char c = '\n'; System.out.println(c); }}

Page 50: Java Puzzles

Still More Java Puzzlers50

The Moral

• Unicode escapes are dangerous─ Equivalent to the character they represent!

• Use escape sequences instead, if possible

• If you must use Unicode escapes, use with care─ \u000A (newline) can break string literals,

char literals, and single-line comments─ \u0022 (") can terminate string literals─ \u0027 (') can terminate character literals

Page 51: Java Puzzles

Still More Java Puzzlers51

Conclusion

• Java platform is simple and elegant─ But it has a few sharp corners—avoid them!

• Keep programs clear and simple

• If you aren’t sure what a program does,it probably doesn’t do what you want

• Don’t code like my brother

Page 52: Java Puzzles

Still More Java Puzzlers52

Shameless Commerce Division

Page 53: Java Puzzles

Still More Java Puzzlers53

Send Us Your Puzzlers!

• If you have a puzzler for us, send it to

[email protected]

Page 54: Java Puzzles

Still More Java Puzzlers54

Still MoreJavaTM Puzzlers

Joshua BlochNeal Gafter

Don’t code like my brother.