Java PuzzlesFilipp Shubin
Overall Presentation Goal   Learn some of the quirks of   programming in general and the   Java language in particular;   ...
Learning Objectives• As a result of this presentation, you  will be able to:  –   Avoid some common programming      pitfa...
1. “All I Get is Static”01   class Dog {02       public static void bark() {03           System.out.print("woof ");04     ...
What Does It Print?(a) woof(b) woof woof(c) It varies
What Does It Print?(a) woof(b) woof woof(c) It variesNo dynamic dispatch on static methods
Another Look01   class Dog {02       public static void bark() {03           System.out.print("woof ");04       }05   }06 ...
How Do You Fix It?• Remove static from the bark  method
The Moral• Static methods cant be overridden  –   They can only be hidden• Don’t hide static methods• Never invoke static ...
2. “Whats in a Name?”01 public class Name {02     private String first, last;03     public Name(String first, String last)...
What Does It Print?(a) True(b) False(c) It varies
What Does It Print?(a) True(b) False(c) It variesDonald is in the set, but the set can’t find  him.The Name class violates...
Another Look01 public class Name {02     private String first, last;03     public Name(String first, String last) {04     ...
How Do You Fix It?Add a hashCode method:public int hashCode() {  return 31 * first.hashCode() + last.hashCode();}
The Moral• If you override equals, override  hashCode• Obey general contracts when  overriding• See Effective Java, Chapte...
3. “Indecision”01 class Indecisive {02     public static void main(String[] args) {03         System.out.println(waffle())...
What Does It Print?(a) true(b) false(c) None of the above
What Does It Print?(a) true(b) false(c) None of the aboveThe finally is processed after the try.
Another Look01 class Indecisive {02     public static void main(String[] args) {03         System.out.println(waffle());04...
The Moral• Avoid abrupt completion of  finally blocks  –   Wrap unpredictable actions with nested      trys  –   Dont retu...
4. “The Saga of the Sordid Sort”01 public class SordidSort {02     public static void main(String args[]) {03         Inte...
What Does It Print?(a) [-2000000000, 0, 2000000000](b) [2000000000, 0, -2000000000](c) [-2000000000, 2000000000, 0](d) It ...
What Does It Print?(a) [-2000000000, 0, 2000000000](b) [2000000000, 0, -2000000000](c) [-2000000000, 2000000000, 0](d) It ...
Another Look01 public class SordidSort {02     public static void main(String args[]) {03         Integer big   = new Inte...
How Do You Fix It?• Replace comparator with one that  works   01   public int compare(Object o1, Object o2) {   02       i...
The Moral• ints arent integers!• Think about overflow• This particular comparison technique  –   OK only if max - min <= I...
5. “Youre Such a Character”01 public class Trivial {02     public static void main(String args[]) {03         System.out.p...
What Does It Print?(a) HaHa(b) Ha(c) None of the above
What Does It Print?(a) HaHa(b) Ha(c) None of the above: It prints Ha169  H + a evaluated as int, then converted    to Stri...
The Moral•   Use string concatenation (+) with    care    –   At least one operand must be a String    –   If it isnt, cas...
6. “The Case of the Constructor”01 public class Confusing {02     public Confusing(Object o) {03         System.out.printl...
What Does It Print?(a) Object(b) double array(c) None of the above
What Does It Print?(a) Object(b) double array(c) None of the above   When multiple overloadings   apply, the most specific...
Another Look01 public class Confusing {02     public Confusing(Object o) {03         System.out.println("Object");04     }...
How Do You Fix It?• There may be no problem• If there is, use a cast:  New Confusing((Object)null);
The Moral• Avoid overloading• If you overload, avoid ambiguity• If you do have ambiguous  overloadings, make their behavio...
7. “A Big Delight in Every Byte”01 public class ByteMe {02     public static void main(String[] args) {03       for (byte ...
What Does It Print?(a) (nothing)(b) Byte me!(c) Byte me! Byte me!
What Does It Print?(a) (nothing)(b) Byte me!(c) Byte me! Byte me!Program compares a byte with an  int  –   byte is promote...
Another Look01 public class ByteMe {02     public static void main(String[] args) {03       for (byte b = Byte.MIN_VALUE;0...
How Do You Fix It?• Cast int to byte if (b == (byte)0x90)   System.out.println("Byte me!");• Or convert byte to int, suppr...
The Moral• Bytes arent ints• Be careful when mixing primitive  types• Compare like-typed expressions  –   Cast or convert ...
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 Ch...
What Does It Print?(a) 0.9(b) 0.90(c) It varies(d) None of the above
What Does It Print?(a) 0.9(b) 0.90(c) It varies(d) None of the above:  0.89999999999999  Decimal Values cant be represente...
How Do You Fix It?01   import java.math.BigDecimal;02   public class Change2 {03       public static void main(String args...
The Moral• Avoid float and double where  exact answers are required• Use BigDecimal, int, or long  instead
9. “A Private Matter”01   class Base {02       public String name = "Base";03   }0405   class Derived extends Base {06    ...
What Does It Print?(a) Derived(b) Base(c) Compiler error in class Derived:   Cant assign weaker access to name(d) None of ...
What Does it Print?(a) Derived(b) Base(c) Compiler error in class Derived:    Cant assign weaker access to name(d) None of...
Another Look01   class Base {02       public String name = "Base";03   }0405   class Derived extends Base {06       privat...
How Do You Fix It?01   class Base {02       public String getName() { return "Base"; }03   }0405   class Derived extends B...
The Moral• Avoid hiding  –   Violates subsumption• Avoid public fields  –   Use accessor methods instead
10. “Loopy Behavior”01 public class Loopy {02     public static void main(String[] args) {03       final int start = Integ...
What Does It Print?(a) 100(b) 101(c) (nothing)
What Does It Print?(a) 100(b) 101(c) (nothing)The loop test is broken - infinite loop!
Another Look01 public class Loopy {02     public static void main(String[] args) {03       final int start = Integer.MAX_V...
How Do You Fix It?• Change loop variable from int  to long for (long i = start; i <= end; i++)   count++;
The Moral• ints arent integers!• Think about overflow• Uselarger type if  necessary
11. “Random Behavior”01 public class RandomSet {02     public static void main(String[] args) {03         Set s = new Hash...
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
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 aboveA new rand...
Another Look01 public class RandomSet {02     public static void main(String[] args) {03         Set s = new HashSet();04 ...
How Do You Fix It?01 public class RandomSet {02     public static void main(String[] args) {03         Set s = new HashSet...
The Moral• Use one Random instance for each  sequence• In most programs, one is all you  need• In multithreaded programs, ...
12.“Making a Hash of It”01 public class Name {02     private String first, last;03     public Name(String first, String la...
What Does It Print?(a) true(b) false(c) It varies
What Does It Print?(a) true(b) false(c) It variesName overrides hashCode but notequals.The two Name instances are unequal.
Another Look01 public class Name {02     private String first, last;03     public Name(String first, String last) {04     ...
How Do You Fix It?•   Replace the overloaded equals method    with an overriding equals method    01 public boolean equals...
The Moral• If you want to override a method: ─ Make sure signatures match ─ The compiler doesn’t check for you ─ Do copy-a...
13. “Ping Pong”01 class PingPong {02     public static synchronized void main(String[] a)   {03         Thread t = new Thr...
What Does It Print?(a) PingPong(b) PongPing(c) It varies
What Does It Print?(a) PingPong(b) PongPing(c) It variesNot a multithreaded program!
Another Look01 class PingPong {02     public static synchronized void main(String[] a) {03         Thread t = new Thread()...
How Do You Fix It?01 class PingPong {02   public static synchronized void main(String[] a) {03     Thread t = new Thread()...
The Moral• Invoke Thread.start, not  Thread.run ─ Common error ─ Can be very difficult to diagnose• (Thread shouldn’t impl...
14. “Shifty”01 public class Shifty {02     public static void main(String[] args) {03         int distance = 0;04         ...
What Does It Print?(a) 31(b) 32(c) 33(d) None of the above
What Does It Print?(a) 31(b) 32(c) 33(d) None of the above: infinite loop!Shift distances are calculated mod 32.
Another Look01 public class Shifty {02     public static void main(String[] args) {03         int distance = 0;04         ...
How Do You Fix It?01 public class Shifty {02    public static void main(String[] args) {03       int distance = 0;04      ...
The Moral• Shift distances are computed mod  32 (or 64)• It’s impossible to shift out an entire  int  (or long) using any ...
15. “Line Printer” 01 public class LinePrinter { 02     public static void main(String[] args) { 03        // Note: u000A ...
What Does It Print?(a) Two blank lines(b) 10(c) Won’t compile(d) It varies
What Does It Print?(a) Two blank lines(b) 10(c) Won’t compile: Syntax error!(d) It variesThe Unicode escape in the comment...
Another Look are processed before comments! 01 // Unicode escapes  02 public class LinePrinter {  03     public static voi...
How Do You Fix It? 01 public class LinePrinter { 02    public static void main(String[] args) { 03       // Escape sequenc...
The Moral• Unicode escapes are dangerous  ─Equivalent to the character they   represent!• Use escape sequences instead, if...
16. “All Strung Out”01   public class Puzzling {02       public static void main(String[] args) {03           String s = n...
What Does It Print?(a) Won’t compile(b) blah(c) Throws an exception at runtime(d) Other
What Does It Print?(a) Won’t compile(b) blah(c) Throws an exception at runtime(d) OtherNoSuchMethodError is thrownbecause ...
Another Look01   public class Puzzling {02       public static void main(String[] args) {03           String s = new Strin...
How Do You Fix It?01   public class Puzzling {02       public static void main(String[] args) {03           MyString s = n...
The Moral• Avoid name reuse in all its guises ─ hiding, shadowing, overloading• Don’t even think about reusing  platform  ...
17. “Reflection Infection”01 import java.lang.reflect.*;0203 public class Reflector {04     public static void main(String...
What Does It Print?(a) Won’t compile(b) true(c) Throws exception(d) None of the above
What Does It Print?(a) Won’t compile(b) true(c) Throws exception -  IllegalAccessError(d) None of the aboveAttempts to inv...
Another Look01 import java.lang.reflect.*;0203 public class Reflector {04     public static void main(String[] args) throw...
How Do You Fix It?01 import java.lang.reflect.*;0203 public class Reflector {04     public static void main(String[] args)...
The Moral• Reflection has its own access rules• Avoid reflection when possible• If you must use reflection ─ Instantiate u...
18. “String Cheese”01 public class StringCheese {02     public static void main(String args[]) {03         byte b[] = new ...
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...
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 th...
Another Look01 public class StringCheese {02     public static void main(String args[]) {03         byte b[] = new byte[25...
How Do You Fix It?If you want it to print numbers from   0-255   in order:01 public class StringCheese {02     public stat...
The Moral• Converting bytes to chars uses a  charset• If you don’t specify one, you get  default ─ Depends on OS and local...
19. “Elvis Lives!”01 public class Elvis {02     public static final Elvis INSTANCE = new Elvis();03     private final int ...
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 th...
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 th...
Another Look01 // Static initialization proceeds top to bottom.02 public class Elvis {03     // Recursive initialization r...
How Do You Fix It?01 public class Elvis {02     private final int beltSize;0304     private static final int CURRENT_YEAR ...
The Moral• Watch out for circularities in static  initialization   One or more classes may be involved   Circularities are...
20. “What’s the Point?”01 class Point {02     protected final int x, y;03     private final String name; // Cached at cons...
What Does It Print?(a) [4,2]:purple(b) [4,2]:null(c) Throws exception at runtime(d) None of the above
What Does It Print?(a) [4,2]:purple(b) [4,2]:null(c) Throws exception at runtime(d) None of the aboveSuperclass constructo...
Another Look01 class Point {02     protected final int x, y;03     private final String name;04     protected String makeN...
How Do You Fix It?01 class Point {02     protected final int x, y;03     private String name; // Lazily initialized (cache...
The Moral• Never call overridable methods  from constructors, directly or  indirectly• Also applies to “pseudo-constructor...
21. “Long Division”01 public class LongDivision {02    private static final long MILLIS_PER_DAY03        = 24 * 60 * 60 * ...
What Does It Print?(a) 5(b) 1000(c) 5000(d) Throws an exception
What Does It Print?(a) 5(b) 1000(c) 5000(d) Throws an exceptionComputation does overflow
Another Look01 public class LongDivision {02     private static final long MILLIS_PER_DAY03         = 24 * 60 * 60 * 1000;...
How Do You Fix It?01 public class LongDivision {02     private static final long MILLIS_PER_DAY03         = 24L * 60 * 60 ...
The Moral• When working with large numbers watch out  for overflow—it’s a silent killer• Just because variable is big enou...
22. “No Pain, No Gain”01 public class Rhymes {02    private static Random rnd = new Random();03    public static void main...
What Does It Print?(a) Pain, Gain, or Main (varies at  random)(b) Pain or Main (varies at random)(c) Main (always)(d) None...
What Does It Print?(a) Pain, Gain, or Main (varies at  random)(b) Pain or Main (varies at random)(c) Main (always)(d) None...
Another Look01 public class Rhymes {02    private static Random rnd = new Random();03    public static void main(String[] ...
How Do You Fix It?01 public class Rhymes {02     private static Random rnd = new Random();03     public static void main(S...
The Moral• Use common idioms  ─ If you must stray, consult the documentation• Chars are not strings; they’re more like int...
23. “The Name Game”01 public class NameGame {02     public static void main(String args[]) {03         Map m = new Identit...
What Does It Print?(a) 0(b) 1(c) 2(d) It varies
What Does It Print?(a) 0(b) 1(c) 2(d) It variesWe’re using an IdentityHashMap, but   stringliterals are interned (they can...
Another Look01 public class NameGame {02     public static void main(String args[]) {03         Map m = new IdentityHashMa...
How Do You Fix It?01 public class NameGame {02     public static void main(String args[]) {03         Map m = new HashMap(...
The Moral• IdentityHashMap not a general-purpose Map ─ Don’t use it unless you know it’s what   you want ─ Uses identity i...
24. “More of The Same”01 public class Names {02     private Map m = new HashMap();03     public void Names() {04         m...
What Does It Print?(a) 0(b) 1(c) 2(d) It varies
What Does It Print?(a) 0(b) 1(c) 2(d) It variesNo programmer-defined constructor
Another Look01 public class Names {02      private Map m = new HashMap();03      public void Names() {    // Not a constru...
How Do You Fix It?01 public class Names {02     private Map m = new HashMap();03     public Names() {    // No return type...
The Moral• It is possible for a method to have the same name as a constructor• Don’t ever do it• Obey naming conventions  ...
25. “Shades of Gray”01   public class Gray {02       public static void main(String[] args){03           System.out.printl...
What Does It Print?(a) Black(b) White(c) Won’t compile(d) None of the above
What Does It Print?(a) Black(b) White(c) Won’t compile(d) None of the aboveField Y obscures member class Y (JLS  6.3.2)The...
Another Look01   public class Gray {02       public static void main(String[] args){03           System.out.println(X.Y.Z)...
How Do You Fix It?01   public class Gray {02       public static void main(String[] args){03           System.out.println(...
The Moral• Obey naming conventions  ─ field, method(), Class, CONSTANT  ─ Single-letter uppercase names reserved     for t...
26. “It’s Elementary”01 public class Elementary {02     public static void main(String[] args) {03         System.out.prin...
What Does It Print?(a)   -22430(b)    59753(c)    10864(d)   108642
What Does It Print?(a)   -22430(b)    59753(c)    10864(d)   108642Program doesn’t say what you think it  does!
Another Look01 public class Elementary {02     public static void main(String[] args) {03           System.out.println(543...
How Do You Fix It?We won’t insult your intelligence
The Moral• Always use uppercase el (L) for long literals  ─ Lowercase el makes the code    unreadable  ─ 5432L is clearly ...
27. “Down For The Count”01 public class Count {02     public static void main(String[] args) {03         final int START =...
What Does It Print?(a) 0(b) 50(c) 51(d) None of the above
What Does It Print?(a) 0(b) 50(c) 51(d) None of the aboveThe termination test misbehaves dueto floating point “granularity.”
Another Look01 public class Count {02     public static void main(String[] args) {03         final int START = 2000000000;...
How Do You Fix It?01 public class Count {02    public static void main(String[] args) {03        final int START = 2000000...
The Moral• Don’t use floating point for loop  indices• Not every int can be expressed as a  float• Not every long can be e...
28. “Classy Fire”01 public class Classifier {02     public static void main(String[] args) {03         System.out.println(...
What Does It Print?(a) LETTER OPERATOR NUMERAL(b) LETTER UNKNOWN NUMERAL(c) Throws an exception(d) None of the above
What Does It Print?(a) LETTER OPERATOR NUMERAL(b) LETTER UNKNOWN NUMERAL(c) Throws an exception(d) None of the aboveAs for...
Another Look01 public class Classifier {02     public static void main(String[] args) {03         System.out.println(04   ...
How Do You Fix It?01   public class Classifier {02       public static void main(String[] args) {03           System.out.p...
The Moral• You cannot reliably block-comment out code  ─Comments do not nest• Use “if (false)” idiom or “//” comments
29. “The Joy of Hex”01 public class JoyOfHex {02      public static void main(String[] args) {03          System.out.print...
What Does It Print?(a) cafebabe(b) 1cafebabe(c) ffffffffcafebabe(d) Throws an exception
What Does It Print?(a) cafebabe(b) 1cafebabe(c) ffffffffcafebabe(d) Throws an exception0xcafebabe is a negative number
Another Look01 public class JoyOfHex {02      public static void main(String[] args) {03          System.out.println(04   ...
How Do You Fix It?01 public class JoyOfHex {02     public static void main(String[] args) {03         System.out.println(0...
The Moral• Decimal literals are all positive; not  so for hex > Negative decimal constants have minus   sign > Hex literal...
30. “Animal Farm”01 public class AnimalFarm {02     public static void main(String[] args) {03         final String pig = ...
What Does It Print?(a) Animals are equal: true(b) Animals are equal: false(c) It varies(d) None of the above
What Does It Print?(a) Animals are equal: true(b) Animals are equal: false(c) It varies(d) None of the above: falseThe + o...
Another Look01 public class AnimalFarm {02     public static void main(String[] args) {03         final String pig = "leng...
How Do You Fix It?01 public class AnimalFarm {02     public static void main(String[] args) {03         final String pig =...
The Moral• Parenthesize when using string  concatenation • Spacing can be deceptive; parentheses   never lie• Don’t depend...
31. “A Tricky Assignment”01 public class Assignment {02     public static void main(String[] a) throws Exception {03      ...
What Does It Print?(a) 0(b) 3(c) 14(d) None of the above
What Does It Print?(a) 0(b) 3(c) 14(d) None of the aboveOperands are evaluated left to right.Postfix increment returns old...
Another Look01 public class Assignment {02     public static void main(String[] a) throws Exception {03         int tricky...
Another Look01 public class Assignment {02     public static void main(String[] a) throws Exception {03         int tricky...
Another Look05       tricky += tricky++;        (0)                    (tricky == 0)
Another Look05       tricky += tricky++;        (0)                    (tricky == 0)
Another Look05       tricky += tricky++;         0         0           (tricky == 1)
Another Look05       tricky += tricky++;         0         0           (tricky == 1)
Another Look05       tricky += tricky++;         0         0           (tricky == 0)
Another Look01 public class Assignment {02     public static void main(String[] a) throws Exception {03         int tricky...
How Do You Fix It?01 public class Assignment {02     public static void main(String[] a) throws Exception {03         int ...
The Moral• Don’t depend on details of expression  evaluation• Don’t assign to a variable twice in  one expression• Postfix...
32. “Thrown for a Loop”01 public class Loop {02      public static void main(String[] args) {03          int[][] tests = {...
What Does It Print?(a) 0(b) 1(c) 2(d) None of the above
What Does It Print?(a) 0(b) 1(c) 2(d) None of the aboveNot only is the program repulsive, but it has abug
Another Look01 public class Loop {02      public static void main(String[] args) {03          int[][] tests = { { 6, 5, 4,...
How Do You Fix It?01 public class Loop {02     public static void main(String[] args) {03         int[][] tests = { { 6, 5...
The Moral• Use exceptions only for exceptional  conditions  > Never use exceptions for normal   control flow• Beware the l...
33. “Sum Fun”01 class Cache {02     static { initIfNecessary(); }03     private static int sum;04     public static int ge...
What Does It Print?(a) 4950(b) 5050(c) 9900(d) None of the above
What Does It Print?(a) 4950(b) 5050(c) 9900(d) None of the aboveLazy initialization + eager initialization = amess
Another Look01 class Cache {02     static { initIfNecessary(); }03     private static int sum;04     public static int get...
Another Look01 class Cache {02     static { initIfNecessary(); }03     private static int sum;04     public static int get...
How Do You Fix It?01 class Cache {02     private static final int SUM = computeSum();0304     private static int computeSu...
The Moral• Use eager or lazy initialization, not  both  > Prefer eager initialization to lazy• Think about class initializ...
34. “The Mod Squad”01 public class Mod {02     public static void main(String[] args) {03         final int MODULUS = 3;04...
What Does It Print?(a) 1431655765 14316557651431655765(b) 1431655765 14316557661431655765(c) Throws an exception(d) None o...
What Does It Print?(a) 1431655765 14316557651431655765(b) 1431655765 14316557661431655765(c) Throws an exception: array ou...
Another Look01 public class Mod {02     public static void main(String[] args) {03         final int MODULUS = 3;04       ...
How Do You Fix It?Replace:   histogram[Math.abs(i) % MODULUS]++;With:   histogram[mod(i, MODULUS)]++;   private static int...
The Moral• Math.abs can return a negative value  • Two’s-complement integers are    asymmetric  • int arithmetic overflows...
35. “Package Deal”01 package click;02 public class CodeTalk {03     public void doIt() { printMessage(); }04     void prin...
What Does It Print?(a) Click(b) Hack(c) Won’t compile(d) None of the above
What Does It Print?(a) Click(b) Hack(c) Won’t compile(d) None of the aboveThere is no overriding in this program
Another Look01 package click;02 public class CodeTalk {03     public void doIt() { printMessage(); }04     void printMessa...
How Do You Fix It?• If you want overriding • Make printMessage public or protected • Use @Override to ensure that you got ...
The Moral• Package-private methods can’t be  overridden by methods outside their  package• If you can’t see it, you can’t ...
36. “Lazy Initialization” 01 public class Lazy { 02     private static boolean initialized = false; 03     static { 04    ...
What Does It Print?(a) true(b) false(c) It varies(d) None of the above
What Does It Print?(a) true(b) false(c) It varies(d) None of the above: it deadlocksIntuition: You wouldn’t believe us if ...
Another Look01 public class Lazy {02     private static boolean initialized = false;03     static {04         Thread t = n...
How Do You Fix It?• Don’t use background threads in class  initialization   > If it hurts when you go like that, don’t go ...
The Moral• Never use background threads in class  initialization• Keep class initialization simple• Don’t code like my bro...
37. “Odd Behavior”01 public class OddBehavior {02     public static void main(String[] args) {03         List<Integer> lis...
What Does It Print?01 public class OddBehavior {02     public static void main(String[] args) {03         List<Integer> li...
What Does It Print?(a) true(b) false(c) Throws exception(d) None of the above: Nothing—Infinite loopConditional OR operato...
Another Lookpublic class OddBehavior {    public static void main(String[] args) {        List<Integer> list = Arrays.asLi...
You Could Fix it Like This….public class OddBehavior {    public static void main(String[] args) {        List<Integer> li...
…But This Is Even Betterpublic class OddBehavior {    public static void main(String[] args) {        List<Integer> list =...
The Moral• Use for-each wherever possible  > Nicer and safer than explicit iterator or   index usage• If you must use an i...
38. “Set List”public class SetList {    public static void main(String[] args) {        Set<Integer> set = new LinkedHashS...
(a) [-3, -2, -1] [-3, -2, -1]What Does It Print?                    (b) [-3, -2, -1] [-2, 0, 2]                           ...
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 aboveAutobo...
Another Lookpublic class SetList {    public static void main(String[] args) {        Set<Integer> set = new LinkedHashSet...
How Do You Fix It?public class SetList {    public static void main(String[] args) {        Set<Integer> set = new LinkedH...
The Moral• Avoid ambiguous overloadings• Harder to avoid in release 5.0 > Autoboxing, varargs, generics• Design new APIs w...
39. “Powers of Ten”public enum PowerOfTen {    ONE(1), TEN(10),    HUNDRED(100) {        @Override public String toString(...
What Does It Print?                      (a) ONE TEN HUNDRED                                         (b) one ten hundredpu...
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 va...
Another Lookpublic enum PowerOfTen {    ONE(1), TEN(10),    HUNDRED(100) { // Creates static anonymous class        @Overr...
How Do You Fix It?public enum PowerOfTen {    ONE(1), TEN(10),    HUNDRED(100) {        @Override public String toString()...
The Moral• Nest-mates can use each others’ private  members• But private members are never inherited• Constant-specific en...
40. “Testy Behavior”import java.lang.reflect.*;@interface Test { }public class Testy {   @Test public static void test() {...
What Does It Print?                             (a) Pass Fail                                                (b) Pass Pass...
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 ...
Another Lookimport java.lang.reflect.*;@interface Test { } // By default, annotations are discarded at runtimepublic class...
How Do You Fix It?import java.lang.reflect.*;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME) @interface ...
The Moral• By default, annotations are discarded  at runtime  > If you need annotations at runtime, use   @Retention(Reten...
41. “What the Bleep?”public class Bleep {     String name = "Bleep";     void setName(String name) {         this.name = n...
What Does It Print?                            (a) Bleeppublic class Bleep {                            (b) Blat     Strin...
What Does It Print?(a) Bleep(b) Blat(c) It varies(d) None of the aboveBleep.setName isn’t getting called
Another Lookpublic class Bleep {     String name = "Bleep";     void setName(String name) { // Does this look familiar?   ...
How Do You Fix It?public class Bleep {     String name = "Bleep";     void setName(String name) {         this.name = name...
The Moral• Don’t extend Thread  > Use new Thread(Runnable) instead• Often the Executor Framework is  better still  > Much ...
42. “Beyond Compare”public class BeyondCompare {   public static void main(String[] args) {       Object o = new Integer(3...
What Does It Print?public class BeyondCompare {   public static void main(String[] args) {       Object o = new Integer(3)...
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(Doub...
Another Lookpublic class BeyondCompare {   public static void main(String[] args) {       Object o = new Integer(3);      ...
How Do You Fix It?// Preserves 1.4 semanticspublic class BeyondCompare {   public static void main(String[] args) {       ...
The Moral• Binary compatibility is preserved at all costs• Source compatibility broken for good cause  (rare)  • Comparabl...
43. “Fib O’Nacci”public class Fibonacci {    private static final int LENGTH = 7;    public static void main(String[] args...
What Does It Print?public class Fibonacci {    private static final int LENGTH = 7;    public static void main(String[] ar...
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 ...
Another Lookpublic class Fibonacci {    private static final int LENGTH = 7;    public static void main(String[] args) {  ...
How Do You Fix It?public class Fibonacci {    private static final int LENGTH = 7;    public static void main(String[] arg...
The Moral• Use varargs sparingly in your APIs  > It can hide errors and cause confusion  > This program wouldnt compile un...
44. “Parsing Is Such Sweet Sorrow”public class Parsing {   /**     * Returns Integer corresponding to s, or null if s is n...
(a) -1 null 1What Does It Print?                          (b) -1 0 1                                             (c) Throw...
What Does It Print?(a) -1 null 1(b) -1 0 1(c) Throws exception:NullPointerException(d) None of the aboveProgram attempts t...
Another Lookpublic class Parsing {   /**     * Returns Integer corresponding to s, or null if s is null.     * @throws Num...
How Do You Fix It?public class Parsing {   /**     * Returns Integer corresponding to s, or null if s is null.     * @thro...
The Moral• Mixed-type computations are  confusing• Especially true for ?: expressions• Avoid null where possible• Auto-unb...
Resources and Summary
Resources• Send more puzzles  –   puzzlers@javapuzzles.com
Conclusion•   Java platform is simple and elegant    –   But it has a few sharp corners — avoid        them!•   Keep progr...
Upcoming SlideShare
Loading in …5
×

Java puzzle-1195101951317606-3

2,671 views

Published on

1 Comment
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total views
2,671
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
105
Comments
1
Likes
0
Embeds 0
No embeds

No notes for slide

Java puzzle-1195101951317606-3

  1. 1. Java PuzzlesFilipp Shubin
  2. 2. Overall Presentation Goal Learn some of the quirks of programming in general and the Java language in particular; Have fun!
  3. 3. 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
  4. 4. 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 }
  5. 5. What Does It Print?(a) woof(b) woof woof(c) It varies
  6. 6. What Does It Print?(a) woof(b) woof woof(c) It variesNo dynamic dispatch on static methods
  7. 7. 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 }
  8. 8. How Do You Fix It?• Remove static from the bark method
  9. 9. The Moral• Static methods cant be overridden – They can only be hidden• Don’t hide static methods• Never invoke static methods on instances – Not Instance.staticMethod() – But Class.staticMethod()
  10. 10. 2. “Whats 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 }
  11. 11. What Does It Print?(a) True(b) False(c) It varies
  12. 12. What Does It Print?(a) True(b) False(c) It variesDonald is in the set, but the set can’t find him.The Name class violates the hashCode contract.
  13. 13. 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 }
  14. 14. How Do You Fix It?Add a hashCode method:public int hashCode() { return 31 * first.hashCode() + last.hashCode();}
  15. 15. The Moral• If you override equals, override hashCode• Obey general contracts when overriding• See Effective Java, Chapter 3
  16. 16. 3. “Indecision”01 class Indecisive {02 public static void main(String[] args) {03 System.out.println(waffle());04 }0506 static boolean waffle() {07 try {08 return true;09 } finally {10 return false;11 }12 }13 }
  17. 17. What Does It Print?(a) true(b) false(c) None of the above
  18. 18. What Does It Print?(a) true(b) false(c) None of the aboveThe finally is processed after the try.
  19. 19. Another Look01 class Indecisive {02 public static void main(String[] args) {03 System.out.println(waffle());04 }0506 static boolean waffle() {07 try {08 return true;09 } finally {10 return false;11 }12 }13 }
  20. 20. The Moral• Avoid abrupt completion of finally blocks – Wrap unpredictable actions with nested trys – Dont return or throw exceptions
  21. 21. 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 }
  22. 22. What Does It Print?(a) [-2000000000, 0, 2000000000](b) [2000000000, 0, -2000000000](c) [-2000000000, 2000000000, 0](d) It varies
  23. 23. 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
  24. 24. 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 }
  25. 25. 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 }
  26. 26. The Moral• ints arent 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
  27. 27. 5. “Youre 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 }
  28. 28. What Does It Print?(a) HaHa(b) Ha(c) None of the above
  29. 29. 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.
  30. 30. The Moral• Use string concatenation (+) with care – At least one operand must be a String – If it isnt, cast or convert" + H + a);• Be glad operator overloading isnt supported
  31. 31. 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 }
  32. 32. What Does It Print?(a) Object(b) double array(c) None of the above
  33. 33. What Does It Print?(a) Object(b) double array(c) None of the above When multiple overloadings apply, the most specific wins
  34. 34. 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 }
  35. 35. How Do You Fix It?• There may be no problem• If there is, use a cast: New Confusing((Object)null);
  36. 36. 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
  37. 37. 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 }
  38. 38. What Does It Print?(a) (nothing)(b) Byte me!(c) Byte me! Byte me!
  39. 39. 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
  40. 40. 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 }1011 // But (byte)0x90 == -112
  41. 41. How Do You Fix It?• Cast int to byte if (b == (byte)0x90) System.out.println("Byte me!");• Or convert byte to int, suppressing sign extension with mask if ((b & 0xff) == 0x90) System.out.println("Byte me!");
  42. 42. The Moral• Bytes arent ints• Be careful when mixing primitive types• Compare like-typed expressions – Cast or convert one operand as necessary
  43. 43. 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 }
  44. 44. What Does It Print?(a) 0.9(b) 0.90(c) It varies(d) None of the above
  45. 45. What Does It Print?(a) 0.9(b) 0.90(c) It varies(d) None of the above: 0.89999999999999 Decimal Values cant be represented exactly by float or double
  46. 46. 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 }
  47. 47. The Moral• Avoid float and double where exact answers are required• Use BigDecimal, int, or long instead
  48. 48. 9. “A Private Matter”01 class Base {02 public String name = "Base";03 }0405 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 }
  49. 49. What Does It Print?(a) Derived(b) Base(c) Compiler error in class Derived: Cant assign weaker access to name(d) None of the above
  50. 50. What Does it Print?(a) Derived(b) Base(c) Compiler error in class Derived: Cant assign weaker access to name(d) None of the above: Compiler error in class PrivateMatter: Cant access name Private method cant overrides public, but private field can hide public
  51. 51. Another Look01 class Base {02 public String name = "Base";03 }0405 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 }
  52. 52. How Do You Fix It?01 class Base {02 public String getName() { return "Base"; }03 }0405 class Derived extends Base {06 public String getName() { return "Derived"; }07 }0809 public class PrivateMatter {10 public static void main(String[] args) {11 System.out.println(new Derived().getName());12 }13 }
  53. 53. The Moral• Avoid hiding – Violates subsumption• Avoid public fields – Use accessor methods instead
  54. 54. 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 }
  55. 55. What Does It Print?(a) 100(b) 101(c) (nothing)
  56. 56. What Does It Print?(a) 100(b) 101(c) (nothing)The loop test is broken - infinite loop!
  57. 57. 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 }
  58. 58. How Do You Fix It?• Change loop variable from int to long for (long i = start; i <= end; i++) count++;
  59. 59. The Moral• ints arent integers!• Think about overflow• Uselarger type if necessary
  60. 60. 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 }
  61. 61. 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
  62. 62. 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 aboveA new random number generator iscreated each iteration and the seedchanges rarely if at all.
  63. 63. 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 }
  64. 64. 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();1011 private static Integer randomInteger() {12 return new Integer(rnd.nextInt());13 }14 }
  65. 65. 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
  66. 66. 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 }
  67. 67. What Does It Print?(a) true(b) false(c) It varies
  68. 68. What Does It Print?(a) true(b) false(c) It variesName overrides hashCode but notequals.The two Name instances are unequal.
  69. 69. 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 }
  70. 70. 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 }
  71. 71. 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!
  72. 72. 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 };0809 t.run();10 System.out.print("Ping");11 }1213 static synchronized void pong() {14 System.out.print("Pong");15 }16 }
  73. 73. What Does It Print?(a) PingPong(b) PongPing(c) It varies
  74. 74. What Does It Print?(a) PingPong(b) PongPing(c) It variesNot a multithreaded program!
  75. 75. 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 };0809 t.run(); // Common typo!10 System.out.print("Ping");11 }1213 static synchronized void pong() {14 System.out.print("Pong");15 }16 }
  76. 76. 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 }
  77. 77. The Moral• Invoke Thread.start, not Thread.run ─ Common error ─ Can be very difficult to diagnose• (Thread shouldn’t implement Runnable)
  78. 78. 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 }
  79. 79. What Does It Print?(a) 31(b) 32(c) 33(d) None of the above
  80. 80. What Does It Print?(a) 31(b) 32(c) 33(d) None of the above: infinite loop!Shift distances are calculated mod 32.
  81. 81. 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 }0910 // (-1 << 32) == -1
  82. 82. 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 }
  83. 83. 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
  84. 84. 15. “Line Printer” 01 public class LinePrinter { 02 public static void main(String[] args) { 03 // Note: u000A is Unicode representation for newline 04 char c = 0x000A; 05 System.out.println(c); 06 } 07 }
  85. 85. What Does It Print?(a) Two blank lines(b) 10(c) Won’t compile(d) It varies
  86. 86. What Does It Print?(a) Two blank lines(b) 10(c) Won’t compile: Syntax error!(d) It variesThe Unicode escape in the commentbreaksit in two. The second half is garbage.
  87. 87. Another Look are processed before comments! 01 // Unicode escapes 02 public class LinePrinter { 03 public static void main(String[] args) { 04 // Note: u000A is unicode representation for newline 05 char c = 0x000A; 06 System.out.println(c); 07 } 08 } 01 // This is what the parser sees 02 public class LinePrinter { 03 public static void main(String[] args) { 04 // Note: 05 is Unicode representation for newline 06 char c = 0x000A; 07 System.out.println(c); 08 } 09 }
  88. 88. How Do You Fix It? 01 public class LinePrinter { 02 public static void main(String[] args) { 03 // Escape sequences (like n) are fine in comments 04 char c = n; 05 System.out.println(c); 06 } 07 }
  89. 89. 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
  90. 90. 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 }
  91. 91. What Does It Print?(a) Won’t compile(b) blah(c) Throws an exception at runtime(d) Other
  92. 92. What Does It Print?(a) Won’t compile(b) blah(c) Throws an exception at runtime(d) OtherNoSuchMethodError is thrownbecause the Puzzling class is missinga main method.
  93. 93. 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;0910 public String(java.lang.String s) {11 this.s = s;12 }13 public java.lang.String toString() {14 return s;15 }16 }
  94. 94. 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;0910 public MyString(String s) {11 this.s = s;12 }13 public String toString() {14 return s;15 }16 }
  95. 95. The Moral• Avoid name reuse in all its guises ─ hiding, shadowing, overloading• Don’t even think about reusing platform class names!
  96. 96. 17. “Reflection Infection”01 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 }
  97. 97. What Does It Print?(a) Won’t compile(b) true(c) Throws exception(d) None of the above
  98. 98. What Does It Print?(a) Won’t compile(b) true(c) Throws exception - IllegalAccessError(d) None of the aboveAttempts to invoke a method on a private class
  99. 99. 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 }
  100. 100. How Do You Fix It?01 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 Iterator.class.getMethod("hasNext",10 new Class[0]);11 System.out.println(m.invoke(i, new Object[0]));12 }13 }
  101. 101. 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
  102. 102. 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 }
  103. 103. 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
  104. 104. 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 aboveThe 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
  105. 105. 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.]
  106. 106. 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.
  107. 107. 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
  108. 108. 19. “Elvis Lives!”01 public class Elvis {02 public static final Elvis INSTANCE = new Elvis();03 private final int beltSize;0405 private static final int CURRENT_YEAR =06 Calendar.getInstance().get(Calendar.YEAR);0708 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 }
  109. 109. 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.
  110. 110. 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 isinitialized, due to circularity in class initialization.
  111. 111. 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;0607 private static final int CURRENT_YEAR =08 Calendar.getInstance().get(Calendar.YEAR);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 }
  112. 112. How Do You Fix It?01 public class Elvis {02 private final int beltSize;0304 private static final int CURRENT_YEAR =05 Calendar.getInstance().get(Calendar.YEAR);0607 // 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 }
  113. 113. 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)
  114. 114. 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 }
  115. 115. What Does It Print?(a) [4,2]:purple(b) [4,2]:null(c) Throws exception at runtime(d) None of the above
  116. 116. What Does It Print?(a) [4,2]:purple(b) [4,2]:null(c) Throws exception at runtime(d) None of the aboveSuperclass constructor runs a subclass methodbefore the subclass instance is initialized.
  117. 117. 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 }
  118. 118. 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 }1213 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 }
  119. 119. The Moral• Never call overridable methods from constructors, directly or indirectly• Also applies to “pseudo-constructors” ─ readObject() ─ clone()• See Effective Java, Item 15
  120. 120. 21. “Long Division”01 public class LongDivision {02 private static final long MILLIS_PER_DAY03 = 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 }
  121. 121. What Does It Print?(a) 5(b) 1000(c) 5000(d) Throws an exception
  122. 122. What Does It Print?(a) 5(b) 1000(c) 5000(d) Throws an exceptionComputation does overflow
  123. 123. Another Look01 public class LongDivision {02 private static final long MILLIS_PER_DAY03 = 24 * 60 * 60 * 1000;04 private static final long MICROS_PER_DAY05 = 24 * 60 * 60 * 1000 * 1000; // >> Integer.MAX_VALUE0607 public static void main(String[] args) {08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);09 }10 }
  124. 124. How Do You Fix It?01 public class LongDivision {02 private static final long MILLIS_PER_DAY03 = 24L * 60 * 60 * 1000;04 private static final long MICROS_PER_DAY05 = 24L * 60 * 60 * 1000 * 1000;0607 public static void main(String[] args) {08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);09 }10 }
  125. 125. 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
  126. 126. 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)
  127. 127. 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
  128. 128. 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.
  129. 129. 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 }
  130. 130. 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 }
  131. 131. 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
  132. 132. 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 }
  133. 133. What Does It Print?(a) 0(b) 1(c) 2(d) It varies
  134. 134. What Does It Print?(a) 0(b) 1(c) 2(d) It variesWe’re using an IdentityHashMap, but stringliterals are interned (they cancel each other out)
  135. 135. 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 }
  136. 136. 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 }
  137. 137. 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)
  138. 138. 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 }0708 public int size() { return m.size(); }0910 public static void main(String args[]) {11 Names names = new Names();12 System.out.println(names.size());13 }14 }
  139. 139. What Does It Print?(a) 0(b) 1(c) 2(d) It varies
  140. 140. What Does It Print?(a) 0(b) 1(c) 2(d) It variesNo programmer-defined constructor
  141. 141. 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(); }0910 public static void main(String args[]) {11 Names names = new Names(); // Invokes default!12 System.out.println(names.size());13 }14 }
  142. 142. 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 }0708 public int size() { return m.size(); }0910 public static void main(String args[]) {11 Names names = new Names();12 System.out.println(names.size());13 }14 }
  143. 143. 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
  144. 144. 25. “Shades of Gray”01 public class Gray {02 public static void main(String[] args){03 System.out.println(X.Y.Z);04 }05 }0607 class X {08 static class Y {09 static String Z = "Black";10 }11 static C Y = new C();12 }1314 class C {15 String Z = "White";16 }Thanks to Prof. Dominik Gruntz, Fachhochschule Aargau
  145. 145. What Does It Print?(a) Black(b) White(c) Won’t compile(d) None of the above
  146. 146. What Does It Print?(a) Black(b) White(c) Won’t compile(d) None of the aboveField Y obscures member class Y (JLS 6.3.2)The rule: variable > type > package
  147. 147. Another Look01 public class Gray {02 public static void main(String[] args){03 System.out.println(X.Y.Z);04 }05 }0607 class X {08 static class Y {09 static String Z = "Black";10 }11 static C Y = new C();12 }1314 class C {15 String Z = "White";16 }The rule: variable > type > package
  148. 148. 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 }0607 class Ex {08 static class Why {09 static String z = "Black";10 }11 static See y = new See();12 }1314 class See {15 String z = "White";16 }
  149. 149. 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
  150. 150. 26. “It’s Elementary”01 public class Elementary {02 public static void main(String[] args) {03 System.out.println(54321 + 5432l);04 }05 }
  151. 151. What Does It Print?(a) -22430(b) 59753(c) 10864(d) 108642
  152. 152. What Does It Print?(a) -22430(b) 59753(c) 10864(d) 108642Program doesn’t say what you think it does!
  153. 153. Another Look01 public class Elementary {02 public static void main(String[] args) {03 System.out.println(54321 + 5432l);04 }05 }1 - the numeral onel - the lowercase letter el
  154. 154. How Do You Fix It?We won’t insult your intelligence
  155. 155. 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();
  156. 156. 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 }
  157. 157. What Does It Print?(a) 0(b) 50(c) 51(d) None of the above
  158. 158. What Does It Print?(a) 0(b) 50(c) 51(d) None of the aboveThe termination test misbehaves dueto floating point “granularity.”
  159. 159. 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)
  160. 160. 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 }
  161. 161. 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
  162. 162. 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 }
  163. 163. What Does It Print?(a) LETTER OPERATOR NUMERAL(b) LETTER UNKNOWN NUMERAL(c) Throws an exception(d) None of the above
  164. 164. What Does It Print?(a) LETTER OPERATOR NUMERAL(b) LETTER UNKNOWN NUMERAL(c) Throws an exception(d) None of the aboveAs for the intuition, you’ll see in amoment...
  165. 165. 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 }
  166. 166. 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 }
  167. 167. The Moral• You cannot reliably block-comment out code ─Comments do not nest• Use “if (false)” idiom or “//” comments
  168. 168. 29. “The Joy of Hex”01 public class JoyOfHex {02 public static void main(String[] args) {03 System.out.println(04 Long.toHexString(0x100000000L + 0xcafebabe));05 }06 }
  169. 169. What Does It Print?(a) cafebabe(b) 1cafebabe(c) ffffffffcafebabe(d) Throws an exception
  170. 170. What Does It Print?(a) cafebabe(b) 1cafebabe(c) ffffffffcafebabe(d) Throws an exception0xcafebabe is a negative number
  171. 171. Another Look01 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
  172. 172. How Do You Fix It?01 public class JoyOfHex {02 public static void main(String[] args) {03 System.out.println(04 Long.toHexString(0x100000000L + 0xcafebabeL));05 }06 }
  173. 173. 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
  174. 174. 30. “Animal Farm”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 }
  175. 175. What Does It Print?(a) Animals are equal: true(b) Animals are equal: false(c) It varies(d) None of the above
  176. 176. What Does It Print?(a) Animals are equal: true(b) Animals are equal: false(c) It varies(d) None of the above: falseThe + operator binds tighter than ==
  177. 177. Another Look01 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);
  178. 178. How Do You Fix It?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 }
  179. 179. 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
  180. 180. 31. “A Tricky Assignment”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 }
  181. 181. What Does It Print?(a) 0(b) 3(c) 14(d) None of the above
  182. 182. What Does It Print?(a) 0(b) 3(c) 14(d) None of the aboveOperands are evaluated left to right.Postfix increment returns old value.
  183. 183. Another Look01 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 }
  184. 184. Another Look01 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 }
  185. 185. Another Look05 tricky += tricky++; (0) (tricky == 0)
  186. 186. Another Look05 tricky += tricky++; (0) (tricky == 0)
  187. 187. Another Look05 tricky += tricky++; 0 0 (tricky == 1)
  188. 188. Another Look05 tricky += tricky++; 0 0 (tricky == 1)
  189. 189. Another Look05 tricky += tricky++; 0 0 (tricky == 0)
  190. 190. Another Look01 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 }
  191. 191. How Do You Fix It?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 }
  192. 192. 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)
  193. 193. 32. “Thrown for a Loop”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 }
  194. 194. What Does It Print?(a) 0(b) 1(c) 2(d) None of the above
  195. 195. What Does It Print?(a) 0(b) 1(c) 2(d) None of the aboveNot only is the program repulsive, but it has abug
  196. 196. Another Look01 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 }
  197. 197. How Do You Fix It?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 }1112 private static boolean thirdElementIsThree(int[] a) {13 return a.length >= 3 && a[2] == 3;14 }15 }
  198. 198. 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
  199. 199. 33. “Sum Fun”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 }
  200. 200. What Does It Print?(a) 4950(b) 5050(c) 9900(d) None of the above
  201. 201. What Does It Print?(a) 4950(b) 5050(c) 9900(d) None of the aboveLazy initialization + eager initialization = amess
  202. 202. Another Look01 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 }
  203. 203. Another Look01 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 }
  204. 204. How Do You Fix It?01 class Cache {02 private static final int SUM = computeSum();0304 private static int computeSum() {05 int result = 0;06 for (int i = 0; i < 100; i++)07 result += i;08 return result;09 }1011 public static int getSum() {12 return SUM;13 }1415 public static void main(String[] args) {16 System.out.println(getSum());17 }18 }
  205. 205. The Moral• Use eager or lazy initialization, not both > Prefer eager initialization to lazy• Think about class initialization• Avoid complex class initialization sequences
  206. 206. 34. “The Mod Squad”01 public class Mod {02 public static void main(String[] args) {03 final int MODULUS = 3;04 int[] histogram = new int[MODULUS];0506 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);1112 for (int j = 0; j < MODULUS; j++)13 System.out.print(histogram[j] + " ");14 }15 }
  207. 207. What Does It Print?(a) 1431655765 14316557651431655765(b) 1431655765 14316557661431655765(c) Throws an exception(d) None of the aboveHint: 232 / 3 = 1,431,655,765
  208. 208. What Does It Print?(a) 1431655765 14316557651431655765(b) 1431655765 14316557661431655765(c) Throws an exception: array out ofbounds(d) None of the aboveMath.abs doesn’t always return a nonnegative
  209. 209. Another Look01 public class Mod {02 public static void main(String[] args) {03 final int MODULUS = 3;04 int[] histogram = new int[MODULUS];0506 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);1112 for (int j = 0; j < MODULUS; j++)13 System.out.println(histogram[j] + " ");14 }15 }
  210. 210. How Do You Fix It?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; }
  211. 211. 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
  212. 212. 35. “Package Deal”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 }
  213. 213. What Does It Print?(a) Click(b) Hack(c) Won’t compile(d) None of the above
  214. 214. What Does It Print?(a) Click(b) Hack(c) Won’t compile(d) None of the aboveThere is no overriding in this program
  215. 215. Another Look01 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 }
  216. 216. How Do You Fix It?• If you want overriding • Make printMessage public or protected • Use @Override to ensure that you got overriding
  217. 217. 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
  218. 218. 36. “Lazy Initialization” 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 }
  219. 219. What Does It Print?(a) true(b) false(c) It varies(d) None of the above
  220. 220. What Does It Print?(a) true(b) false(c) It varies(d) None of the above: it deadlocksIntuition: You wouldn’t believe us if we toldyou.
  221. 221. Another Look01 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 }
  222. 222. 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!
  223. 223. The Moral• Never use background threads in class initialization• Keep class initialization simple• Don’t code like my brother
  224. 224. 37. “Odd Behavior”01 public class OddBehavior {02 public static void main(String[] args) {03 List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2);0405 boolean foundOdd = false;06 for (Iterator<Integer> it=list.iterator();it.hasNext(); )07 foundOdd = foundOdd || isOdd(it.next());0809 System.out.println(foundOdd);10 }1112 private static boolean isOdd(int i) {13 return (i & 1) != 0;14 }15 }
  225. 225. What Does It Print?01 public class OddBehavior {02 public static void main(String[] args) {03 List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2);0405 boolean foundOdd = false;06 for (Iterator<Integer> it=list.iterator(); it.hasNext(); )07 foundOdd = foundOdd || isOdd(it.next());0809 System.out.println(foundOdd);10 }1112 private static boolean isOdd(int i) {13 return (i & 1) != 0; (a) true14 }15 } (b) false (c) Throws exception (d) None of the above
  226. 226. What Does It Print?(a) true(b) false(c) Throws exception(d) None of the above: Nothing—Infinite loopConditional OR operator (||) short-circuits iterator
  227. 227. Another Lookpublic 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; }}
  228. 228. You Could Fix it Like This….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; }}
  229. 229. …But This Is Even Betterpublic 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; }}
  230. 230. 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
  231. 231. 38. “Set List”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); }}
  232. 232. (a) [-3, -2, -1] [-3, -2, -1]What Does It Print? (b) [-3, -2, -1] [-2, 0, 2] (c) Throws exceptionpublic class SetList { (d) None of the above 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); }}
  233. 233. 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 aboveAutoboxing + overloading = confusion
  234. 234. Another Lookpublic 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); }}
  235. 235. How Do You Fix It?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); }}
  236. 236. 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>
  237. 237. 39. “Powers of Ten”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); }}
  238. 238. What Does It Print? (a) ONE TEN HUNDRED (b) one ten hundredpublic enum PowerOfTen { (c) one ten 100 ONE(1), TEN(10), HUNDRED(100) { (d) None of the above @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); }}
  239. 239. 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
  240. 240. Another Lookpublic 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); }}
  241. 241. How Do You Fix It?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); }}
  242. 242. 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
  243. 243. 40. “Testy Behavior”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 "); } } } }}
  244. 244. What Does It Print? (a) Pass Fail (b) Pass Passimport java.lang.reflect.*; (c) It varies@interface Test { } (d) None of the abovepublic 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 "); } } } }}
  245. 245. 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, bothsubtle
  246. 246. Another Lookimport 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 "); } } } }}
  247. 247. How Do You Fix It?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 "); } } } }}
  248. 248. 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
  249. 249. 41. “What the Bleep?”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(); }}
  250. 250. What Does It Print? (a) Bleeppublic class Bleep { (b) Blat String name = "Bleep"; void setName(String name) { (c) It varies this.name = name; (d) None of the above } 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(); }}
  251. 251. What Does It Print?(a) Bleep(b) Blat(c) It varies(d) None of the aboveBleep.setName isn’t getting called
  252. 252. Another Lookpublic 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(); }}
  253. 253. How Do You Fix It?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(); }}
  254. 254. 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
  255. 255. 42. “Beyond Compare”public class BeyondCompare { public static void main(String[] args) { Object o = new Integer(3); System.out.println(new Double(3).compareTo(o) == 0); }}
  256. 256. What Does It Print?public class BeyondCompare { public static void main(String[] args) { Object o = new Integer(3); System.out.println(new Double(3).compareTo(o) == 0); }} (a) true (b) false (c) Throws exception (d) None of the above
  257. 257. 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
  258. 258. Another Lookpublic 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>
  259. 259. How Do You Fix It?// 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); }}
  260. 260. 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
  261. 261. 43. “Fib O’Nacci”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)); }}
  262. 262. What Does It Print?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)); }} (a) [1, 1, 2, 3, 5, 8, 13] (b) Throws exception (c) It varies (d) None of the above
  263. 263. 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 aboveArrays.asList only works on arrays ofobject refs
  264. 264. Another Lookpublic 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)); }}
  265. 265. How Do You Fix It?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)); }}
  266. 266. The Moral• Use varargs sparingly in your APIs > It can hide errors and cause confusion > This program wouldnt 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
  267. 267. 44. “Parsing Is Such Sweet Sorrow”public class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesnt 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")); }}
  268. 268. (a) -1 null 1What Does It Print? (b) -1 0 1 (c) Throws exceptionpublic class Parsing { /** (d) None of the above * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesnt 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")); }}
  269. 269. What Does It Print?(a) -1 null 1(b) -1 0 1(c) Throws exception:NullPointerException(d) None of the aboveProgram attempts to auto-unbox null
  270. 270. Another Lookpublic class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesnt 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")); }}
  271. 271. How Do You Fix It?public class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesnt 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")); }}
  272. 272. The Moral• Mixed-type computations are confusing• Especially true for ?: expressions• Avoid null where possible• Auto-unboxing and null are a dangerous mix
  273. 273. Resources and Summary
  274. 274. Resources• Send more puzzles – puzzlers@javapuzzles.com
  275. 275. 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 arent sure what a program does, it probably doesnt do what you want it to

×