java puzzle

275
Java Puzzles Filipp Shubin

Upload: sfilipp

Post on 10-May-2015

17.704 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Java Puzzle

Java Puzzles

Filipp Shubin

Page 2: Java Puzzle

Overall Presentation Goal

Learn some of the quirks of programming in general and the Java language in particular;

Have fun!

Page 3: Java Puzzle

Learning Objectives

• As a result of this presentation, you will be able to:– Avoid some common programming

pitfalls– Have some fun while you are learning

Page 4: Java Puzzle

1. “All I Get is Static”01 class Dog {02 public static void bark() {03 System.out.print("woof ");04 }05 }06 class Basenji extends Dog {07 public static void bark() { }08 }09 public class Bark {10 public static void main(String args[]) {11 Dog woofer = new Dog();12 Dog nipper = new Basenji();13 woofer.bark();14 nipper.bark();15 }16 }

Page 5: Java Puzzle

What Does It Print?

(a) woof(b) woof woof(c) It varies

Page 6: Java Puzzle

What Does It Print?

(a) woof(b) woof woof(c) It varies

No dynamic dispatch on static methods

Page 7: Java Puzzle

Another Look01 class Dog {02 public static void bark() {03 System.out.print("woof ");04 }05 }06 class Basenji extends Dog {07 public static void bark() { }08 }09 public class Bark {10 public static void main(String args[]) {11 Dog woofer = new Dog();12 Dog nipper = new Basenji();13 woofer.bark();14 nipper.bark();15 }16 }

Page 8: Java Puzzle

How Do You Fix It?

• Remove static from the bark method

Page 9: Java Puzzle

The Moral

• Static methods can't be overridden– They can only be hidden

• Don’t hide static methods

• Never invoke static methods on instances– Not Instance.staticMethod()– But Class.staticMethod()

Page 10: Java Puzzle

2. “What's in a Name?”01 public class Name {02 private String first, last;03 public Name(String first, String last) {04 this.first = first;05 this.last = last;06 }07 public boolean equals(Object o) {08 if (!(o instanceof Name)) return false;09 Name n = (Name)o;10 return n.first.equals(first) &&11 n.last.equals(last);12 }13 public static void main(String[] args) {14 Set s = new HashSet();15 s.add(new Name("Donald", "Duck"));16 System.out.println(17 s.contains(new Name("Donald", "Duck")));18 }19 }

Page 11: Java Puzzle

What Does It Print?

(a) True(b) False(c) It varies

Page 12: Java Puzzle

What Does It Print?

(a) True(b) False(c) It varies

Donald is in the set, but the set can’t find him.

The Name class violates the hashCode contract.

Page 13: Java Puzzle

Another Look01 public class Name {02 private String first, last;03 public Name(String first, String last) {04 this.first = first;05 this.last = last;06 }07 public boolean equals(Object o) {08 if (!(o instanceof Name)) return false;09 Name n = (Name)o;10 return n.first.equals(first) &&11 n.last.equals(last);12 }13 public static void main(String[] args) {14 Set s = new HashSet();15 s.add(new Name("Donald", "Duck"));16 System.out.println(17 s.contains(new Name("Donald", "Duck")));18 }19 }

Page 14: Java Puzzle

How Do You Fix It?

Add a hashCode method:public int hashCode() { return 31 * first.hashCode() + last.hashCode();

}

Page 15: Java Puzzle

The Moral

• If you override equals, override hashCode

• Obey general contracts when overriding

• See Effective Java, Chapter 3

Page 16: Java Puzzle

3. “Indecision”01 class Indecisive {02 public static void main(String[] args) {03 System.out.println(waffle());04 }05 06 static boolean waffle() {07 try {08 return true;09 } finally {10 return false;11 }12 }13 }

Page 17: Java Puzzle

What Does It Print?

(a) true(b) false(c) None of the above

Page 18: Java Puzzle

What Does It Print?

(a) true(b) false(c) None of the above

The finally is processed after the try.

Page 19: Java Puzzle

Another Look01 class Indecisive {02 public static void main(String[] args) {03 System.out.println(waffle());04 }05 06 static boolean waffle() {07 try {08 return true;09 } finally {10 return false;11 }12 }13 }

Page 20: Java Puzzle

The Moral

• Avoid abrupt completion of finally blocks– Wrap unpredictable actions with nested

trys– Don't return or throw exceptions

Page 21: Java Puzzle

4. “The Saga of the Sordid Sort”01 public class SordidSort {02 public static void main(String args[]) {03 Integer big = new Integer( 2000000000);04 Integer small = new Integer(-2000000000);05 Integer zero = new Integer(0);06 Integer[] a = new Integer[] {big, small, zero};07 Arrays.sort(a, new Comparator() {08 public int compare(Object o1, Object o2) {09 return ((Integer)o2).intValue() -10 ((Integer)o1).intValue();11 }12 });13 System.out.println(Arrays.asList(a));14 }15 }

Page 22: Java Puzzle

What Does It Print?

(a) [-2000000000, 0, 2000000000](b) [2000000000, 0, -2000000000](c) [-2000000000, 2000000000, 0](d) It varies

Page 23: Java Puzzle

What Does It Print?

(a) [-2000000000, 0, 2000000000](b) [2000000000, 0, -2000000000](c) [-2000000000, 2000000000, 0](d) It varies (behavior is undefined)

The comparator is broken!

• It relies on int subtraction

• Int too small to hold difference of 2 arbitrary ints

Page 24: Java Puzzle

Another Look01 public class SordidSort {02 public static void main(String args[]) {03 Integer big = new Integer( 2000000000);04 Integer small = new Integer(-2000000000);05 Integer zero = new Integer(0);06 Integer[] a = new Integer[] {big,small,zero};07 Arrays.sort(a, new Comparator() {08 public int compare(Object o1, Object o2) {09 return ((Integer)o2).intValue() -10 ((Integer)o1).intValue();11 }12 });13 System.out.println(Arrays.asList(a));14 }15 }

Page 25: Java Puzzle

How Do You Fix It?

• Replace comparator with one that works

01 public int compare(Object o1, Object o2) {

02 int i1 = ((Integer)o1).intValue();

03 int i2 = ((Integer)o2).intValue();

04 return

05 (i2 < i1 ? -1 : (i2 == i1 ? 0 : 1));

06 }

Page 26: Java Puzzle

The Moral

• ints aren't integers!

• Think about overflow• This particular comparison technique

– OK only if max - min <= Integer.MAX_VALUE– For example: all values positive

• Don’t write overly clever code

Page 27: Java Puzzle

5. “You're Such a Character”01 public class Trivial {

02 public static void main(String args[]) {

03 System.out.print("H" + "a");

04 System.out.print('H' + 'a');

05 }

06 }

Page 28: Java Puzzle

What Does It Print?

(a) HaHa(b) Ha

(c) None of the above

Page 29: Java Puzzle

What Does It Print?

(a) HaHa(b) Ha(c) None of the above: It prints Ha169

'H' + 'a' evaluated as int, then converted to String. Ouch.

Page 30: Java Puzzle

The Moral

• Use string concatenation (+) with care– At least one operand must be a String– If it isn't, cast or convert" + 'H' + 'a');

• Be glad operator overloading isn't supported

Page 31: Java Puzzle

6. “The Case of the Constructor”01 public class Confusing {02 public Confusing(Object o) {03 System.out.println("Object");04 }05 public Confusing(double[] dArray) {06 System.out.println("double array");07 }08 public static void main(String args[]) {09 new Confusing(null);10 }11 }

Page 32: Java Puzzle

What Does It Print?

(a) Object(b) double array

(c) None of the above

Page 33: Java Puzzle

What Does It Print?

(a) Object(b) double array

(c) None of the above

When multiple overloadings apply, the most specific wins

Page 34: Java Puzzle

Another Look01 public class Confusing {

02 public Confusing(Object o) {

03 System.out.println("Object");

04 }

05 public Confusing(double[] dArray) {

06 System.out.println("double array");

07 }

08 public static void main(String args[]) {

09 new Confusing(null);

10 }

11 }

Page 35: Java Puzzle

How Do You Fix It?

• There may be no problem• If there is, use a cast:

New Confusing((Object)null);

Page 36: Java Puzzle

The Moral

• Avoid overloading• If you overload, avoid ambiguity

• If you do have ambiguous overloadings, make their behavior identical

• If you are using a "broken" class, make intentions clear with a cast

Page 37: Java Puzzle

7. “A Big Delight in Every Byte”01 public class ByteMe {02 public static void main(String[] args) {03 for (byte b = Byte.MIN_VALUE;

04 b < Byte.MAX_VALUE; b++) {05 if (b == 0x90)06 System.out.print("Byte me! ");07 }08 }09 }

Page 38: Java Puzzle

What Does It Print?

(a) (nothing)(b) Byte me!(c) Byte me! Byte me!

Page 39: Java Puzzle

What Does It Print?

(a) (nothing)(b) Byte me!(c) Byte me! Byte me!

Program compares a byte with an int– byte is promoted with surprising results

Page 40: Java Puzzle

Another Look01 public class ByteMe {02 public static void main(String[] args) {03 for (byte b = Byte.MIN_VALUE;

04 b < Byte.MAX_VALUE; b++) {05 if (b == 0x90) // (b == 144)06 System.out.print("Byte me! ");07 }08 }09 }10 11 // But (byte)0x90 == -112

Page 41: Java Puzzle

How Do You Fix It?

• Cast int to byteif (b == (byte)0x90)

System.out.println("Byte me!");

• Or convert byte to int, suppressing sign extension with maskif ((b & 0xff) == 0x90)

System.out.println("Byte me!");

Page 42: Java Puzzle

The Moral

• Bytes aren't ints

• Be careful when mixing primitive types

• Compare like-typed expressions– Cast or convert one operand as

necessary

Page 43: Java Puzzle

8. “Time for a Change”

• If you pay $2.00 for a gasket that costs $1.10, how much change do you get?

01 public class Change {02 public static void main(String args[])03 {

04 System.out.println(2.00 - 1.10);05 }06 }

Page 44: Java Puzzle

What Does It Print?

(a) 0.9(b) 0.90(c) It varies(d) None of the above

Page 45: Java Puzzle

What Does It Print?

(a) 0.9(b) 0.90(c) It varies(d) None of the above:

0.89999999999999

Decimal Values can't be represented exactly by float or double

Page 46: Java Puzzle

How Do You Fix It?01 import java.math.BigDecimal;

02 public class Change2 {

03 public static void main(String args[]) {

04 System.out.println(

05 new BigDecimal("2.00").subtract(

06 new BigDecimal("1.10")));

07 }

08 }0910 public class Change {11 public static void main(String args[]) {12 System.out.println(200 - 110);13 }14 }

Page 47: Java Puzzle

The Moral

• Avoid float and double where exact answers are required

• Use BigDecimal, int, or long instead

Page 48: Java Puzzle

9. “A Private Matter”01 class Base {

02 public String name = "Base";

03 }

04

05 class Derived extends Base {

06 private String name = "Derived";

07 }

08

09 public class PrivateMatter {

10 public static void main(String[] args) {

11 System.out.println(new Derived().name);

12 }

13 }

Page 49: Java Puzzle

What Does It Print?

(a) Derived

(b) Base(c) Compiler error in class Derived:

Can't assign weaker access to name

(d) None of the above

Page 50: Java Puzzle

What Does it Print?

(a) Derived

(b) Base(c) Compiler error in class Derived:

Can't assign weaker access to name(d) None of the above: Compiler error in

class

PrivateMatter: Can't access name

Private method can't overrides public, but private field can hide public

Page 51: Java Puzzle

Another Look01 class Base {02 public String name = "Base";03 }04 05 class Derived extends Base {06 private String name = "Derived";07 }0809 public class PrivateMatter {10 public static void main(String[] args) {11 System.out.println(new Derived().name);12 }13 }

Page 52: Java Puzzle

How Do You Fix It?01 class Base {02 public String getName() { return "Base"; }03 }04 05 class Derived extends Base {06 public String getName() { return "Derived"; }07 }08 09 public class PrivateMatter {10 public static void main(String[] args) {11 System.out.println(new Derived().getName());12 }13 }

Page 53: Java Puzzle

The Moral

• Avoid hiding– Violates subsumption

• Avoid public fields– Use accessor methods instead

Page 54: Java Puzzle

10. “Loopy Behavior”01 public class Loopy {02 public static void main(String[] args) {03 final int start = Integer.MAX_VALUE -

04 100;05 final int end = Integer.MAX_VALUE;06 int count = 0;07 for (int i = start; i <= end; i++)08 count++;09 System.out.println(count);10 }11 }

Page 55: Java Puzzle

What Does It Print?

(a) 100(b) 101

(c) (nothing)

Page 56: Java Puzzle

What Does It Print?

(a) 100(b) 101

(c) (nothing)

The loop test is broken - infinite loop!

Page 57: Java Puzzle

Another Look01 public class Loopy {02 public static void main(String[] args) {03 final int start = Integer.MAX_VALUE -

04 100;05 final int end = Integer.MAX_VALUE;06 int count = 0;07 for (int i = start; i <= end; i++)08 count++;09 System.out.println(count);10 }11 }

Page 58: Java Puzzle

How Do You Fix It?

• Change loop variable from int to long

for (long i = start; i <= end; i++)

count++;

Page 59: Java Puzzle

The Moral

• ints aren't integers!• Think about overflow

• Use larger type if necessary

Page 60: Java Puzzle

11. “Random Behavior”01 public class RandomSet {02 public static void main(String[] args) {03 Set s = new HashSet();04 for (int i = 0; i < 100; i++)05 s.add(randomInteger());06 System.out.println(s.size());07 }0809 private static Integer randomInteger() {10 return new Integer(new Random().nextInt());11 }12 }

Page 61: Java Puzzle

What Does It Print?

(a) A number close to 1(b) A number close to 50(c) A number close to 100(d) None of the above

Page 62: Java Puzzle

What Does It Print?

(a) A number close to 1(b) A number close to 50(c) A number close to 100(d) None of the above

A new random number generator is created each iteration and the seed changes rarely if at all.

Page 63: Java Puzzle

Another Look01 public class RandomSet {02 public static void main(String[] args) {03 Set s = new HashSet();04 for (int i=0; i<100; i++)05 s.add(randomInteger());06 System.out.println(s.size());07 }0809 private static Integer randomInteger() {10 return new Integer(new Random().nextInt());11 }12 }

Page 64: Java Puzzle

How Do You Fix It?01 public class RandomSet {02 public static void main(String[] args) {03 Set s = new HashSet();04 for (int i=0; i<100; i++)05 s.add(randomInteger());06 System.out.println(s.size());07 }0809 private static Random rnd = new Random();10 11 private static Integer randomInteger() {12 return new Integer(rnd.nextInt());13 }14 }

Page 65: Java Puzzle

The Moral

• Use one Random instance for each sequence

• In most programs, one is all you need

• In multithreaded programs, you may want multiple instances for increased concurrency─ Seed explicitly or risk identical sequences─ Generally ok to use one instance to seed

others

Page 66: Java Puzzle

12.“Making a Hash of It”01 public class Name {02 private String first, last;03 public Name(String first, String last) {04 if (first == null || last == null) 05 throw new NullPointerException();06 this.first = first; this.last = last;07 }08 public boolean equals(Name o) {09 return first.equals(o.first) && last.equals(o.last);10 }11 public int hashCode() {12 return 31 * first.hashCode() + last.hashCode();13 }14 public static void main(String[] args) {15 Set s = new HashSet();16 s.add(new Name("Mickey", "Mouse"));17 System.out.println(18 s.contains(new Name("Mickey", "Mouse")));19 }20 }

Page 67: Java Puzzle

What Does It Print?

(a) true

(b) false

(c) It varies

Page 68: Java Puzzle

What Does It Print?

(a) true

(b) false

(c) It varies

Name overrides hashCode but not equals.The two Name instances are unequal.

Page 69: Java Puzzle

Another Look01 public class Name {02 private String first, last;03 public Name(String first, String last) {04 if (first == null || last == null) 05 throw new NullPointerException();06 this.first = first; this.last = last;07 }08 public boolean equals(Name o) { // Accidental overloading09 return first.equals(o.first) && last.equals(o.last);10 }11 public int hashCode() { // Overriding12 return 31 * first.hashCode() + last.hashCode();13 }14 public static void main(String[] args) {15 Set s = new HashSet();16 s.add(new Name("Mickey", "Mouse"));17 System.out.println(18 s.contains(new Name("Mickey", "Mouse")));19 }20 }

Page 70: Java Puzzle

How Do You Fix It?

• Replace the overloaded equals method with an overriding equals method

01 public boolean equals(Object o) { 02 if (!(o instanceof Name)) 03 return false; 04 Name n = (Name)o; 05 return n.first.equals(first) && n.last.equals(last); 06 }

Page 71: Java Puzzle

The Moral

• If you want to override a method:─Make sure signatures match─ The compiler doesn’t check for you─Do copy-and-paste declarations!

Page 72: Java Puzzle

13. “Ping Pong”01 class PingPong {02 public static synchronized void main(String[] a)

{03 Thread t = new Thread() {04 public void run() {05 pong(); 06 }07 };08 09 t.run();10 System.out.print("Ping");11 }1213 static synchronized void pong() {14 System.out.print("Pong");15 }16 }

Page 73: Java Puzzle

What Does It Print?

(a) PingPong(b) PongPing(c) It varies

Page 74: Java Puzzle

What Does It Print?

(a) PingPong(b) PongPing(c) It varies

Not a multithreaded program!

Page 75: Java Puzzle

Another Look01 class PingPong {02 public static synchronized void main(String[] a) {03 Thread t = new Thread() {04 public void run() {05 pong(); 06 }07 };08 09 t.run(); // Common typo!10 System.out.print("Ping");11 }1213 static synchronized void pong() {14 System.out.print("Pong");15 }16 }

Page 76: Java Puzzle

How Do You Fix It?01 class PingPong {02 public static synchronized void main(String[] a) {03 Thread t = new Thread() {04 public void run() {05 pong(); 06 }07 };0809 t.start();10 System.out.print("Ping");11 }1213 static synchronized void pong() {14 System.out.print("Pong");15 }16 }

Page 77: Java Puzzle

The Moral

• Invoke Thread.start, not Thread.run─Common error─Can be very difficult to diagnose

• (Thread shouldn’t implement Runnable)

Page 78: Java Puzzle

14. “Shifty”01 public class Shifty {02 public static void main(String[] args) {03 int distance = 0;04 while ((-1 << distance) != 0)05 distance++;06 System.out.println(distance);07 }08 }

Page 79: Java Puzzle

What Does It Print?

(a) 31

(b) 32

(c) 33

(d) None of the above

Page 80: Java Puzzle

What Does It Print?

(a) 31

(b) 32

(c) 33

(d) None of the above: infinite loop!

Shift distances are calculated mod 32.

Page 81: Java Puzzle

Another Look01 public class Shifty {02 public static void main(String[] args) {03 int distance = 0;04 while ((-1 << distance) != 0)05 distance++;06 System.out.println(distance);07 }08 }09 10 // (-1 << 32) == -1

Page 82: Java Puzzle

How Do You Fix It?01 public class Shifty {02 public static void main(String[] args) {03 int distance = 0;04 for (int val = -1; val != 0; val <<= 1)05 distance++;06 System.out.println(distance);07 }08 }

Page 83: Java Puzzle

The Moral

• Shift distances are computed mod 32 (or 64)

• It’s impossible to shift out an entire int(or long) using any shift operator or distance

• Use care when shift distance is not a literal

Page 84: Java Puzzle

15. “Line Printer”01 public class LinePrinter {02 public static void main(String[] args) {03 // Note: \u000A is Unicode representation for

newline04 char c = 0x000A;05 System.out.println(c);06 }07 }

Page 85: Java Puzzle

What Does It Print?

(a) Two blank lines(b) 10

(c) Won’t compile(d) It varies

Page 86: Java Puzzle

What Does It Print?

(a) Two blank lines(b) 10

(c) Won’t compile: Syntax error!(d) It varies

The Unicode escape in the comment breaks it in two. The second half is garbage.

Page 87: Java Puzzle

Another Look01 // Unicode escapes are processed before comments!02 public class LinePrinter {03 public static void main(String[] args) {04 // Note: \u000A is unicode representation for

newline05 char c = 0x000A;06 System.out.println(c);07 }08 }

01 // This is what the parser sees02 public class LinePrinter {03 public static void main(String[] args) {04 // Note: 05 is Unicode representation for newline06 char c = 0x000A;07 System.out.println(c);08 }09 }

Page 88: Java Puzzle

How Do You Fix It?01 public class LinePrinter {02 public static void main(String[] args) {03 // Escape sequences (like \n) are fine in comments04 char c = '\n';05 System.out.println(c);06 }07 }

Page 89: Java Puzzle

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 90: Java Puzzle

16. “All Strung Out”01 public class Puzzling {02 public static void main(String[] args) {03 String s = new String("blah");04 System.out.println(s);05 }06 }07 class String {08 java.lang.String s;0910 public String(java.lang.String s) {11 this.s = s;12 }13 public java.lang.String toString() {14 return s;15 }16 }

Page 91: Java Puzzle

What Does It Print?

(a) Won’t compile(b) blah

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

Page 92: Java Puzzle

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.

Page 93: Java Puzzle

Another Look01 public class Puzzling {02 public static void main(String[] args) {03 String s = new String("blah");04 System.out.println(s);05 }06 }07 class String {08 java.lang.String s;09 10 public String(java.lang.String s) {11 this.s = s;12 }13 public java.lang.String toString() {14 return s;15 }16 }

Page 94: Java Puzzle

How Do You Fix It?01 public class Puzzling {02 public static void main(String[] args) {03 MyString s = new MyString("blah");04 System.out.println(s);05 }06 }07 class MyString {08 String s;09 10 public MyString(String s) {11 this.s = s;12 }13 public String toString() {14 return s;15 }16 }

Page 95: Java Puzzle

The Moral

• Avoid name reuse in all its guises─hiding, shadowing, overloading

• Don’t even think about reusing platformclass names!

Page 96: Java Puzzle

17. “Reflection Infection”01 import java.lang.reflect.*;02 03 public class Reflector {04 public static void main(String[] args) throws Exception {05 Set s = new HashSet();06 s.add("foo");07 Iterator i = s.iterator();08 Method m =09 i.getClass().getMethod("hasNext", new Class[0]);10 System.out.println(m.invoke(i, new Object[0]));11 }12 }

Page 97: Java Puzzle

What Does It Print?

(a) Won’t compile(b) true

(c) Throws exception(d) None of the above

Page 98: Java Puzzle

What Does It Print?

(a) Won’t compile(b) true

(c) Throws exception - IllegalAccessError

(d) None of the above

Attempts to invoke a method on a private class

Page 99: Java Puzzle

Another Look01 import java.lang.reflect.*;0203 public class Reflector {04 public static void main(String[] args) throws Exception {05 Set s = new HashSet();06 s.add("foo");07 Iterator i = s.iterator();08 Method m =09 i.getClass().getMethod("hasNext", new Class[0]);10 System.out.println(m.invoke(i, new Object[0]));11 }12 }

Page 100: Java Puzzle

How Do You Fix It?01 import java.lang.reflect.*;02 03 public class Reflector {04 public static void main(String[] args) throws Exception {05 Set s = new HashSet();06 s.add("foo");07 Iterator i = s.iterator();08 Method m =09 Iterator.class.getMethod("hasNext",10 new Class[0]);11 System.out.println(m.invoke(i, new Object[0]));12 }13 }

Page 101: Java Puzzle

The Moral

• Reflection has its own access rules• Avoid reflection when possible• If you must use reflection─ Instantiate using reflection─Cast to an interface type─Access via interface

• Avoid extralinguistic mechanisms

Page 102: Java Puzzle

18. “String Cheese”01 public class StringCheese {02 public static void main(String args[]) {03 byte b[] = new byte[256]; 04 for(int i = 0; i < 256; i++)05 b[i] = (byte)i;06 String str = new String(b);07 for(int i = 0; i < str.length(); i++)08 System.out.print((int)str.charAt(i) + " ");09 }10 }

Page 103: Java Puzzle

What Does It Print?

(a) The numbers from 0 to 255(b) The numbers from 0 to 127 then

-128 to -1(c) It varies(d) None of the above

Page 104: Java Puzzle

What Does It Print?

(a) The numbers from 0 to 255(b) The numbers from 0 to 127 then

-128 to -1(c) It varies*(d) None of the above

The sequence depends on the default charset,which depends on OS and locale.

* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 8364 65533 8218 402 8222 8230 8224 8225 710 8240 352 8249 338 65533 381 65533 65533 8216 8217 8220 8221 8226 8211 8212 732 8482 353 8250 339 65533 382 376 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

Page 105: Java Puzzle

Another Look01 public class StringCheese {02 public static void main(String args[]) {03 byte b[] = new byte[256]; 04 for(int i = 0; i < 256; i++)05 b[i] = (byte)i;06 String str = new String(b);07 for(int i = 0; i < str.length(); i++)08 System.out.print((int)str.charAt(i) + " ");09 }10 }

String(byte[] bytes) -“Constructs a new String by decoding the specified array of bytes using the platform’s default charset.” [from API Spec.]

Page 106: Java Puzzle

How Do You Fix It?

If you want it to print numbers from 0-255 in order:

01 public class StringCheese {02 public static void main(String args[]) {03 byte b[] = new byte[256]; 04 for(int i = 0; i < 256; i++)05 b[i] = (byte)i;06 String str = new String(b, "ISO-8859-1");07 for(int i = 0; i < str.length(); i++)08 System.out.print((int)str.charAt(i) + " ");09 }10 }

ISO-8859-1 indicates the Latin1 charset.

Page 107: Java Puzzle

The Moral

• Converting bytes to chars uses a charset

• If you don’t specify one, you get default─Depends on OS and locale

• If you need predictability, specify a charset

Page 108: Java Puzzle

19. “Elvis Lives!”01 public class Elvis {02 public static final Elvis INSTANCE = new Elvis();03 private final int beltSize;04 05 private static final int CURRENT_YEAR = 06 Calendar.getInstance().get(Calendar.YEAR);07 08 private Elvis() { beltSize = CURRENT_YEAR - 1930; }09 public int beltSize() { return beltSize; }1011 public static void main(String[] args) {12 System.out.println("Elvis wears size " +13 INSTANCE.beltSize() + " belt.");14 }15 }

Page 109: Java Puzzle

What Does It Print?

(a) Elvis wears size 0 belt.

(b) Elvis wears size 73 belt.

(c) Elvis wears size -1930 belt.

(d) None of the above.

Page 110: Java Puzzle

What Does It Print?

(a) Elvis wears size 0 belt.

(b) Elvis wears size 73 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.

Page 111: Java Puzzle

Another Look01 // Static initialization proceeds top to bottom.02 public class Elvis {03 // Recursive initialization returns immediately!04 public static final Elvis INSTANCE = new Elvis();05 private final int beltSize;06 07 private static final int CURRENT_YEAR = 08 Calendar.getInstance().get(Calendar.YEAR);09 10 private Elvis() { beltSize = CURRENT_YEAR - 1930; }11 public int beltSize() { return beltSize; }12 13 public static void main(String[] args) {14 System.out.println("Elvis wears size " +15 INSTANCE.beltSize() + " belt.");16 }17 }

Page 112: Java Puzzle

How Do You Fix It?01 public class Elvis {02 private final int beltSize;03 04 private static final int CURRENT_YEAR = 05 Calendar.getInstance().get(Calendar.YEAR);06 07 // Make instance after other initialization complete08 public static final Elvis INSTANCE = new Elvis();0910 private Elvis() { beltSize = CURRENT_YEAR - 1930; }11 public int beltSize() { return beltSize; }1213 public static void main(String[] args) {14 System.out.println("Elvis wears size " +15 INSTANCE.beltSize() + " belt.");16 }17 }

Page 113: Java Puzzle

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)

Page 114: Java Puzzle

20. “What’s the Point?”01 class Point {02 protected final int x, y;03 private final String name; // Cached at construction time04 protected String makeName() { return "[" + x + "," + y + "]"; }05 public final String toString() { return name; }06 Point(int x, int y) {07 this.x = x; this.y = y;08 this.name = makeName();09 }10 }1112 public class ColorPoint extends Point {13 private final String color;14 protected String makeName() { return super.makeName() + ":" +

color; }15 ColorPoint(int x, int y, String color) {16 super(x, y);17 this.color = color;18 }19 public static void main(String[] args) {20 System.out.println(new ColorPoint(4, 2, "purple"));21 }22 }

Page 115: Java Puzzle

What Does It Print?

(a) [4,2]:purple

(b) [4,2]:null

(c) Throws exception at runtime(d) None of the above

Page 116: Java Puzzle

What Does It Print?

(a) [4,2]:purple

(b) [4,2]:null

(c) Throws exception at runtime(d) None of the above

Superclass constructor runs a subclass method

before the subclass instance is initialized.

Page 117: Java Puzzle

Another Look01 class Point {02 protected final int x, y;03 private final String name;04 protected String makeName() { return "[" + x + "," + y + "]"; }05 public final String toString() { return name; }06 Point(int x, int y) {07 this.x = x; this.y = y;08 this.name = makeName(); // (3) Invokes subclass method09 }10 }1112 public class ColorPoint extends Point {13 private final String color;14 // (4) Subclass method executes before subclass constructor body!15 protected String makeName() { return super.makeName() + ":" +

color; }16 ColorPoint(int x, int y, String color) {17 super(x, y); // (2) Chains to superclass constructor18 this.color = color; // (5) Initializes blank final instance

field19 }20 public static void main(String[] args) { // (1) Invoke subclass cons.21 System.out.println(new ColorPoint(4, 2, "purple"));22 }23 }

Page 118: Java Puzzle

How Do You Fix It?01 class Point {02 protected final int x, y;03 private String name; // Lazily initialized (cached on first use)04 protected String makeName() { return "[" + x + "," + y + "]"; }05 public final synchronized String toString()06 { return (name == null ? (name = makeName()) : name); }07 Point(int x, int y) {08 this.x = x; this.y = y;09 // (name initialization removed)10 }11 }12 13 public class ColorPoint extends Point {14 private final String color;15 protected String makeName() { return super.makeName() + ":" +

color; }16 ColorPoint(int x, int y, String color) {17 super(x, y);18 this.color = color;19 }20 public static void main(String[] args) {21 System.out.println(new ColorPoint(4, 2, "purple"));22 }23 }

Page 119: Java Puzzle

The Moral

• Never call overridable methods from constructors, directly or indirectly

• Also applies to “pseudo-constructors”─ readObject()─ clone()

• See Effective Java, Item 15

Page 120: Java Puzzle

21. “Long Division”01 public class LongDivision {02 private static final long MILLIS_PER_DAY 03 = 24 * 60 * 60 * 1000;04 private static final long MICROS_PER_DAY05 = 24 * 60 * 60 * 1000 * 1000;0607 public static void main(String[] args) {08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);09 }10 }

Page 121: Java Puzzle

What Does It Print?

(a) 5

(b) 1000

(c) 5000

(d) Throws an exception

Page 122: Java Puzzle

What Does It Print?

(a) 5

(b) 1000

(c) 5000

(d) Throws an exception

Computation does overflow

Page 123: Java Puzzle

Another Look01 public class LongDivision {02 private static final long MILLIS_PER_DAY 03 = 24 * 60 * 60 * 1000;04 private static final long MICROS_PER_DAY05 = 24 * 60 * 60 * 1000 * 1000; // >> Integer.MAX_VALUE06 07 public static void main(String[] args) {08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);09 }10 }

Page 124: Java Puzzle

How Do You Fix It?01 public class LongDivision {02 private static final long MILLIS_PER_DAY 03 = 24L * 60 * 60 * 1000;04 private static final long MICROS_PER_DAY05 = 24L * 60 * 60 * 1000 * 1000;06 07 public static void main(String[] args) {08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);09 }10 }

Page 125: Java Puzzle

The Moral

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

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

• When in doubt, use long

Page 126: Java Puzzle

22. “No Pain, No Gain”01 public class Rhymes {02 private static Random rnd = new Random();03 public static void main(String[] args) {04 StringBuffer word = null;05 switch(rnd.nextInt(2)) {06 case 1: word = new StringBuffer('P');07 case 2: word = new StringBuffer('G');08 default: word = new StringBuffer('M');09 }10 word.append('a');11 word.append('i');12 word.append('n');13 System.out.println(word);14 }15 }

Thanks to madbot (also known as Mike McCloskey)

Page 127: Java Puzzle

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 128: Java Puzzle

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 129: Java Puzzle

Another Look01 public class Rhymes {02 private static Random rnd = new Random();03 public static void main(String[] args) {04 StringBuffer word = null;05 switch(rnd.nextInt(2)) { // No breaks!06 case 1: word = new StringBuffer('P');07 case 2: word = new StringBuffer('G');08 default: word = new StringBuffer('M');09 }10 word.append('a');11 word.append('i');12 word.append('n');13 System.out.println(word);14 }15 }

Page 130: Java Puzzle

How Do You Fix It?01 public class Rhymes {02 private static Random rnd = new Random();03 public static void main(String[] args) {04 StringBuffer word = null;05 switch(rnd.nextInt(3)) {06 case 1: word = new StringBuffer("P");

break;07 case 2: word = new StringBuffer("G");

break;08 default: word = new StringBuffer("M");

break;09 }10 word.append('a');11 word.append('i');12 word.append('n');13 System.out.println(word);14 }15 }

Page 131: Java Puzzle

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 132: Java Puzzle

23. “The Name Game”01 public class NameGame {02 public static void main(String args[]) {03 Map m = new IdentityHashMap();04 m.put("Mickey", "Mouse");05 m.put("Mickey", "Mantle");06 System.out.println(m.size());07 }08 }

Page 133: Java Puzzle

What Does It Print?

(a) 0

(b) 1

(c) 2

(d) It varies

Page 134: Java Puzzle

What Does It Print?

(a) 0

(b) 1

(c) 2

(d) It varies

We’re using an IdentityHashMap, but string

literals are interned (they cancel each other out)

Page 135: Java Puzzle

Another Look01 public class NameGame {02 public static void main(String args[]) {03 Map m = new IdentityHashMap();04 m.put("Mickey", "Mouse");05 m.put("Mickey", "Mantle");06 System.out.println(m.size());07 }08 }

Page 136: Java Puzzle

How Do You Fix It?01 public class NameGame {02 public static void main(String args[]) {03 Map m = new HashMap();04 m.put("Mickey", "Mouse");05 m.put("Mickey", "Mantle");06 System.out.println(m.size());07 }08 }

Page 137: Java Puzzle

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 138: Java Puzzle

24. “More of The Same”01 public class Names {02 private Map m = new HashMap();03 public void Names() {04 m.put("Mickey", "Mouse");05 m.put("Mickey", "Mantle");06 }07 08 public int size() { return m.size(); }09 10 public static void main(String args[]) {11 Names names = new Names();12 System.out.println(names.size());13 }14 }

Page 139: Java Puzzle

What Does It Print?

(a) 0

(b) 1

(c) 2

(d) It varies

Page 140: Java Puzzle

What Does It Print?

(a) 0

(b) 1

(c) 2

(d) It varies

No programmer-defined constructor

Page 141: Java Puzzle

Another Look01 public class Names {02 private Map m = new HashMap();03 public void Names() { // Not a constructor!04 m.put("Mickey", "Mouse");05 m.put("Mickey", "Mantle");06 }0708 public int size() { return m.size(); }09 10 public static void main(String args[]) {11 Names names = new Names(); // Invokes

default!12 System.out.println(names.size());13 }14 }

Page 142: Java Puzzle

How Do You Fix It?01 public class Names {02 private Map m = new HashMap();03 public Names() { // No return type04 m.put("Mickey", "Mouse");05 m.put("Mickey", "Mantle");06 }07 08 public int size() { return m.size(); }09 10 public static void main(String args[]) {11 Names names = new Names();12 System.out.println(names.size());13 }14 }

Page 143: Java Puzzle

The Moral

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

• Don’t ever do it

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

Page 144: Java Puzzle

25. “Shades of Gray”01 public class Gray {02 public static void main(String[] args){03 System.out.println(X.Y.Z);04 }05 }06 07 class X {08 static class Y {09 static String Z = "Black";10 }11 static C Y = new C();12 }13 14 class C {15 String Z = "White";16 }

Thanks to Prof. Dominik Gruntz, Fachhochschule Aargau

Page 145: Java Puzzle

What Does It Print?

(a) Black

(b) White

(c) Won’t compile(d) None of the above

Page 146: Java Puzzle

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 147: Java Puzzle

Another Look01 public class Gray {02 public static void main(String[] args){03 System.out.println(X.Y.Z);04 }05 }06 07 class X {08 static class Y {09 static String Z = "Black";10 }11 static C Y = new C();12 }13 14 class C {15 String Z = "White";16 }

The rule: variable > type > package

Page 148: Java Puzzle

How Do You Fix It?01 public class Gray {02 public static void main(String[] args){03 System.out.println(Ex.Why.z);04 }05 }06 07 class Ex {08 static class Why {09 static String z = "Black";10 }11 static See y = new See();12 }13 14 class See {15 String z = "White";16 }

Page 149: Java Puzzle

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 150: Java Puzzle

26. “It’s Elementary”01 public class Elementary {02 public static void main(String[] args) {03 System.out.println(54321 + 5432l);04 }05 }

Page 151: Java Puzzle

What Does It Print?

(a) -22430

(b) 59753

(c) 10864

(d) 108642

Page 152: Java Puzzle

What Does It Print?

(a) -22430

(b) 59753

(c) 10864

(d) 108642

Program doesn’t say what you think it does!

Page 153: Java Puzzle

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

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

04 }05 }

1 - the numeral one

l - the lowercase letter el

Page 154: Java Puzzle

How Do You Fix It?

We won’t insult your intelligence

Page 155: Java Puzzle

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 156: Java Puzzle

27. “Down For The Count”01 public class Count {02 public static void main(String[] args) {03 final int START = 2000000000;04 int count = 0;05 for (float f = START; f < START + 50; f++)06 count++;07 System.out.println(count);08 }09 }

Page 157: Java Puzzle

What Does It Print?

(a) 0

(b) 50

(c) 51

(d) None of the above

Page 158: Java Puzzle

What Does It Print?

(a) 0

(b) 50

(c) 51

(d) None of the above

The termination test misbehaves due to floating point “granularity.”

Page 159: Java Puzzle

Another Look01 public class Count {02 public static void main(String[] args) {03 final int START = 2000000000;04 int count = 0;05 for (float f = START; f < START + 50; f++)06 count++;07 System.out.println(count);08 }09 }

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

Page 160: Java Puzzle

How Do You Fix It?01 public class Count {02 public static void main(String[] args) {03 final int START = 2000000000;04 int count = 0;05 for (int f = START; f < START + 50; f++)06 count++;07 System.out.println(count);08 }09 }

Page 161: Java Puzzle

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

enough precision and you have a compelling performance need (space or time)

Page 162: Java Puzzle

28. “Classy Fire”01 public class Classifier {02 public static void main(String[] args) {03 System.out.println(04 classify('n') + classify('+') + classify('2'));05 }06 static String classify(char ch) {07 if ("0123456789".indexOf(ch) >= 0)08 return "NUMERAL ";09 if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) >= 0)10 return "LETTER ";11 /* (Operators not supported yet)12 * if ("+-*/&|!=".indexOf(ch) >= 0)13 * return "OPERATOR ";14 */15 return "UNKNOWN ";16 }17 }

Page 163: Java Puzzle

What Does It Print?

(a) LETTER OPERATOR NUMERAL

(b) LETTER UNKNOWN NUMERAL

(c) Throws an exception(d) None of the above

Page 164: Java Puzzle

What Does It Print?

(a) LETTER OPERATOR NUMERAL

(b) LETTER UNKNOWN NUMERAL

(c) Throws an exception(d) None of the above

As for the intuition, you’ll see in a moment...

Page 165: Java Puzzle

Another Look01 public class Classifier {02 public static void main(String[] args) {03 System.out.println(04 classify('n') + classify('+') + classify('2'));05 }06 static String classify(char ch) {07 if ("0123456789".indexOf(ch) >= 0)08 return "NUMERAL ";09 if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) >= 0)10 return "LETTER ";11 /* (Operators not supported yet)12 * if ("+-*/&|!=".indexOf(ch) >= 0)13 * return "OPERATOR ";14 */15 return "UNKNOWN ";16 }17 }

Page 166: Java Puzzle

How Do You Fix It?01 public class Classifier {02 public static void main(String[] args) {03 System.out.println(04 classify('n') + classify('+') + classify('2'));05 }06 static String classify(char ch) {07 if ("0123456789".indexOf(ch) >= 0)08 return "NUMERAL ";09 if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) >= 0)10 return "LETTER ";11 if (false) { // (Operators not supported yet)12 if ("+-*/&|!=".indexOf(ch) >= 0)13 return "OPERATOR ";14 }15 return "UNKNOWN ";16 }17 }

Page 167: Java Puzzle

The Moral

• You cannot reliably block-comment out code─Comments do not nest

• Use “if (false)” idiom or “//” comments

Page 168: Java Puzzle

01 public class JoyOfHex {02 public static void main(String[] args) {03 System.out.println(04 Long.toHexString(0x100000000L +

0xcafebabe));05 }06 }

29. “The Joy of Hex”

Page 169: Java Puzzle

What Does It Print?

(a) cafebabe(b) 1cafebabe(c) ffffffffcafebabe(d) Throws an exception

Page 170: Java Puzzle

What Does It Print?

(a) cafebabe(b) 1cafebabe(c) ffffffffcafebabe(d) Throws an exception

0xcafebabe is a negative number

Page 171: Java Puzzle

01 public class JoyOfHex {02 public static void main(String[] args) {03 System.out.println(04 Long.toHexString(0x100000000L +

0xcafebabe));05 }06 }

1 1 1 1 1 1 1

0xffffffffcafebabeL + 0x0000000100000000L 0x00000000cafebabeL

Another Look

Page 172: Java Puzzle

01 public class JoyOfHex {02 public static void main(String[] args) {03 System.out.println(04 Long.toHexString(0x100000000L + 0xcafebabeL));05 }06 }

How Do You Fix It?

Page 173: Java Puzzle

The Moral

• Decimal literals are all positive; not so for hex> Negative decimal constants have minus

sign> Hex literals are negative if the high-order

bit is set

• Widening conversion can cause sign extension

• Mixed-mode arithmetic is tricky—avoid it

Page 174: Java Puzzle

01 public class AnimalFarm {02 public static void main(String[] args) {03 final String pig = "length: 10";04 final String dog = "length: "+pig.length();05 System.out.println("Animals are equal: "06 + pig == dog);07 }08 }

30. “Animal Farm”

Page 175: Java Puzzle

What Does It Print?

(a) Animals are equal: true(b) Animals are equal: false(c) It varies(d) None of the above

Page 176: Java Puzzle

What Does It Print?

(a) Animals are equal: true(b) Animals are equal: false(c) It varies(d) None of the above: false

The + operator binds tighter than ==

Page 177: Java Puzzle

01 public class AnimalFarm {02 public static void main(String[] args) {03 final String pig = "length: 10";04 final String dog = "length: "+pig.length();05 System.out.println("Animals are equal: "06 + pig == dog);07 }08 }

System.out.println( ("Animals are equal: " + pig) == dog);

Another Look

Page 178: Java Puzzle

01 public class AnimalFarm {02 public static void main(String[] args) {03 final String pig = "length: 10";04 final String dog = "length: "+pig.length();05 System.out.println("Animals are equal: "06 + (pig == dog));07 }08 }

How Do You Fix It?

Page 179: Java Puzzle

The Moral

• Parenthesize when using string concatenation• Spacing can be deceptive; parentheses

never lie

• Don’t depend on interning of string

constants• Use equals, not ==, for strings

Page 180: Java Puzzle

01 public class Assignment {02 public static void main(String[] a) throws Exception {03 int tricky = 0;04 for (int i = 0; i < 3; i++)05 tricky += tricky++;06 System.out.println(tricky);07 }08 }

31. “A Tricky Assignment”

Page 181: Java Puzzle

What Does It Print?

(a) 0(b) 3(c) 14(d) None of the above

Page 182: Java Puzzle

What Does It Print?

(a) 0(b) 3(c) 14(d) None of the above

Operands are evaluated left to right.Postfix increment returns old value.

Page 183: Java Puzzle

01 public class Assignment {02 public static void main(String[] a) throws Exception {03 int tricky = 0;04 for (int i = 0; i < 3; i++)05 tricky += tricky++;06 System.out.println(tricky);07 }08 }

Another Look

Page 184: Java Puzzle

01 public class Assignment {02 public static void main(String[] a) throws Exception {03 int tricky = 0;04 for (int i = 0; i < 3; i++)05 tricky += tricky++;06 System.out.println(tricky);07 }08 }

Another Look

Page 185: Java Puzzle

05 tricky += tricky++; (0) (tricky == 0)

Another Look

Page 186: Java Puzzle

05 tricky += tricky++; (0) (tricky == 0)

Another Look

Page 187: Java Puzzle

05 tricky += tricky++; 0 0 (tricky == 1)

Another Look

Page 188: Java Puzzle

05 tricky += tricky++; 0 0 (tricky == 1)

Another Look

Page 189: Java Puzzle

05 tricky += tricky++; 0 0 (tricky == 0)

Another Look

Page 190: Java Puzzle

01 public class Assignment {02 public static void main(String[] a) throws Exception {03 int tricky = 0;04 for (int i = 0; i < 3; i++)05 tricky += tricky++;06 System.out.println(tricky);07 }08 }

Another Look

Page 191: Java Puzzle

01 public class Assignment {02 public static void main(String[] a) throws Exception {03 int tricky = 0;04 for (int i = 0; i < 3; i++) {05 tricky++;06 tricky += tricky; // or tricky *= 2;07 }08 System.out.println(tricky);09 }10 }

How Do You Fix It?

Page 192: Java Puzzle

The Moral

• Don’t depend on details of expression evaluation

• Don’t assign to a variable twice in one expression

• Postfix increment returns old value• (Operands are evaluated left to right)

Page 193: Java Puzzle

01 public class Loop {02 public static void main(String[] args) {03 int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 },04 { 1, 2, 3 }, { 1, 2, 3, 4 },

{ 1 } };05 int successCount = 0;06 try {07 int i = 0;08 while (true) {09 if (thirdElementIsThree(tests[i++]))10 successCount++;11 }12 } catch (ArrayIndexOutOfBoundsException e) { }13 System.out.println(successCount);14 }15 private static boolean thirdElementIsThree(int[] a) {16 return a.length >= 3 & a[2] == 3;17 }18 }

32. “Thrown for a Loop”

Page 194: Java Puzzle

What Does It Print?

(a) 0(b) 1(c) 2(d) None of the above

Page 195: Java Puzzle

What Does It Print?

(a) 0(b) 1(c) 2(d) None of the above

Not only is the program repulsive, but it has a bug

Page 196: Java Puzzle

01 public class Loop {02 public static void main(String[] args) {03 int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 },04 { 1, 2, 3 }, { 1, 2, 3, 4 },

{ 1 } };05 int successCount = 0;06 try {07 int i = 0;08 while (true) {09 if (thirdElementIsThree(tests[i++]))10 successCount++;11 }12 } catch (ArrayIndexOutOfBoundsException e) { }13 System.out.println(successCount);14 }15 private static boolean thirdElementIsThree(int[] a) {16 return a.length >= 3 & a[2] == 3;17 }18 }

Another Look

Page 197: Java Puzzle

01 public class Loop {02 public static void main(String[] args) {03 int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 },04 { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } };05 int successCount = 0;06 for (int[] test : tests)07 if (thirdElementIsThree(test))08 successCount++;09 System.out.println(successCount);10 }11 12 private static boolean thirdElementIsThree(int[] a) {13 return a.length >= 3 && a[2] == 3;14 }15 }

How Do You Fix It?

Page 198: Java Puzzle

The Moral

• Use exceptions only for exceptional conditions> Never use exceptions for normal

control flow

• Beware the logical AND and OR operators> Document all intentional uses of & and |

on boolean

Page 199: Java Puzzle

01 class Cache {02 static { initIfNecessary(); }03 private static int sum;04 public static int getSum() {05 initIfNecessary();06 return sum;07 }08 private static boolean initialized = false;09 private static synchronized void initIfNecessary() {10 if (!initialized) {11 for (int i = 0; i < 100; i++)12 sum += i;13 initialized = true;14 }15 }16 public static void main(String[] args) {17 System.out.println(getSum());18 }19 }

33. “Sum Fun”

Page 200: Java Puzzle

What Does It Print?

(a) 4950(b) 5050(c) 9900(d) None of the above

Page 201: Java Puzzle

What Does It Print?

(a) 4950(b) 5050(c) 9900(d) None of the above

Lazy initialization + eager initialization = a mess

Page 202: Java Puzzle

01 class Cache {02 static { initIfNecessary(); }03 private static int sum;04 public static int getSum() {05 initIfNecessary();06 return sum;07 }08 private static boolean initialized = false;09 private static synchronized void initIfNecessary() {10 if (!initialized) {11 for (int i = 0; i < 100; i++)12 sum += i;13 initialized = true;14 }15 }16 public static void main(String[] args) {17 System.out.println(getSum());18 }19 }

Another Look

Page 203: Java Puzzle

01 class Cache {02 static { initIfNecessary(); }03 private static int sum;04 public static int getSum() {05 initIfNecessary();06 return sum;07 }08 private static boolean initialized = false; // Ouch!09 private static synchronized void initIfNecessary() {10 if (!initialized) {11 for (int i = 0; i < 100; i++)12 sum += i;13 initialized = true;14 }15 }16 public static void main(String[] args) {17 System.out.println(getSum());18 }19 }

Another Look

Page 204: Java Puzzle

01 class Cache {02 private static final int SUM = computeSum();03 04 private static int computeSum() {05 int result = 0;06 for (int i = 0; i < 100; i++)07 result += i;08 return result;09 }10 11 public static int getSum() {12 return SUM;13 }14 15 public static void main(String[] args) {16 System.out.println(getSum());17 }18 }

How Do You Fix It?

Page 205: Java Puzzle

The Moral

• Use eager or lazy initialization, not both> Prefer eager initialization to lazy

• Think about class initialization• Avoid complex class initialization

sequences

Page 206: Java Puzzle

01 public class Mod {02 public static void main(String[] args) {03 final int MODULUS = 3;04 int[] histogram = new int[MODULUS];05 06 int i = Integer.MIN_VALUE;07 // This loop iterates over all int values08 do {09 histogram[Math.abs(i) % MODULUS]++;10 } while (i++ != Integer.MAX_VALUE);11 12 for (int j = 0; j < MODULUS; j++)13 System.out.print(histogram[j] + " ");14 }15 }

34. “The Mod Squad”

Page 207: Java Puzzle

What Does It Print?

(a) 1431655765 1431655765 1431655765(b) 1431655765 1431655766 1431655765

(c) Throws an exception(d) None of the above

Hint: 232 / 3 = 1,431,655,765

Page 208: Java Puzzle

What Does It Print?

(a) 1431655765 1431655765 1431655765(b) 1431655765 1431655766 1431655765

(c) Throws an exception: array out of bounds(d) None of the above

Math.abs doesn’t always return a nonnegative value

Page 209: Java Puzzle

01 public class Mod {02 public static void main(String[] args) {03 final int MODULUS = 3;04 int[] histogram = new int[MODULUS];05 06 int i = Integer.MIN_VALUE;07 // This loop iterates over all int values08 do {09 histogram[Math.abs(i) % MODULUS]++;10 } while (i++ != Integer.MAX_VALUE);11 12 for (int j = 0; j < MODULUS; j++)13 System.out.println(histogram[j] + " ");14 }15 }

Another Look

Page 210: Java Puzzle

Replace: histogram[Math.abs(i) % MODULUS]++;

With: histogram[mod(i, MODULUS)]++;

private static int mod(int i, int modulus) {

int result = i % modulus;

return result < 0 ? result + modulus : result;

}

How Do You Fix It?

Page 211: Java Puzzle

The Moral

• Math.abs can return a negative value• Two’s-complement integers are

asymmetric• int arithmetic overflows silently

• i mod m ≠ Math.abs(i) % m

Page 212: Java Puzzle

01 package click;02 public class CodeTalk {03 public void doIt() { printMessage(); }04 void printMessage() { System.out.println("Click"); }05 }___________________________________________________________

01 package hack;02 import click.CodeTalk;03 public class TypeIt {04 private static class ClickIt extends CodeTalk {05 void printMessage()

{ System.out.println("Hack"); }06 }07 public static void main(String[] args) {08 new ClickIt().doIt();09 }10 }

35. “Package Deal”

Page 213: Java Puzzle

What Does It Print?

(a) Click(b) Hack(c) Won’t compile(d) None of the above

Page 214: Java Puzzle

What Does It Print?

(a) Click(b) Hack(c) Won’t compile(d) None of the above

There is no overriding in this program

Page 215: Java Puzzle

01 package click;02 public class CodeTalk {03 public void doIt() { printMessage(); }04 void printMessage() { System.out.println("Click"); }05 }___________________________________________________________

01 package hack;02 import click.CodeTalk;03 public class TypeIt {04 private static class ClickIt extends CodeTalk {05 void printMessage()

{ System.out.println("Hack"); }06 }07 public static void main(String[] args) {08 new ClickIt().doIt();09 }10 }

Another Look

Page 216: Java Puzzle

How Do You Fix It?

• If you want overriding• Make printMessage public or protected• Use @Override to ensure that you got

overriding

Page 217: Java Puzzle

The Moral

• Package-private methods can’t be overridden by methods outside their package

• If you can’t see it, you can’t override it

Page 218: Java Puzzle

01 public class Lazy {02 private static boolean initialized = false;03 static {04 Thread t = new Thread(new Runnable() {05 public void run() {06 initialized = true;07 }08 });09 t. start();10 try {11 t.join();12 } catch (InterruptedException e) {13 throw new AssertionError(e);14 }15 }16 public static void main(String[] args) {17 System.out.println(initialized);18 }19 }

36. “Lazy Initialization”

Page 219: Java Puzzle

What Does It Print?

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

Page 220: Java Puzzle

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.

Page 221: Java Puzzle

01 public class Lazy {02 private static boolean initialized = false;03 static {04 Thread t = new Thread(new Runnable() {05 public void run() {06 initialized = true; // Deadlocks here!07 }08 });09 t. start();10 try {11 t.join();12 } catch (InterruptedException e) {13 throw new AssertionError(e);14 }15 }16 public static void main(String[] args) {17 System.out.println(initialized);18 }19 }

Another Look

Page 222: Java Puzzle

How Do You Fix It?

• Don’t use background threads in class initialization> If it hurts when you go like that, don’t go

like that!

Page 223: Java Puzzle

The Moral

• Never use background threads in class initialization

• Keep class initialization simple• Don’t code like my brother

Page 224: Java Puzzle

01 public class OddBehavior {02 public static void main(String[] args) {03 List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2);04 05 boolean foundOdd = false;06 for (Iterator<Integer> it=list.iterator();it.hasNext(); )07 foundOdd = foundOdd || isOdd(it.next());08 09 System.out.println(foundOdd);10 }11 12 private static boolean isOdd(int i) {13 return (i & 1) != 0;14 }15 }

37. “Odd Behavior”

Page 225: Java Puzzle

01 public class OddBehavior {02 public static void main(String[] args) {03 List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2);04 05 boolean foundOdd = false;06 for (Iterator<Integer> it=list.iterator(); it.hasNext(); )07 foundOdd = foundOdd || isOdd(it.next());08 09 System.out.println(foundOdd);10 }11 12 private static boolean isOdd(int i) {13 return (i & 1) != 0;14 }15 }

What Does It Print?

(a) true

(b) false

(c) Throws exception

(d) None of the above

Page 226: Java Puzzle

What Does It Print?

(a) true(b) false(c) Throws exception(d) None of the above: Nothing—Infinite loop

Conditional OR operator (||) short-circuits iterator

Page 227: Java Puzzle

public class OddBehavior { public static void main(String[] args) { List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2); boolean foundOdd = false; for (Iterator<Integer> it = list.iterator(); it.hasNext();

) foundOdd = foundOdd || isOdd(it.next()); System.out.println(foundOdd); } private static boolean isOdd(int i) { return (i & 1) != 0; }}

Another Look

Page 228: Java Puzzle

public class OddBehavior { public static void main(String[] args) { List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2); boolean foundOdd = false; for (int i : list) foundOdd = foundOdd || isOdd(i); System.out.println(foundOdd); } private static boolean isOdd(int i) { return (i & 1) != 0; }}

You Could Fix it Like This….

Page 229: Java Puzzle

public class OddBehavior { public static void main(String[] args) { List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2); System.out.println(containsOdd(list)); }

private static boolean containsOdd(List<Integer> list) { for (int i : list) if (isOdd(i)) return true; return false; } private static boolean isOdd(int i) { return (i & 1) != 0; }}

…But This Is Even Better

Page 230: Java Puzzle

The Moral

• Use for-each wherever possible> Nicer and safer than explicit iterator or

index usage

• If you must use an iterator, make sure you call next() exactly once

• Conditional operators evaluate their right operand only if necessary to determine result> This is almost always what you want> If not, you can use the logical operators

(& and |)

Page 231: Java Puzzle

public class SetList { public static void main(String[] args) { Set<Integer> set = new LinkedHashSet<Integer>(); List<Integer> list = new ArrayList<Integer>(); for (int i = -3; i < 3; i++) { set.add(i); list.add(i); } for (int i = 0; i < 3; i++) { set.remove(i); list.remove(i); } System.out.println(set + " " + list); }}

38. “Set List”

Page 232: Java Puzzle

public class SetList { public static void main(String[] args) { Set<Integer> set = new LinkedHashSet<Integer>(); List<Integer> list = new ArrayList<Integer>(); for (int i = -3; i < 3; i++) { set.add(i); list.add(i); } for (int i = 0; i < 3; i++) { set.remove(i); list.remove(i); } System.out.println(set + " " + list); }}

What Does It Print?(a) [-3, -2, -1] [-3, -2, -1]

(b) [-3, -2, -1] [-2, 0, 2]

(c) Throws exception

(d) None of the above

Page 233: Java Puzzle

What Does It Print?

(a) [-3, -2, -1] [-3, -2, -1](b) [-3, -2, -1] [-2, 0, 2](c) Throws exception(d) None of the above

Autoboxing + overloading = confusion

Page 234: Java Puzzle

public class SetList { public static void main(String[] args) { Set<Integer> set = new LinkedHashSet<Integer>(); List<Integer> list = new ArrayList<Integer>(); for (int i = -3; i < 3; i++) { set.add(i); list.add(i); } for (int i = 0; i < 3; i++) { set.remove(i); list.remove(i); // List.remove(int) } System.out.println(set + " " + list); }}

Another Look

Page 235: Java Puzzle

public class SetList { public static void main(String[] args) { Set<Integer> set = new LinkedHashSet<Integer>(); List<Integer> list = new ArrayList<Integer>(); for (int i = -3; i < 3; i++) { set.add(i); list.add(i); } for (int i = 0; i < 3; i++) { set.remove(i); list.remove((Integer) i); } System.out.println(set + " " + list); }}

How Do You Fix It?

Page 236: Java Puzzle

The Moral

• Avoid ambiguous overloadings• Harder to avoid in release 5.0

> Autoboxing, varargs, generics

• Design new APIs with this in mind> Old rules no longer suffice

• Luckily, few existing APIs were compromised> Beware List<Integer>

Page 237: Java Puzzle

public enum PowerOfTen { ONE(1), TEN(10), HUNDRED(100) { @Override public String toString() { return Integer.toString(val); } }; private final int val; PowerOfTen(int val) { this.val = val; }

@Override public String toString() { return name().toLowerCase(); } public static void main(String[] args) { System.out.println(ONE + " " + TEN + " " + HUNDRED); }}

39. “Powers of Ten”

Page 238: Java Puzzle

public enum PowerOfTen { ONE(1), TEN(10), HUNDRED(100) { @Override public String toString() { return Integer.toString(val); } }; private final int val; PowerOfTen(int val) { this.val = val; }

@Override public String toString() { return name().toLowerCase(); } public static void main(String[] args) { System.out.println(ONE + " " + TEN + " " + HUNDRED); }}

What Does It Print? (a) ONE TEN HUNDRED

(b) one ten hundred

(c) one ten 100

(d) None of the above

Page 239: Java Puzzle

What Does It Print?

(a) ONE TEN HUNDRED(b) one ten hundred(c) one ten 100(d) None of the above: Won’t compile Non-static variable val can’t be referenced from static context

return Integer.toString(val);

^

Private members are never inherited

Page 240: Java Puzzle

public enum PowerOfTen { ONE(1), TEN(10), HUNDRED(100) { // Creates static anonymous class @Override public String toString() { return Integer.toString(val); } }; private final int val; PowerOfTen(int val) { this.val = val; }

@Override public String toString() { return name().toLowerCase(); } public static void main(String[] args) { System.out.println(ONE + " " + TEN + " " + HUNDRED); }}

Another Look

Page 241: Java Puzzle

public enum PowerOfTen { ONE(1), TEN(10), HUNDRED(100) { @Override public String toString() { return Integer.toString(super.val); } }; private final int val; PowerOfTen(int val) { this.val = val; }

@Override public String toString() { return name().toLowerCase(); } public static void main(String[] args) { System.out.println(ONE + " " + TEN + " " + HUNDRED); }}

How Do You Fix It?

Page 242: Java Puzzle

The Moral

• Nest-mates can use each others’ private members

• But private members are never inherited

• Constant-specific enum bodies define static anonymous classes

• Compiler diagnostics can be confusing

Page 243: Java Puzzle

import java.lang.reflect.*;

@interface Test { }public class Testy { @Test public static void test() { return; } @Test public static void test2() { new RuntimeException(); } public static void main(String[] args) throws Exception { for (Method m : Testy.class.getDeclaredMethods()) { if (m.isAnnotationPresent(Test.class)) { try { m.invoke(null); System.out.print("Pass "); } catch (Throwable ex) { System.out.print("Fail "); } } } }}

40. “Testy Behavior”

Page 244: Java Puzzle

import java.lang.reflect.*;

@interface Test { }public class Testy { @Test public static void test() { return; } @Test public static void test2() { new RuntimeException(); } public static void main(String[] args) throws Exception { for (Method m : Testy.class.getDeclaredMethods()) { if (m.isAnnotationPresent(Test.class)) { try { m.invoke(null); System.out.print("Pass "); } catch (Throwable ex) { System.out.print("Fail "); } } } }}

What Does It Print? (a) Pass Fail

(b) Pass Pass

(c) It varies

(d) None of the above

Page 245: Java Puzzle

What Does It Print?

(a) Pass Fail(b) Pass Pass(c) It varies(d) None of the above: In fact, nothing!

The program contains two bugs, both subtle

Page 246: Java Puzzle

import java.lang.reflect.*;

@interface Test { } // By default, annotations are discarded at runtimepublic class Testy { @Test public static void test() { return; } @Test public static void test2() { new RuntimeException(); } // Oops ! public static void main(String[] args) throws Exception { for (Method m : Testy.class.getDeclaredMethods()) { if (m.isAnnotationPresent(Test.class)) { try { m.invoke(null); System.out.print("Pass"); } catch (Throwable ex) { System.out.print("Fail "); } } } }}

Another Look

Page 247: Java Puzzle

import java.lang.reflect.*;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME) @interface Test { }public class Testy { @Test public static void test() { return; } @Test public static void test2() { throw new RuntimeException(); } public static void main(String[] args) throws Exception { for (Method m : Testy.class.getDeclaredMethods()) { if (m.isAnnotationPresent(Test.class)) { try { m.invoke(null); System.out.print("Pass "); } catch (Throwable ex) { System.out.print("Fail "); } } } }}

How Do You Fix It?

Page 248: Java Puzzle

The Moral

• By default, annotations are discarded at runtime> If you need annotations at runtime, use @Retention(RetentionPolicy.RUNTIME)

> If you want them omitted from class file, use @Retention(RetentionPolicy.SOURCE)

• No guarantee on order of reflected entities

• Don’t forget to throw your exceptions

Page 249: Java Puzzle

public class Bleep { String name = "Bleep"; void setName(String name) { this.name = name; } void backgroundSetName() throws InterruptedException { Thread t = new Thread() { @Override public void run() { setName("Blat"); } }; t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException

{ new Bleep().backgroundSetName(); }}

41. “What the Bleep?”

Page 250: Java Puzzle

public class Bleep { String name = "Bleep"; void setName(String name) { this.name = name; } void backgroundSetName() throws InterruptedException { Thread t = new Thread() { @Override public void run() { setName("Blat"); } }; t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException

{ new Bleep().backgroundSetName(); }}

What Does It Print? (a) Bleep

(b) Blat

(c) It varies

(d) None of the above

Page 251: Java Puzzle

What Does It Print?

(a) Bleep(b) Blat(c) It varies(d) None of the above

Bleep.setName isn’t getting called

Page 252: Java Puzzle

public class Bleep { String name = "Bleep"; void setName(String name) { // Does this look familiar? this.name = name; } void backgroundSetName() throws InterruptedException { Thread t = new Thread() { // Invokes Thread.setName (shadowing) @Override public void run() { setName("Blat"); } }; t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException

{ new Bleep().backgroundSetName(); }}

Another Look

Page 253: Java Puzzle

public class Bleep { String name = "Bleep"; void setName(String name) { this.name = name; } void backgroundSetName() throws InterruptedException { Thread t = new Thread(new Runnable() { public void run() { setName("Blat"); } }); t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException

{ new Bleep().backgroundSetName(); }}

How Do You Fix It?

Page 254: Java Puzzle

The Moral

• Don’t extend Thread> Use new Thread(Runnable) instead

• Often the Executor Framework is better still> Much more flexible

> See java.util.concurrent for more information

• Beware of shadowing

Page 255: Java Puzzle

public class BeyondCompare { public static void main(String[] args) { Object o = new Integer(3); System.out.println(new Double(3).compareTo(o) == 0); }}

42. “Beyond Compare”

Page 256: Java Puzzle

public class BeyondCompare { public static void main(String[] args) { Object o = new Integer(3); System.out.println(new Double(3).compareTo(o) == 0); }}

What Does It Print?

(a) true

(b) false

(c) Throws exception

(d) None of the above

Page 257: Java Puzzle

What Does It Print?(a) true

(b) false

(c) Throws exception

(d) None of the above: Won’t compile (it did in 1.4) compareTo(Double) in Double cannot be applied to (Object)

System.out.println(new Double(3).compareTo(o) == 0);

^

The Comparable interface was generified in 5.0

Page 258: Java Puzzle

public class BeyondCompare { public static void main(String[] args) { Object o = new Integer(3); System.out.println(new Double(3).compareTo(o) == 0); }}

// Interface Comparable was generified in release 5.0public interface Comparable<T> { int compareTo(T t); // Was Object}

public class Double extends Number implements Comparable<Double>

Another Look

Page 259: Java Puzzle

// Preserves 1.4 semanticspublic class BeyondCompare { public static void main(String[] args) { Object o = new Integer(3); System.out.println( new Double(3).compareTo((Double) o) == 0); }}

// Fixes the underlying problempublic class BeyondCompare { public static void main(String[] args) { Double d = 3.0; System.out.println(Double.valueOf(3).compareTo(d) == 0); }}

How Do You Fix It?

Page 260: Java Puzzle

The Moral

• Binary compatibility is preserved at all costs

• Source compatibility broken for good cause (rare)• Comparable<T> alerts you to errors at compile

time

• Take compiler diagnostics seriously> Often there is an underlying problem

Page 261: Java Puzzle

public class Fibonacci { private static final int LENGTH = 7; public static void main(String[] args) { int[] fib = new int[LENGTH]; fib[0] = fib[1] = 1; // First 2 Fibonacci numbers for (int i = 2; i < LENGTH; i++) fib[i] = fib[i - 2] + fib[i - 1];

System.out.println(Arrays.asList(fib)); }}

43. “Fib O’Nacci”

Page 262: Java Puzzle

public class Fibonacci { private static final int LENGTH = 7; public static void main(String[] args) { int[] fib = new int[LENGTH]; fib[0] = fib[1] = 1; // First 2 Fibonacci numbers for (int i = 2; i < LENGTH; i++) fib[i] = fib[i - 2] + fib[i - 1];

System.out.println(Arrays.asList(fib)); }}

What Does It Print?

(a) [1, 1, 2, 3, 5, 8, 13]

(b) Throws exception

(c) It varies

(d) None of the above

Page 263: Java Puzzle

What Does It Print?

(a) [1, 1, 2, 3, 5, 8, 13](b) Throws exception(c) It varies: Depends on hashcode [[I@ad3ba4](d) None of the above

Arrays.asList only works on arrays of object refs

Page 264: Java Puzzle

public class Fibonacci { private static final int LENGTH = 7; public static void main(String[] args) { int[] fib = new int[LENGTH]; fib[0] = fib[1] = 1; // First 2 Fibonacci numbers for (int i = 2; i < LENGTH; i++) fib[i] = fib[i - 2] + fib[i - 1];

// Idiom only works for arrays of object references System.out.println(Arrays.asList(fib)); }}

Another Look

Page 265: Java Puzzle

public class Fibonacci { private static final int LENGTH = 7; public static void main(String[] args) { int[] fib = new int[LENGTH]; fib[0] = fib[1] = 1; // First 2 Fibonacci numbers for (int i = 2; i < LENGTH; i++) fib[i] = fib[i - 2] + fib[i - 1];

System.out.println(Arrays.toString(fib)); }}

How Do You Fix It?

Page 266: Java Puzzle

The Moral

• Use varargs sparingly in your APIs> It can hide errors and cause confusion> This program wouldn't compile under 1.4

• Arrays.asList printing idiom is obsolete> use Arrays.toString instead> Prettier, safer, and more powerful

• A full complement of array utilities added in 5.0• equals, hashCode, toString for all array

types

• Integer is not the same as int

Page 267: Java Puzzle

public class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesn't represent a valid integer */ public static Integer parseInt(String s) { return (s == null) ? (Integer) null : Integer.parseInt(s); }

public static void main(String[] args) { System.out.println(parseInt("-1") + " " + parseInt(null) + " " + parseInt("1")); }}

44. “Parsing Is Such Sweet Sorrow”

Page 268: Java Puzzle

public class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesn't represent a valid integer */ public static Integer parseInt(String s) { return (s == null) ? (Integer) null : Integer.parseInt(s); }

public static void main(String[] args) { System.out.println(parseInt("-1") + " " + parseInt(null) + " " + parseInt("1")); }}

What Does It Print? (a) -1 null 1

(b) -1 0 1

(c) Throws exception(d) None of the above

Page 269: Java Puzzle

What Does It Print?

(a) -1 null 1(b) -1 0 1(c) Throws exception: NullPointerException

(d) None of the above

Program attempts to auto-unbox null

Page 270: Java Puzzle

public class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesn't represent a valid integer. */ public static Integer parseInt(String s) { return (s == null) ? // Mixed-type computation: Integer and int (Integer) null : Integer.parseInt(s); }

public static void main(String[] args) { System.out.println(parseInt("-1") + " " + parseInt(null) + " " + parseInt("1")); }}

Another Look

Page 271: Java Puzzle

public class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesn't represent a valid integer. */ public static Integer parseInt(String s) { return (s == null) ? null : Integer.valueOf(s); }

public static void main(String[] args) { System.out.println(parseInt("-1") + " " + parseInt(null) + " " + parseInt("1")); }}

How Do You Fix It?

Page 272: Java Puzzle

The Moral

• Mixed-type computations are confusing

• Especially true for ?: expressions

• Avoid null where possible

• Auto-unboxing and null are a dangerous mix

Page 273: Java Puzzle

Resources and Summary

Page 274: Java Puzzle

Resources

• Send more puzzles– [email protected]

Page 275: Java Puzzle

Conclusion

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

them!

• Keep programs simple– Avoid name reuse: overloading, hiding,

shadowing

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