SlideShare a Scribd company logo
1 of 275
Download to read offline
Java Puzzles




Filipp Shubin
Overall Presentation Goal


   Learn some of the quirks of
   programming in general and the
   Java language in particular;
   Have fun!
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
  –
1. “All I Get is Static”
01   class Dog {
02       public static void bark() {
03           System.out.print(quot;woof quot;);
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   }
What Does It Print?
(a) woof
(b) woof woof
(c) It varies
What Does It Print?
(a) woof
(b) woof woof
(c) It varies

No dynamic dispatch on static methods
Another Look
01   class Dog {
02       public static void bark() {
03           System.out.print(quot;woof quot;);
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   }
How Do You Fix It?
• Remove static from the bark
  method
The Moral
• Static methods can't be overridden
      They can only be hidden
  –

• Don’t hide static methods
• Never invoke static methods on
  instances
      Not Instance.staticMethod()
  –
      But Class.staticMethod()
  –
2. “What's in a Name?”
01 public class Name {
02     private String first, last;
03     public Name(String first, String last) {
04         this.first = first;
05         this.last = last;
06     }
07     public boolean equals(Object o) {
08         if (!(o instanceof Name)) return false;
09         Name n = (Name)o;
10         return n.first.equals(first) &&
11                             n.last.equals(last);
12     }
13     public static void main(String[] args) {
14         Set s = new HashSet();
15         s.add(new Name(quot;Donaldquot;, quot;Duckquot;));
16         System.out.println(
17           s.contains(new Name(quot;Donaldquot;, quot;Duckquot;)));
18     }
19 }
What Does It Print?
(a) True
(b) False
(c) It varies
What Does It Print?
(a) True
(b) False
(c) It varies

Donald is in the set, but the set can’t find
  him.
The Name class violates the hashCode contract.
Another Look
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(quot;Donaldquot;, quot;Duckquot;));
16         System.out.println(
17           s.contains(new Name(quot;Donaldquot;, quot;Duckquot;)));
18     }
19 }
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, Chapter 3
3. “Indecision”
01 class Indecisive {
02     public static void main(String[] args) {
03         System.out.println(waffle());
04     }
05
06     static boolean waffle() {
07         try {
08             return true;
09         } finally {
10             return false;
11         }
12     }
13 }
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 above

The finally is processed after the try.
Another Look
01 class Indecisive {
02     public static void main(String[] args) {
03         System.out.println(waffle());
04     }
05
06     static boolean waffle() {
07         try {
08             return true;
09         } finally {
10             return false;
11         }
12     }
13 }
The Moral
• Avoid abrupt completion of
  finally blocks
      Wrap unpredictable actions with nested
  –
      trys
      Don't return or throw exceptions
  –
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 }
What Does It Print?
(a) [-2000000000, 0, 2000000000]
(b) [2000000000, 0, -2000000000]
(c) [-2000000000, 2000000000, 0]
(d) It varies
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
      •
Another Look
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 }
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   }
The Moral
• ints aren't integers!
• Think about overflow
• This particular comparison technique
      OK only if max - min <= Integer.MAX_VALUE
  –
      For example: all values positive
  –

• Don’t write overly clever code
5. “You're Such a Character”
01 public class Trivial {
02     public static void main(String args[]) {
03         System.out.print(quot;Hquot; + quot;aquot;);
04         System.out.print('H' + 'a');
05     }
06 }
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 String. Ouch.
The Moral
    Use string concatenation (+) with
•
    care
        At least one operand must be a String
    –
        If it isn't, cast or convertquot; + 'H' +
    –
        'a');
    Be glad operator overloading isn't
•
    supported
6. “The Case of the Constructor”
01 public class Confusing {
02     public Confusing(Object o) {
03         System.out.println(quot;Objectquot;);
04     }
05     public Confusing(double[] dArray) {
06         System.out.println(quot;double arrayquot;);
07     }
08     public static void main(String args[]) {
09         new Confusing(null);
10     }
11 }
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 wins
Another Look
01 public class Confusing {
02     public Confusing(Object o) {
03         System.out.println(quot;Objectquot;);
04     }
05     public Confusing(double[] dArray) {
06         System.out.println(quot;double arrayquot;);
07     }
08     public static void main(String args[]) {
09         new Confusing(null);
10     }
11 }
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 behavior
  identical
• If you are using a quot;brokenquot; class,
  make intentions clear with a cast
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(quot;Byte me! quot;);
07       }
08     }
09 }
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 promoted with surprising results
  –
Another Look
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) // (b == 144)
06               System.out.print(quot;Byte me! quot;);
07       }
08     }
09 }
10
11 // But (byte)0x90 == -112
How Do You Fix It?
• Cast int to byte
 if (b == (byte)0x90)
   System.out.println(quot;Byte me!quot;);
• Or convert byte to int, suppressing
  sign extension with mask
  if ((b & 0xff) == 0x90)
    System.out.println(quot;Byte me!quot;);
The Moral
• Bytes aren't ints
• Be careful when mixing primitive
  types
• Compare like-typed expressions
      Cast or convert one operand as
  –
      necessary
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 }
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 can't be represented
  exactly by float or double
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(quot;2.00quot;).subtract(
06                   new BigDecimal(quot;1.10quot;)));
07       }
08   }
09
10   public class Change {
11       public static void main(String args[]) {
12           System.out.println(200 - 110);
13       }
14   }
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 = quot;Basequot;;
03   }
04
05   class Derived extends Base {
06       private String name = quot;Derivedquot;;
07   }
08
09   public class PrivateMatter {
10       public static void main(String[] args) {
11           System.out.println(new Derived().name);
12       }
13   }
What Does It Print?
(a) Derived
(b) Base
(c) Compiler error in class Derived:
   Can't assign weaker access to name
(d) None of the above
What Does it Print?
(a) Derived
(b) Base
(c) Compiler error in class Derived:
    Can't assign weaker access to name
(d) None of the above: Compiler error in
  class
   PrivateMatter: Can't access name

   Private method can't overrides public,
       but private field can hide public
Another Look
01   class Base {
02       public String name = quot;Basequot;;
03   }
04
05   class Derived extends Base {
06       private String name = quot;Derivedquot;;
07   }
08
09   public class PrivateMatter {
10       public static void main(String[] args) {
11           System.out.println(new Derived().name);
12       }
13   }
How Do You Fix It?
01   class Base {
02       public String getName() { return quot;Basequot;; }
03   }
04
05   class Derived extends Base {
06       public String getName() { return quot;Derivedquot;; }
07   }
08
09   public class PrivateMatter {
10       public static void main(String[] args) {
11          System.out.println(new Derived().getName());
12       }
13   }
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 = 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 }
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 Look
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 }
How Do You Fix It?
• Change loop variable from int
  to long
 for (long i = start; i <= end; i++)
   count++;
The Moral
• ints aren't integers!
• Think about overflow

     larger type if
• Use
  necessary
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     }
08
09     private static Integer randomInteger() {
10         return new Integer(new Random().nextInt());
11     }
12 }
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 above

A new random number generator is
created each iteration and the seed
changes rarely if at all.
Another Look
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     }
08
09     private static Integer randomInteger() {
10         return new Integer(new Random().nextInt());
11     }
12 }
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     }
08
09     private static Random rnd = new Random();
10
11     private static Integer randomInteger() {
12         return new Integer(rnd.nextInt());
13     }
14 }
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
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(quot;Mickeyquot;, quot;Mousequot;));
17         System.out.println(
18             s.contains(new Name(quot;Mickeyquot;, quot;Mousequot;)));
19     }
20 }
What Does It Print?
(a) true
(b) false
(c) It varies
What Does It Print?
(a) true
(b) false
(c) It varies

Name overrides hashCode but not
equals.
The two Name instances are unequal.
Another Look
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) { // Accidental overloading
09         return first.equals(o.first) && last.equals(o.last);
10     }
11     public int hashCode() {         // Overriding
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(quot;Mickeyquot;, quot;Mousequot;));
17         System.out.println(
18         s.contains(new Name(quot;Mickeyquot;, quot;Mousequot;)));
19     }
20 }
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 }
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!
13. “Ping Pong”
01 class PingPong {
02     public static synchronized void main(String[] a)
   {
03         Thread t = new Thread() {
04             public void run() {
05                  pong();
06             }
07         };
08
09         t.run();
10         System.out.print(quot;Pingquot;);
11     }
12
13     static synchronized void pong() {
14         System.out.print(quot;Pongquot;);
15     }
16 }
What Does It Print?
(a) PingPong
(b) PongPing
(c) It varies
What Does It Print?
(a) PingPong
(b) PongPing
(c) It varies

Not a multithreaded program!
Another Look
01 class PingPong {
02     public static synchronized void main(String[] a) {
03         Thread t = new Thread() {
04             public void run() {
05                  pong();
06             }
07         };
08
09         t.run(); // Common typo!
10         System.out.print(quot;Pingquot;);
11     }
12
13     static synchronized void pong() {
14         System.out.print(quot;Pongquot;);
15     }
16 }
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     };
08
09     t.start();
10     System.out.print(quot;Pingquot;);
11   }
12
13   static synchronized void pong() {
14     System.out.print(quot;Pongquot;);
15   }
16 }
The Moral
• Invoke Thread.start, not
  Thread.run
 ─ Common error
 ─ Can be very difficult to diagnose
• (Thread shouldn’t implement
  Runnable)
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 }
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 Look
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 }
09
10 // (-1 << 32) == -1
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 }
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
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 }
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 varies

The Unicode escape in the comment
breaks
it in two. The second half is garbage.
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   }
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 }
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 (quot;) can terminate string literals
16. “All Strung Out”
01   public class Puzzling {
02       public static void main(String[] args) {
03           String s = new String(quot;blahquot;);
04           System.out.println(s);
05       }
06   }
07   class String {
08       java.lang.String s;
09
10       public String(java.lang.String s) {
11           this.s = s;
12       }
13       public java.lang.String toString() {
14           return s;
15       }
16   }
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) Other


NoSuchMethodError is thrown
because the Puzzling class is missing
a main method.
Another Look
01   public class Puzzling {
02       public static void main(String[] args) {
03           String s = new String(quot;blahquot;);
04           System.out.println(s);
05       }
06   }
07   class String {
08       java.lang.String s;
09
10       public String(java.lang.String s) {
11           this.s = s;
12       }
13       public java.lang.String toString() {
14           return s;
15       }
16   }
How Do You Fix It?
01   public class Puzzling {
02       public static void main(String[] args) {
03           MyString s = new MyString(quot;blahquot;);
04           System.out.println(s);
05       }
06   }
07   class MyString {
08       String s;
09
10       public MyString(String s) {
11           this.s = s;
12       }
13       public String toString() {
14           return s;
15       }
16   }
The Moral
• Avoid name reuse in all its guises
 ─ hiding, shadowing, overloading
• Don’t even think about reusing
  platform
  class names!
17. “Reflection Infection”
01 import java.lang.reflect.*;
02
03 public class Reflector {
04     public static void main(String[] args) throws Exception {
05         Set s = new HashSet();
06         s.add(quot;fooquot;);
07         Iterator i = s.iterator();
08         Method m =
09             i.getClass().getMethod(quot;hasNextquot;, new Class[0]);
10         System.out.println(m.invoke(i, new Object[0]));
11     }
12 }
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 above

Attempts to invoke a method on a
 private class
Another Look
01 import java.lang.reflect.*;
02
03 public class Reflector {
04     public static void main(String[] args) throws Exception {
05         Set s = new HashSet();
06         s.add(quot;fooquot;);
07         Iterator i = s.iterator();
08         Method m =
09             i.getClass().getMethod(quot;hasNextquot;, new Class[0]);
10         System.out.println(m.invoke(i, new Object[0]));
11     }
12 }
How Do You Fix It?
01 import java.lang.reflect.*;
02
03 public class Reflector {
04     public static void main(String[] args) throws Exception {
05         Set s = new HashSet();
06         s.add(quot;fooquot;);
07         Iterator i = s.iterator();
08         Method m =
09             Iterator.class.getMethod(quot;hasNextquot;,
10                                      new Class[0]);
11         System.out.println(m.invoke(i, new Object[0]));
12     }
13 }
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
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) + quot; quot;);
09     }
10 }
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
What Does It Print?
(a) The numbers from 0 to 255
(b) The numbers from 0 to 127 then
  -128 to -1
(c) It varies*
(d) None of the above

The sequence depends on the default
 charset,which depends on OS and
 locale.
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
  37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
  71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 8364
  65533 8218 402 8222 8230 8224 8225 710 8240 352 8249 338 65533 381 65533 65533 8216 8217 8220 8221
  8226 8211 8212 732 8482 353 8250 339 65533 382 376 160 161 162 163 164 165 166 167 168 169 170 171 172
Another Look
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) + quot; quot;);
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.]
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, quot;ISO-8859-1quot;);
07         for(int i = 0; i < str.length(); i++)
08             System.out.print((int)str.charAt(i) + quot; quot;);
09     }
10 }

ISO-8859-1 indicates the Latin1 charset.
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
19. “Elvis Lives!”
01 public class Elvis {
02     public static final Elvis INSTANCE = new Elvis();
03     private final int beltSize;
04
05     private static final int CURRENT_YEAR =
06         Calendar.getInstance().get(Calendar.YEAR);
07
08     private Elvis() { beltSize = CURRENT_YEAR - 1930; }
09     public int beltSize() { return beltSize; }
10
11     public static void main(String[] args) {
12         System.out.println(quot;Elvis wears size quot; +
13                        INSTANCE.beltSize() + quot; belt.quot;);
14     }
15 }
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.
What Does It Print?
(a) Elvis wears size 0 belt.
(b) Elvis wears size 73 belt.
(c) Elvis wears size -1930 belt.
(d) None of the above.

The value of CURRENT_YEAR is used before it
  is
initialized, due to circularity in class
  initialization.
Another Look
01 // Static initialization proceeds top to bottom.
02 public class Elvis {
03     // Recursive initialization returns immediately!
04     public static final Elvis INSTANCE = new Elvis();
05     private final int beltSize;
06
07     private static final int CURRENT_YEAR =
08         Calendar.getInstance().get(Calendar.YEAR);
09
10     private Elvis() { beltSize = CURRENT_YEAR - 1930; }
11     public int beltSize() { return beltSize; }
12
13     public static void main(String[] args) {
14         System.out.println(quot;Elvis wears size quot; +
15                        INSTANCE.beltSize() + quot; belt.quot;);
16     }
17 }
How Do You Fix It?
01 public class Elvis {
02     private final int beltSize;
03
04     private static final int CURRENT_YEAR =
05         Calendar.getInstance().get(Calendar.YEAR);
06
07     // Make instance after other initialization complete
08     public static final Elvis INSTANCE = new Elvis();
09
10     private Elvis() { beltSize = CURRENT_YEAR - 1930; }
11     public int beltSize() { return beltSize; }
12
13     public static void main(String[] args) {
14         System.out.println(quot;Elvis wears size quot; +
15                        INSTANCE.beltSize() + quot; belt.quot;);
16     }
17 }
The Moral
• Watch out for circularities in static
  initialization
   One or more classes may be involved
   Circularities aren’t necessarily wrong but…
    quot; Constructors can run before class fully initialized
    quot; 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)
20. “What’s the Point?”
01 class Point {
02     protected final int x, y;
03     private final String name; // Cached at construction time
04     protected String makeName() { return quot;[quot; + x + quot;,quot; + y + quot;]quot;; }
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 }
11
12 public class ColorPoint extends Point {
13     private final String color;
14     protected String makeName() { return super.makeName() + quot;:quot; +
   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, quot;purplequot;));
21     }
22 }
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 above

Superclass constructor runs a subclass
 method
before the subclass instance is
 initialized.
Another Look
01 class Point {
02     protected final int x, y;
03     private final String name;
04     protected String makeName() { return quot;[quot; + x + quot;,quot; + y + quot;]quot;; }
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 method
09     }
10 }
11
12 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() + quot;:quot; +
   color; }
16     ColorPoint(int x, int y, String color) {
17         super(x, y);          // (2) Chains to superclass constructor
18         this.color = color; // (5) Initializes blank final instance
   field
19     }
20     public static void main(String[] args) { // (1) Invoke subclass cons.
21         System.out.println(new ColorPoint(4, 2, quot;purplequot;));
22     }
23 }
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 quot;[quot; + x + quot;,quot; + y + quot;]quot;; }
05     public final synchronized String toString()
06         { return (name == null ? (name = makeName()) : name); }
07     Point(int x, int y) {
08         this.x = x; this.y = y;
09         // (name initialization removed)
10     }
11 }
12
13 public class ColorPoint extends Point {
14     private final String color;
15     protected String makeName() { return super.makeName() + quot;:quot; +
   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, quot;purplequot;));
22     }
23 }
The Moral
• Never call overridable methods
  from constructors, directly or
  indirectly
• Also applies to “pseudo-constructors”
 ─ readObject()
 ─ clone()
• See Effective Java, Item 15
21. “Long Division”
01 public class LongDivision {
02    private static final long MILLIS_PER_DAY
03        = 24 * 60 * 60 * 1000;
04    private static final long MICROS_PER_DAY
05        = 24 * 60 * 60 * 1000 * 1000;
06
07    public static void main(String[] args) {
08        System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
09    }
10 }
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 exception


Computation does overflow
Another Look
01 public class LongDivision {
02     private static final long MILLIS_PER_DAY
03         = 24 * 60 * 60 * 1000;
04     private static final long MICROS_PER_DAY
05         = 24 * 60 * 60 * 1000 * 1000; // >> Integer.MAX_VALUE
06
07     public static void main(String[] args) {
08         System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
09     }
10 }
How Do You Fix It?
01 public class LongDivision {
02     private static final long MILLIS_PER_DAY
03         = 24L * 60 * 60 * 1000;
04     private static final long MICROS_PER_DAY
05         = 24L * 60 * 60 * 1000 * 1000;
06
07     public static void main(String[] args) {
08         System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
09     }
10 }
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
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)
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
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.
Another Look
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)) { // 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 }
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(quot;Pquot;);
   break;
07           case 2: word = new StringBuffer(quot;Gquot;);
   break;
08           default: word = new StringBuffer(quot;Mquot;);
   break;
09        }
10        word.append('a');
11        word.append('i');
12        word.append('n');
13        System.out.println(word);
14     }
15 }
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
23. “The Name Game”
01 public class NameGame {
02     public static void main(String args[]) {
03         Map m = new IdentityHashMap();
04         m.put(quot;Mickeyquot;, quot;Mousequot;);
05         m.put(quot;Mickeyquot;, quot;Mantlequot;);
06         System.out.println(m.size());
07     }
08 }
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 varies

We’re using an IdentityHashMap, but
   string
literals are interned (they cancel each
   other out)
Another Look
01 public class NameGame {
02     public static void main(String args[]) {
03         Map m = new IdentityHashMap();
04         m.put(quot;Mickeyquot;, quot;Mousequot;);
05         m.put(quot;Mickeyquot;, quot;Mantlequot;);
06         System.out.println(m.size());
07     }
08 }
How Do You Fix It?
01 public class NameGame {
02     public static void main(String args[]) {
03         Map m = new HashMap();
04         m.put(quot;Mickeyquot;, quot;Mousequot;);
05         m.put(quot;Mickeyquot;, quot;Mantlequot;);
06         System.out.println(m.size());
07     }
08 }
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)
24. “More of The Same”
01 public class Names {
02     private Map m = new HashMap();
03     public void Names() {
04         m.put(quot;Mickeyquot;, quot;Mousequot;);
05         m.put(quot;Mickeyquot;, quot;Mantlequot;);
06     }
07
08     public int size() { return m.size(); }
09
10     public static void main(String args[]) {
11         Names names = new Names();
12         System.out.println(names.size());
13     }
14 }
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 varies



No programmer-defined constructor
Another Look
01 public class Names {
02      private Map m = new HashMap();
03      public void Names() {    // Not a constructor!
04          m.put(quot;Mickeyquot;, quot;Mousequot;);
05          m.put(quot;Mickeyquot;, quot;Mantlequot;);
06      }
07
08      public int size() { return m.size(); }
09
10      public static void main(String args[]) {
11          Names names = new Names(); // Invokes
   default!
12          System.out.println(names.size());
13      }
14 }
How Do You Fix It?
01 public class Names {
02     private Map m = new HashMap();
03     public Names() {    // No return type
04         m.put(quot;Mickeyquot;, quot;Mousequot;);
05         m.put(quot;Mickeyquot;, quot;Mantlequot;);
06     }
07
08     public int size() { return m.size(); }
09
10     public static void main(String args[]) {
11         Names names = new Names();
12         System.out.println(names.size());
13     }
14 }
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
25. “Shades of Gray”
01   public class Gray {
02       public static void main(String[] args){
03           System.out.println(X.Y.Z);
04       }
05   }
06
07   class X {
08       static class Y {
09           static String Z = quot;Blackquot;;
10       }
11       static C Y = new C();
12   }
13
14   class C {
15       String Z = quot;Whitequot;;
16   }

Thanks to Prof. Dominik Gruntz, Fachhochschule Aargau
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 above

Field Y obscures member class Y (JLS
  6.3.2)
The rule: variable > type > package
Another Look
01   public class Gray {
02       public static void main(String[] args){
03           System.out.println(X.Y.Z);
04       }
05   }
06
07   class X {
08       static class Y {
09           static String Z = quot;Blackquot;;
10       }
11       static C Y = new C();
12   }
13
14   class C {
15       String Z = quot;Whitequot;;
16   }

The rule: variable > type > package
How Do You Fix It?
01   public class Gray {
02       public static void main(String[] args){
03           System.out.println(Ex.Why.z);
04       }
05   }
06
07   class Ex {
08       static class Why {
09           static String z = quot;Blackquot;;
10       }
11       static See y = new See();
12   }
13
14   class See {
15       String z = quot;Whitequot;;
16   }
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
26. “It’s Elementary”
01 public class Elementary {
02     public static void main(String[] args) {
03         System.out.println(54321 + 5432l);
04     }
05 }
What Does It Print?
(a)   -22430
(b)    59753
(c)    10864
(d)   108642
What Does It Print?
(a)   -22430
(b)    59753
(c)    10864
(d)   108642

Program doesn’t say what you think it
  does!
Another Look
01 public class Elementary {
02     public static void main(String[] args) {

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




1    - the numeral one

l    - the lowercase letter el
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 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();
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 }
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 above



The termination test misbehaves due
to floating point “granularity.”
Another Look
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 }



// (float) START == (float) (START + 50)
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 }
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
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 (quot;0123456789quot;.indexOf(ch) >= 0)
08             return quot;NUMERAL quot;;
09         if (quot;abcdefghijklmnopqrstuvwxyzquot;.indexOf(ch) >= 0)
10             return quot;LETTER quot;;
11 /* (Operators not supported yet)
12 *       if (quot;+-*/&|!=quot;.indexOf(ch) >= 0)
13 *            return quot;OPERATOR quot;;
14 */
15         return quot;UNKNOWN quot;;
16     }
17 }
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 above



As for the intuition, you’ll see in a
moment...
Another Look
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 (quot;0123456789quot;.indexOf(ch) >= 0)
08             return quot;NUMERAL quot;;
09         if (quot;abcdefghijklmnopqrstuvwxyzquot;.indexOf(ch) >= 0)
10             return quot;LETTER quot;;
11 /* (Operators not supported yet)
12 *       if (quot;+-*/&|!=quot;.indexOf(ch) >= 0)
13 *            return quot;OPERATOR quot;;
14 */
15         return quot;UNKNOWN quot;;
16     }
17 }
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 (quot;0123456789quot;.indexOf(ch) >= 0)
08                return quot;NUMERAL quot;;
09           if (quot;abcdefghijklmnopqrstuvwxyzquot;.indexOf(ch) >= 0)
10                return quot;LETTER quot;;
11   if (false) {     // (Operators not supported yet)
12           if (quot;+-*/&|!=quot;.indexOf(ch) >= 0)
13                 return quot;OPERATOR quot;;
14   }
15           return quot;UNKNOWN quot;;
16       }
17   }
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.println(
04              Long.toHexString(0x100000000L +
   0xcafebabe));
05      }
06 }
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 exception


0xcafebabe is a negative number
Another Look
01 public class JoyOfHex {
02      public static void main(String[] args) {
03          System.out.println(
04              Long.toHexString(0x100000000L +
   0xcafebabe));
05      }
06 }



           1111111

       0xffffffffcafebabeL
     + 0x0000000100000000L
       0x00000000cafebabeL
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 }
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
30. “Animal Farm”
01 public class AnimalFarm {
02     public static void main(String[] args) {
03         final String pig = quot;length: 10quot;;
04         final String dog = quot;length: quot;+pig.length();
05         System.out.println(quot;Animals are equal: quot;
06                            + pig == dog);
07     }
08 }
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: false


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




System.out.println(
    (quot;Animals are equal: quot; + pig) == dog);
How Do You Fix It?
01 public class AnimalFarm {
02     public static void main(String[] args) {
03         final String pig = quot;length: 10quot;;
04         final String dog = quot;length: quot;+pig.length();
05         System.out.println(quot;Animals are equal: quot;
06                            + (pig == dog));
07     }
08 }
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
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 }
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 above


Operands are evaluated left to right.
Postfix increment returns old value.
Another Look
01 public class Assignment {
02     public static void main(String[] a) throws Exception {
03         int tricky = 0;
04         for (int i = 0; i < 3; i++)
05             tricky += tricky++;
06         System.out.println(tricky);
07     }
08 }
Another Look
01 public class Assignment {
02     public static void main(String[] a) throws Exception {
03         int tricky = 0;
04         for (int i = 0; i < 3; i++)
05            tricky += tricky++;
06         System.out.println(tricky);
07     }
08 }
Another Look


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


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


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


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


05       tricky += tricky++;
         0         0           (tricky == 0)
Another Look
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 }
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 }
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)
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 }
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 above




Not only is the program repulsive, but it has a
bug
Another Look
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 }
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     }
11
12     private static boolean thirdElementIsThree(int[] a) {
13         return a.length >= 3 && a[2] == 3;
14     }
15 }
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
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 }
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 above


Lazy initialization + eager initialization = a
mess
Another Look
01 class Cache {
02     static { initIfNecessary(); }
03     private static int sum;
04     public static int getSum() {
05         initIfNecessary();
06         return sum;
07     }
08     private static boolean initialized = false;
09     private static synchronized void initIfNecessary() {
10         if (!initialized) {
11             for (int i = 0; i < 100; i++)
12                 sum += i;
13             initialized = true;
14         }
15     }
16     public static void main(String[] args) {
17         System.out.println(getSum());
18     }
19 }
Another Look
01 class Cache {
02     static { initIfNecessary(); }
03     private static int sum;
04     public static int getSum() {
05         initIfNecessary();
06         return sum;
07     }
08     private static boolean initialized = false; // Ouch!
09     private static synchronized void initIfNecessary() {
10         if (!initialized) {
11             for (int i = 0; i < 100; i++)
12                 sum += i;
13             initialized = true;
14         }
15     }
16     public static void main(String[] args) {
17         System.out.println(getSum());
18     }
19 }
How Do You Fix It?
01 class Cache {
02     private static final int SUM = computeSum();
03
04     private static int computeSum() {
05         int result = 0;
06         for (int i = 0; i < 100; i++)
07             result += i;
08         return result;
09     }
10
11     public static int getSum() {
12         return SUM;
13     }
14
15     public static void main(String[] args) {
16         System.out.println(getSum());
17     }
18 }
The Moral
• Use eager or lazy initialization, not
  both
  > Prefer eager initialization to lazy
• Think about class initialization
• Avoid complex class initialization
  sequences
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];
05
06         int i = Integer.MIN_VALUE;
07         // This loop iterates over all int values
08         do {
09              histogram[Math.abs(i) % MODULUS]++;
10         } while (i++ != Integer.MAX_VALUE);
11
12         for (int j = 0; j < MODULUS; j++)
13              System.out.print(histogram[j] + quot; quot;);
14     }
15 }
What Does It Print?
(a) 1431655765 1431655765
1431655765
(b) 1431655765 1431655766
1431655765
(c) Throws an exception
(d) None of the above



Hint: 232 / 3 = 1,431,655,765
What Does It Print?
(a) 1431655765 1431655765
1431655765
(b) 1431655765 1431655766
1431655765
(c) Throws an exception: array out of
bounds
(d) None of the above


Math.abs doesn’t always return a nonnegative
Another Look
01 public class Mod {
02     public static void main(String[] args) {
03         final int MODULUS = 3;
04         int[] histogram = new int[MODULUS];
05
06         int i = Integer.MIN_VALUE;
07         // This loop iterates over all int values
08         do {
09              histogram[Math.abs(i) % MODULUS]++;
10         } while (i++ != Integer.MAX_VALUE);
11
12         for (int j = 0; j < MODULUS; j++)
13              System.out.println(histogram[j] + quot; quot;);
14     }
15 }
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;
   }
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
35. “Package Deal”
01 package click;
02 public class CodeTalk {
03     public void doIt() { printMessage(); }
04     void printMessage() { System.out.println(quot;Clickquot;); }
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(quot;Hackquot;); }
06       }
07       public static void main(String[] args) {
08           new ClickIt().doIt();
09     }
10 }
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 above




There is no overriding in this program
Another Look
01 package click;
02 public class CodeTalk {
03     public void doIt() { printMessage(); }
04     void printMessage() { System.out.println(quot;Clickquot;); }
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(quot;Hackquot;); }
06      }
07      public static void main(String[] args) {
08          new ClickIt().doIt();
09      }
10 }
How Do You Fix It?
• If you want overriding
 • Make printMessage public or protected
 • Use @Override to ensure that you got
   overriding
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
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 }
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 deadlocks




Intuition: You wouldn’t believe us if we told
you.
Another Look
01 public class Lazy {
02     private static boolean initialized = false;
03     static {
04         Thread t = new Thread(new Runnable() {
05              public void run() {
06                  initialized = true; // Deadlocks here!
07              }
08         });
09         t. start();
10         try {
11              t.join();
12         } catch (InterruptedException e) {
13              throw new AssertionError(e);
14         }
15     }
16     public static void main(String[] args) {
17         System.out.println(initialized);
18     }
19 }
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!
The Moral
• Never use background threads in class
  initialization
• Keep class initialization simple
• Don’t code like my brother
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);
04
05         boolean foundOdd = false;
06         for (Iterator<Integer> it=list.iterator();it.hasNext(); )
07             foundOdd = foundOdd || isOdd(it.next());
08
09         System.out.println(foundOdd);
10     }
11
12     private static boolean isOdd(int i) {
13         return (i & 1) != 0;
14     }
15 }
What Does It Print?
01 public class OddBehavior {
02     public static void main(String[] args) {
03         List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2);
04
05         boolean foundOdd = false;
06         for (Iterator<Integer> it=list.iterator(); it.hasNext(); )
07             foundOdd = foundOdd || isOdd(it.next());
08
09         System.out.println(foundOdd);
10     }
11
12     private static boolean isOdd(int i) {
13         return (i & 1) != 0;                 (a) true
14     }
                                                (b) false
15 }

                                               (c) Throws exception
                                               (d) None of the above
What Does It Print?
(a) true
(b) false
(c) Throws exception
(d) None of the above: Nothing—
Infinite loop



Conditional OR operator (||) short-
circuits iterator
Another Look
public class OddBehavior {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2);

            boolean foundOdd = false;
            for (Iterator<Integer> it = list.iterator(); it.hasNext();
    )
               foundOdd = foundOdd || isOdd(it.next());

            System.out.println(foundOdd);
        }

        private static boolean isOdd(int i) {
            return (i & 1) != 0;
        }
}
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;
    }
}
…But This Is Even Better
public class OddBehavior {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2);
        System.out.println(containsOdd(list));
    }

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

    private static boolean isOdd(int i) {
        return (i & 1) != 0;
    }
}
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
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 + quot; quot; + list);
    }
}
(a) [-3, -2, -1] [-3, -2, -1]

What Does It Print?                    (b) [-3, -2, -1] [-2, 0, 2]
                                       (c) Throws exception
                                       (d) None of the above
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 + quot; quot; + list);
    }
}
What Does It Print?
(a) [-3, -2, -1] [-3, -2, -1]
(b) [-3, -2, -1] [-2, 0, 2]
(c) Throws exception
(d) None of the above



Autoboxing + overloading = confusion
Another Look
public class SetList {
    public static void main(String[] args) {
        Set<Integer> set = new LinkedHashSet<Integer>();
        List<Integer> list = new ArrayList<Integer>();

        for (int i = -3; i < 3; i++) {
            set.add(i);
            list.add(i);
        }
        for (int i = 0; i < 3; i++) {
            set.remove(i);
            list.remove(i); // List.remove(int)
        }
        System.out.println(set + quot; quot; + list);
    }
}
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 + quot; quot; + list);
    }
}
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>
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 + quot; quot; + TEN + quot; quot; + HUNDRED);
    }
}
What Does It Print?                      (a) ONE TEN HUNDRED
                                         (b) one ten hundred
public enum PowerOfTen {                  (c) one ten 100
    ONE(1), TEN(10),
                                          (d) None of the above
    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 + quot; quot; + TEN + quot; quot; + HUNDRED);
    }
}
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
Another Look
public enum PowerOfTen {
    ONE(1), TEN(10),
    HUNDRED(100) { // Creates static anonymous class
        @Override public String toString() {
            return Integer.toString(val);
        }
    };
    private final int val;
    PowerOfTen(int val) { this.val = val; }

    @Override public String toString() {
        return name().toLowerCase();
    }
    public static void main(String[] args) {
        System.out.println(ONE + quot; quot; + TEN + quot; quot; + HUNDRED);
    }
}
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 + quot; quot; + TEN + quot; quot; + HUNDRED);
    }
}
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
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(quot;Pass quot;);
               } catch (Throwable ex) {
                    System.out.print(quot;Fail quot;);
               }
           }
       }
   }
}
What Does It Print?                             (a) Pass Fail
                                                (b) Pass Pass
import java.lang.reflect.*;                     (c) It varies
                                               (d) None of the above
@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(quot;Pass quot;);
               } catch (Throwable ex) {
                    System.out.print(quot;Fail quot;);
               }
           }
       }
   }
}
What Does It Print?
(a) Pass Fail
(b) Pass Pass
(c) It varies
(d) None of the above: In fact,
nothing!



The program contains two bugs, both
subtle
Another Look
import java.lang.reflect.*;

@interface Test { } // By default, annotations are discarded at runtime
public 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(quot;Passquot;);
               } catch (Throwable ex) {
                   System.out.print(quot;Fail quot;);
               }
           }
       }
   }
}
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(quot;Pass quot;);
               } catch (Throwable ex) {
                   System.out.print(quot;Fail quot;);
               }
           }
       }
   }
}
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
41. “What the Bleep?”
public class Bleep {
     String name = quot;Bleepquot;;
     void setName(String name) {
         this.name = name;
     }
     void backgroundSetName() throws InterruptedException {
         Thread t = new Thread() {
             @Override public void run() { setName(quot;Blatquot;); }
         };
         t.start();
         t.join();
         System.out.println(name);
     }
     public static void main(String[] args) throws InterruptedException
   {
         new Bleep().backgroundSetName();
     }
}
What Does It Print?                            (a) Bleep
                                                (b) Blat
public class Bleep {
     String name = quot;Bleepquot;;
                                                (c) It varies
     void setName(String name) {
                                                (d) None of the above
         this.name = name;
     }
     void backgroundSetName() throws InterruptedException {
         Thread t = new Thread() {
             @Override public void run() { setName(quot;Blatquot;); }
         };
         t.start();
         t.join();
         System.out.println(name);
     }
     public static void main(String[] args) throws InterruptedException
   {
         new Bleep().backgroundSetName();
     }
}
What Does It Print?
(a) Bleep
(b) Blat
(c) It varies
(d) None of the above



Bleep.setName isn’t getting called
Another Look
public class Bleep {
     String name = quot;Bleepquot;;
     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(quot;Blatquot;); }
         };
         t.start();
         t.join();
         System.out.println(name);
     }
     public static void main(String[] args) throws InterruptedException
   {
         new Bleep().backgroundSetName();
     }
}
How Do You Fix It?
public class Bleep {
     String name = quot;Bleepquot;;
     void setName(String name) {
         this.name = name;
     }
     void backgroundSetName() throws InterruptedException {
         Thread t = new Thread(new Runnable() {
             public void run() { setName(quot;Blatquot;); }
         });
         t.start();
         t.join();
         System.out.println(name);
     }
     public static void main(String[] args) throws InterruptedException
   {
         new Bleep().backgroundSetName();
     }
}
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
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);
   }
}
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
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
Another Look
public class BeyondCompare {
   public static void main(String[] args) {
       Object o = new Integer(3);
       System.out.println(new Double(3).compareTo(o) == 0);
   }
}

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

public class Double extends Number
                    implements Comparable<Double>
How Do You Fix It?
// Preserves 1.4 semantics
public 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 problem
public class BeyondCompare {
   public static void main(String[] args) {
       Double d = 3.0;
       System.out.println(Double.valueOf(3).compareTo(d) == 0);
   }
}
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
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));
    }
}
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
What Does It Print?
(a) [1, 1, 2, 3, 5, 8, 13]
(b) Throws exception
(c) It varies: Depends on hashcode
[[I@ad3ba4]
(d) None of the above


Arrays.asList only works on arrays of
object refs
Another Look
public class Fibonacci {
    private static final int LENGTH = 7;
    public static void main(String[] args) {
        int[] fib = new int[LENGTH];
        fib[0] = fib[1] = 1; // First 2 Fibonacci numbers
        for (int i = 2; i < LENGTH; i++)
            fib[i] = fib[i - 2] + fib[i - 1];

        // Idiom only works for arrays of object references
        System.out.println(Arrays.asList(fib));
    }
}
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));
    }
}
The Moral
• Use varargs sparingly in your APIs
  > It can hide errors and cause confusion
  > This program wouldn't compile under 1.4
• Arrays.asList printing idiom is
 obsolete
  > use Arrays.toString instead
  > Prettier, safer, and more powerful
• A full complement of array utilities
  added in 5.0
  • equals, hashCode, toString for all array
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
     *         doesn't represent a valid integer
     */
   public static Integer parseInt(String s) {
        return (s == null) ?
                (Integer) null : Integer.parseInt(s);
   }

    public static void main(String[] args) {
        System.out.println(parseInt(quot;-1quot;) + quot; quot; +
                           parseInt(null) + quot; quot; +
                           parseInt(quot;1quot;));
    }
}
(a) -1 null 1
What Does It Print?                          (b) -1 0 1
                                             (c) Throws exception
public 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
     *         doesn't represent a valid integer
     */
   public static Integer parseInt(String s) {
        return (s == null) ?
                (Integer) null : Integer.parseInt(s);
   }

    public static void main(String[] args) {
        System.out.println(parseInt(quot;-1quot;) + quot; quot; +
                           parseInt(null) + quot; quot; +
                           parseInt(quot;1quot;));
    }
}
What Does It Print?
(a) -1 null 1
(b) -1 0 1
(c) Throws exception:
NullPointerException
(d) None of the above



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

    public static void main(String[] args) {
        System.out.println(parseInt(quot;-1quot;) + quot; quot; +
                           parseInt(null) + quot; quot; +
                           parseInt(quot;1quot;));
    }
}
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
     *         doesn't represent a valid integer.
     */
   public static Integer parseInt(String s) {
        return (s == null) ? null : Integer.valueOf(s);
   }

    public static void main(String[] args) {
        System.out.println(parseInt(quot;-1quot;) + quot; quot; +
                           parseInt(null) + quot; quot; +
                           parseInt(quot;1quot;));
    }
}
The Moral
• Mixed-type computations are
  confusing
• Especially true for ?: expressions
• Avoid null where possible
• Auto-unboxing and null are a
  dangerous mix
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 programs simple
•
        Avoid name reuse: overloading, hiding,
    –
        shadowing
    If you aren't sure what a program
•
    does,
    it probably doesn't do what you
    want it to

More Related Content

What's hot

QA Auotmation Java programs,theory
QA Auotmation Java programs,theory QA Auotmation Java programs,theory
QA Auotmation Java programs,theory archana singh
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance PuzzlersDoug Hawkins
 
Java practical(baca sem v)
Java practical(baca sem v)Java practical(baca sem v)
Java practical(baca sem v)mehul patel
 
JVM Mechanics: Understanding the JIT's Tricks
JVM Mechanics: Understanding the JIT's TricksJVM Mechanics: Understanding the JIT's Tricks
JVM Mechanics: Understanding the JIT's TricksDoug Hawkins
 
The Ring programming language version 1.5.1 book - Part 28 of 180
The Ring programming language version 1.5.1 book - Part 28 of 180The Ring programming language version 1.5.1 book - Part 28 of 180
The Ring programming language version 1.5.1 book - Part 28 of 180Mahmoud Samir Fayed
 
Basic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time APIBasic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time APIjagriti srivastava
 
Next Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingNext Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingTao Xie
 
Concurrency Concepts in Java
Concurrency Concepts in JavaConcurrency Concepts in Java
Concurrency Concepts in JavaDoug Hawkins
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)Alok Kumar
 
20.3 Java encapsulation
20.3 Java encapsulation20.3 Java encapsulation
20.3 Java encapsulationIntro C# Book
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsBaruch Sadogursky
 
Effective Java with Groovy - How Language can Influence Good Practices
Effective Java with Groovy - How Language can Influence Good PracticesEffective Java with Groovy - How Language can Influence Good Practices
Effective Java with Groovy - How Language can Influence Good PracticesNaresha K
 
Introduction to julia
Introduction to juliaIntroduction to julia
Introduction to julia岳華 杜
 
COSCUP: Introduction to Julia
COSCUP: Introduction to JuliaCOSCUP: Introduction to Julia
COSCUP: Introduction to Julia岳華 杜
 
07. Java Array, Set and Maps
07.  Java Array, Set and Maps07.  Java Array, Set and Maps
07. Java Array, Set and MapsIntro C# Book
 
Java PRACTICAL file
Java PRACTICAL fileJava PRACTICAL file
Java PRACTICAL fileRACHIT_GUPTA
 

What's hot (20)

QA Auotmation Java programs,theory
QA Auotmation Java programs,theory QA Auotmation Java programs,theory
QA Auotmation Java programs,theory
 
JVM Mechanics
JVM MechanicsJVM Mechanics
JVM Mechanics
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance Puzzlers
 
Java practical(baca sem v)
Java practical(baca sem v)Java practical(baca sem v)
Java practical(baca sem v)
 
JVM Mechanics: Understanding the JIT's Tricks
JVM Mechanics: Understanding the JIT's TricksJVM Mechanics: Understanding the JIT's Tricks
JVM Mechanics: Understanding the JIT's Tricks
 
Mutation @ Spotify
Mutation @ Spotify Mutation @ Spotify
Mutation @ Spotify
 
The Ring programming language version 1.5.1 book - Part 28 of 180
The Ring programming language version 1.5.1 book - Part 28 of 180The Ring programming language version 1.5.1 book - Part 28 of 180
The Ring programming language version 1.5.1 book - Part 28 of 180
 
Basic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time APIBasic java, java collection Framework and Date Time API
Basic java, java collection Framework and Date Time API
 
Next Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingNext Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized Testing
 
Concurrency Concepts in Java
Concurrency Concepts in JavaConcurrency Concepts in Java
Concurrency Concepts in Java
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)
 
20.3 Java encapsulation
20.3 Java encapsulation20.3 Java encapsulation
20.3 Java encapsulation
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 Seasons
 
Effective Java with Groovy - How Language can Influence Good Practices
Effective Java with Groovy - How Language can Influence Good PracticesEffective Java with Groovy - How Language can Influence Good Practices
Effective Java with Groovy - How Language can Influence Good Practices
 
Clojure class
Clojure classClojure class
Clojure class
 
Java programs
Java programsJava programs
Java programs
 
Introduction to julia
Introduction to juliaIntroduction to julia
Introduction to julia
 
COSCUP: Introduction to Julia
COSCUP: Introduction to JuliaCOSCUP: Introduction to Julia
COSCUP: Introduction to Julia
 
07. Java Array, Set and Maps
07.  Java Array, Set and Maps07.  Java Array, Set and Maps
07. Java Array, Set and Maps
 
Java PRACTICAL file
Java PRACTICAL fileJava PRACTICAL file
Java PRACTICAL file
 

Similar to Java Puzzle

Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3rsmuralirs
 
C Sharp Jn (3)
C Sharp Jn (3)C Sharp Jn (3)
C Sharp Jn (3)jahanullah
 
1z0 851 exam-java standard edition 6 programmer certified professional
1z0 851 exam-java standard edition 6 programmer certified professional1z0 851 exam-java standard edition 6 programmer certified professional
1z0 851 exam-java standard edition 6 programmer certified professionalIsabella789
 
Priming Java for Speed at Market Open
Priming Java for Speed at Market OpenPriming Java for Speed at Market Open
Priming Java for Speed at Market OpenAzul Systems Inc.
 
White Box Testing (Introduction to)
White Box Testing (Introduction to)White Box Testing (Introduction to)
White Box Testing (Introduction to)Henry Muccini
 
Exceptions irst
Exceptions irstExceptions irst
Exceptions irstjkumaranc
 
Effective C#
Effective C#Effective C#
Effective C#lantoli
 
lecture8_Cuong.ppt
lecture8_Cuong.pptlecture8_Cuong.ppt
lecture8_Cuong.pptHongV34104
 
Java, Up to Date Sources
Java, Up to Date SourcesJava, Up to Date Sources
Java, Up to Date Sources輝 子安
 
Fnt software solutions placement paper
Fnt software solutions placement paperFnt software solutions placement paper
Fnt software solutions placement paperfntsofttech
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4Abed Bukhari
 
C++ memory leak detection
C++ memory leak detectionC++ memory leak detection
C++ memory leak detectionVõ Hòa
 
JSUG - Effective Java Puzzlers by Christoph Pickl
JSUG - Effective Java Puzzlers by Christoph PicklJSUG - Effective Java Puzzlers by Christoph Pickl
JSUG - Effective Java Puzzlers by Christoph PicklChristoph Pickl
 
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...Tao Xie
 

Similar to Java Puzzle (20)

Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3
 
C Sharp Jn (3)
C Sharp Jn (3)C Sharp Jn (3)
C Sharp Jn (3)
 
1z0 851 exam-java standard edition 6 programmer certified professional
1z0 851 exam-java standard edition 6 programmer certified professional1z0 851 exam-java standard edition 6 programmer certified professional
1z0 851 exam-java standard edition 6 programmer certified professional
 
Loops
LoopsLoops
Loops
 
Priming Java for Speed at Market Open
Priming Java for Speed at Market OpenPriming Java for Speed at Market Open
Priming Java for Speed at Market Open
 
White Box Testing (Introduction to)
White Box Testing (Introduction to)White Box Testing (Introduction to)
White Box Testing (Introduction to)
 
Exceptions irst
Exceptions irstExceptions irst
Exceptions irst
 
Effective C#
Effective C#Effective C#
Effective C#
 
lecture8_Cuong.ppt
lecture8_Cuong.pptlecture8_Cuong.ppt
lecture8_Cuong.ppt
 
Java, Up to Date Sources
Java, Up to Date SourcesJava, Up to Date Sources
Java, Up to Date Sources
 
Fnt software solutions placement paper
Fnt software solutions placement paperFnt software solutions placement paper
Fnt software solutions placement paper
 
Error handling
Error handlingError handling
Error handling
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
 
Core java
Core javaCore java
Core java
 
Lecture6
Lecture6Lecture6
Lecture6
 
7
77
7
 
C++ memory leak detection
C++ memory leak detectionC++ memory leak detection
C++ memory leak detection
 
JSUG - Effective Java Puzzlers by Christoph Pickl
JSUG - Effective Java Puzzlers by Christoph PicklJSUG - Effective Java Puzzlers by Christoph Pickl
JSUG - Effective Java Puzzlers by Christoph Pickl
 
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...
ACM Distinguished Program: Cooperative Testing and Analysis: Human-Tool, Tool...
 
FSOFT - Test Java Exam
FSOFT - Test Java ExamFSOFT - Test Java Exam
FSOFT - Test Java Exam
 

Recently uploaded

Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentMahmoud Rabie
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...itnewsafrica
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Mark Simos
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructureitnewsafrica
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...Nikki Chapple
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Infrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsInfrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsYoss Cohen
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...BookNet Canada
 
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...itnewsafrica
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesBernd Ruecker
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 

Recently uploaded (20)

Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career Development
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Infrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsInfrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platforms
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
 
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architectures
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 

Java Puzzle

  • 2. Overall Presentation Goal Learn some of the quirks of programming in general and the Java language in particular; Have fun!
  • 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. 1. “All I Get is Static” 01 class Dog { 02 public static void bark() { 03 System.out.print(quot;woof quot;); 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. What Does It Print? (a) woof (b) woof woof (c) It varies
  • 6. What Does It Print? (a) woof (b) woof woof (c) It varies No dynamic dispatch on static methods
  • 7. Another Look 01 class Dog { 02 public static void bark() { 03 System.out.print(quot;woof quot;); 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. How Do You Fix It? • Remove static from the bark method
  • 9. The Moral • Static methods can't be overridden They can only be hidden – • Don’t hide static methods • Never invoke static methods on instances Not Instance.staticMethod() – But Class.staticMethod() –
  • 10. 2. “What's in a Name?” 01 public class Name { 02 private String first, last; 03 public Name(String first, String last) { 04 this.first = first; 05 this.last = last; 06 } 07 public boolean equals(Object o) { 08 if (!(o instanceof Name)) return false; 09 Name n = (Name)o; 10 return n.first.equals(first) && 11 n.last.equals(last); 12 } 13 public static void main(String[] args) { 14 Set s = new HashSet(); 15 s.add(new Name(quot;Donaldquot;, quot;Duckquot;)); 16 System.out.println( 17 s.contains(new Name(quot;Donaldquot;, quot;Duckquot;))); 18 } 19 }
  • 11. What Does It Print? (a) True (b) False (c) It varies
  • 12. What Does It Print? (a) True (b) False (c) It varies Donald is in the set, but the set can’t find him. The Name class violates the hashCode contract.
  • 13. Another Look 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(quot;Donaldquot;, quot;Duckquot;)); 16 System.out.println( 17 s.contains(new Name(quot;Donaldquot;, quot;Duckquot;))); 18 } 19 }
  • 14. How Do You Fix It? Add a hashCode method: public int hashCode() { return 31 * first.hashCode() + last.hashCode(); }
  • 15. The Moral • If you override equals, override hashCode • Obey general contracts when overriding • See Effective Java, Chapter 3
  • 16. 3. “Indecision” 01 class Indecisive { 02 public static void main(String[] args) { 03 System.out.println(waffle()); 04 } 05 06 static boolean waffle() { 07 try { 08 return true; 09 } finally { 10 return false; 11 } 12 } 13 }
  • 17. What Does It Print? (a) true (b) false (c) None of the above
  • 18. What Does It Print? (a) true (b) false (c) None of the above The finally is processed after the try.
  • 19. Another Look 01 class Indecisive { 02 public static void main(String[] args) { 03 System.out.println(waffle()); 04 } 05 06 static boolean waffle() { 07 try { 08 return true; 09 } finally { 10 return false; 11 } 12 } 13 }
  • 20. The Moral • Avoid abrupt completion of finally blocks Wrap unpredictable actions with nested – trys Don't return or throw exceptions –
  • 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. What Does It Print? (a) [-2000000000, 0, 2000000000] (b) [2000000000, 0, -2000000000] (c) [-2000000000, 2000000000, 0] (d) It varies
  • 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. Another Look 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 }
  • 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. The Moral • ints aren't integers! • Think about overflow • This particular comparison technique OK only if max - min <= Integer.MAX_VALUE – For example: all values positive – • Don’t write overly clever code
  • 27. 5. “You're Such a Character” 01 public class Trivial { 02 public static void main(String args[]) { 03 System.out.print(quot;Hquot; + quot;aquot;); 04 System.out.print('H' + 'a'); 05 } 06 }
  • 28. What Does It Print? (a) HaHa (b) Ha (c) None of the above
  • 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. The Moral Use string concatenation (+) with • care At least one operand must be a String – If it isn't, cast or convertquot; + 'H' + – 'a'); Be glad operator overloading isn't • supported
  • 31. 6. “The Case of the Constructor” 01 public class Confusing { 02 public Confusing(Object o) { 03 System.out.println(quot;Objectquot;); 04 } 05 public Confusing(double[] dArray) { 06 System.out.println(quot;double arrayquot;); 07 } 08 public static void main(String args[]) { 09 new Confusing(null); 10 } 11 }
  • 32. What Does It Print? (a) Object (b) double array (c) None of the above
  • 33. What Does It Print? (a) Object (b) double array (c) None of the above When multiple overloadings apply, the most specific wins
  • 34. Another Look 01 public class Confusing { 02 public Confusing(Object o) { 03 System.out.println(quot;Objectquot;); 04 } 05 public Confusing(double[] dArray) { 06 System.out.println(quot;double arrayquot;); 07 } 08 public static void main(String args[]) { 09 new Confusing(null); 10 } 11 }
  • 35. How Do You Fix It? • There may be no problem • If there is, use a cast: New Confusing((Object)null);
  • 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 quot;brokenquot; class, make intentions clear with a cast
  • 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(quot;Byte me! quot;); 07 } 08 } 09 }
  • 38. What Does It Print? (a) (nothing) (b) Byte me! (c) Byte me! Byte me!
  • 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. Another Look 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) // (b == 144) 06 System.out.print(quot;Byte me! quot;); 07 } 08 } 09 } 10 11 // But (byte)0x90 == -112
  • 41. How Do You Fix It? • Cast int to byte if (b == (byte)0x90) System.out.println(quot;Byte me!quot;); • Or convert byte to int, suppressing sign extension with mask if ((b & 0xff) == 0x90) System.out.println(quot;Byte me!quot;);
  • 42. The Moral • Bytes aren't ints • Be careful when mixing primitive types • Compare like-typed expressions Cast or convert one operand as – necessary
  • 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. What Does It Print? (a) 0.9 (b) 0.90 (c) It varies (d) None of the above
  • 45. What Does It Print? (a) 0.9 (b) 0.90 (c) It varies (d) None of the above: 0.89999999999999 Decimal Values can't be represented exactly by float or double
  • 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(quot;2.00quot;).subtract( 06 new BigDecimal(quot;1.10quot;))); 07 } 08 } 09 10 public class Change { 11 public static void main(String args[]) { 12 System.out.println(200 - 110); 13 } 14 }
  • 47. The Moral • Avoid float and double where exact answers are required • Use BigDecimal, int, or long instead
  • 48. 9. “A Private Matter” 01 class Base { 02 public String name = quot;Basequot;; 03 } 04 05 class Derived extends Base { 06 private String name = quot;Derivedquot;; 07 } 08 09 public class PrivateMatter { 10 public static void main(String[] args) { 11 System.out.println(new Derived().name); 12 } 13 }
  • 49. What Does It Print? (a) Derived (b) Base (c) Compiler error in class Derived: Can't assign weaker access to name (d) None of the above
  • 50. What Does it Print? (a) Derived (b) Base (c) Compiler error in class Derived: Can't assign weaker access to name (d) None of the above: Compiler error in class PrivateMatter: Can't access name Private method can't overrides public, but private field can hide public
  • 51. Another Look 01 class Base { 02 public String name = quot;Basequot;; 03 } 04 05 class Derived extends Base { 06 private String name = quot;Derivedquot;; 07 } 08 09 public class PrivateMatter { 10 public static void main(String[] args) { 11 System.out.println(new Derived().name); 12 } 13 }
  • 52. How Do You Fix It? 01 class Base { 02 public String getName() { return quot;Basequot;; } 03 } 04 05 class Derived extends Base { 06 public String getName() { return quot;Derivedquot;; } 07 } 08 09 public class PrivateMatter { 10 public static void main(String[] args) { 11 System.out.println(new Derived().getName()); 12 } 13 }
  • 53. The Moral • Avoid hiding Violates subsumption – • Avoid public fields Use accessor methods instead –
  • 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. What Does It Print? (a) 100 (b) 101 (c) (nothing)
  • 56. What Does It Print? (a) 100 (b) 101 (c) (nothing) The loop test is broken - infinite loop!
  • 57. Another Look 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 }
  • 58. How Do You Fix It? • Change loop variable from int to long for (long i = start; i <= end; i++) count++;
  • 59. The Moral • ints aren't integers! • Think about overflow larger type if • Use necessary
  • 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 } 08 09 private static Integer randomInteger() { 10 return new Integer(new Random().nextInt()); 11 } 12 }
  • 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. What Does It Print? (a) A number close to 1 (b) A number close to 50 (c) A number close to 100 (d) None of the above A new random number generator is created each iteration and the seed changes rarely if at all.
  • 63. Another Look 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 } 08 09 private static Integer randomInteger() { 10 return new Integer(new Random().nextInt()); 11 } 12 }
  • 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 } 08 09 private static Random rnd = new Random(); 10 11 private static Integer randomInteger() { 12 return new Integer(rnd.nextInt()); 13 } 14 }
  • 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. 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(quot;Mickeyquot;, quot;Mousequot;)); 17 System.out.println( 18 s.contains(new Name(quot;Mickeyquot;, quot;Mousequot;))); 19 } 20 }
  • 67. What Does It Print? (a) true (b) false (c) It varies
  • 68. What Does It Print? (a) true (b) false (c) It varies Name overrides hashCode but not equals. The two Name instances are unequal.
  • 69. Another Look 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) { // Accidental overloading 09 return first.equals(o.first) && last.equals(o.last); 10 } 11 public int hashCode() { // Overriding 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(quot;Mickeyquot;, quot;Mousequot;)); 17 System.out.println( 18 s.contains(new Name(quot;Mickeyquot;, quot;Mousequot;))); 19 } 20 }
  • 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. 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. 13. “Ping Pong” 01 class PingPong { 02 public static synchronized void main(String[] a) { 03 Thread t = new Thread() { 04 public void run() { 05 pong(); 06 } 07 }; 08 09 t.run(); 10 System.out.print(quot;Pingquot;); 11 } 12 13 static synchronized void pong() { 14 System.out.print(quot;Pongquot;); 15 } 16 }
  • 73. What Does It Print? (a) PingPong (b) PongPing (c) It varies
  • 74. What Does It Print? (a) PingPong (b) PongPing (c) It varies Not a multithreaded program!
  • 75. Another Look 01 class PingPong { 02 public static synchronized void main(String[] a) { 03 Thread t = new Thread() { 04 public void run() { 05 pong(); 06 } 07 }; 08 09 t.run(); // Common typo! 10 System.out.print(quot;Pingquot;); 11 } 12 13 static synchronized void pong() { 14 System.out.print(quot;Pongquot;); 15 } 16 }
  • 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 }; 08 09 t.start(); 10 System.out.print(quot;Pingquot;); 11 } 12 13 static synchronized void pong() { 14 System.out.print(quot;Pongquot;); 15 } 16 }
  • 77. The Moral • Invoke Thread.start, not Thread.run ─ Common error ─ Can be very difficult to diagnose • (Thread shouldn’t implement Runnable)
  • 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. What Does It Print? (a) 31 (b) 32 (c) 33 (d) None of the above
  • 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. Another Look 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 } 09 10 // (-1 << 32) == -1
  • 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. 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. 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. What Does It Print? (a) Two blank lines (b) 10 (c) Won’t compile (d) It varies
  • 86. What Does It Print? (a) Two blank lines (b) 10 (c) Won’t compile: Syntax error! (d) It varies The Unicode escape in the comment breaks it in two. The second half is garbage.
  • 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. 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. 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 (quot;) can terminate string literals
  • 90. 16. “All Strung Out” 01 public class Puzzling { 02 public static void main(String[] args) { 03 String s = new String(quot;blahquot;); 04 System.out.println(s); 05 } 06 } 07 class String { 08 java.lang.String s; 09 10 public String(java.lang.String s) { 11 this.s = s; 12 } 13 public java.lang.String toString() { 14 return s; 15 } 16 }
  • 91. What Does It Print? (a) Won’t compile (b) blah (c) Throws an exception at runtime (d) Other
  • 92. What Does It Print? (a) Won’t compile (b) blah (c) Throws an exception at runtime (d) Other NoSuchMethodError is thrown because the Puzzling class is missing a main method.
  • 93. Another Look 01 public class Puzzling { 02 public static void main(String[] args) { 03 String s = new String(quot;blahquot;); 04 System.out.println(s); 05 } 06 } 07 class String { 08 java.lang.String s; 09 10 public String(java.lang.String s) { 11 this.s = s; 12 } 13 public java.lang.String toString() { 14 return s; 15 } 16 }
  • 94. How Do You Fix It? 01 public class Puzzling { 02 public static void main(String[] args) { 03 MyString s = new MyString(quot;blahquot;); 04 System.out.println(s); 05 } 06 } 07 class MyString { 08 String s; 09 10 public MyString(String s) { 11 this.s = s; 12 } 13 public String toString() { 14 return s; 15 } 16 }
  • 95. The Moral • Avoid name reuse in all its guises ─ hiding, shadowing, overloading • Don’t even think about reusing platform class names!
  • 96. 17. “Reflection Infection” 01 import java.lang.reflect.*; 02 03 public class Reflector { 04 public static void main(String[] args) throws Exception { 05 Set s = new HashSet(); 06 s.add(quot;fooquot;); 07 Iterator i = s.iterator(); 08 Method m = 09 i.getClass().getMethod(quot;hasNextquot;, new Class[0]); 10 System.out.println(m.invoke(i, new Object[0])); 11 } 12 }
  • 97. What Does It Print? (a) Won’t compile (b) true (c) Throws exception (d) None of the above
  • 98. What Does It Print? (a) Won’t compile (b) true (c) Throws exception - IllegalAccessError (d) None of the above Attempts to invoke a method on a private class
  • 99. Another Look 01 import java.lang.reflect.*; 02 03 public class Reflector { 04 public static void main(String[] args) throws Exception { 05 Set s = new HashSet(); 06 s.add(quot;fooquot;); 07 Iterator i = s.iterator(); 08 Method m = 09 i.getClass().getMethod(quot;hasNextquot;, new Class[0]); 10 System.out.println(m.invoke(i, new Object[0])); 11 } 12 }
  • 100. How Do You Fix It? 01 import java.lang.reflect.*; 02 03 public class Reflector { 04 public static void main(String[] args) throws Exception { 05 Set s = new HashSet(); 06 s.add(quot;fooquot;); 07 Iterator i = s.iterator(); 08 Method m = 09 Iterator.class.getMethod(quot;hasNextquot;, 10 new Class[0]); 11 System.out.println(m.invoke(i, new Object[0])); 12 } 13 }
  • 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. 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) + quot; quot;); 09 } 10 }
  • 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. What Does It Print? (a) The numbers from 0 to 255 (b) The numbers from 0 to 127 then -128 to -1 (c) It varies* (d) None of the above The sequence depends on the default charset,which depends on OS and locale. * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 8364 65533 8218 402 8222 8230 8224 8225 710 8240 352 8249 338 65533 381 65533 65533 8216 8217 8220 8221 8226 8211 8212 732 8482 353 8250 339 65533 382 376 160 161 162 163 164 165 166 167 168 169 170 171 172
  • 105. Another Look 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) + quot; quot;); 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. 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, quot;ISO-8859-1quot;); 07 for(int i = 0; i < str.length(); i++) 08 System.out.print((int)str.charAt(i) + quot; quot;); 09 } 10 } ISO-8859-1 indicates the Latin1 charset.
  • 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. 19. “Elvis Lives!” 01 public class Elvis { 02 public static final Elvis INSTANCE = new Elvis(); 03 private final int beltSize; 04 05 private static final int CURRENT_YEAR = 06 Calendar.getInstance().get(Calendar.YEAR); 07 08 private Elvis() { beltSize = CURRENT_YEAR - 1930; } 09 public int beltSize() { return beltSize; } 10 11 public static void main(String[] args) { 12 System.out.println(quot;Elvis wears size quot; + 13 INSTANCE.beltSize() + quot; belt.quot;); 14 } 15 }
  • 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. What Does It Print? (a) Elvis wears size 0 belt. (b) Elvis wears size 73 belt. (c) Elvis wears size -1930 belt. (d) None of the above. The value of CURRENT_YEAR is used before it is initialized, due to circularity in class initialization.
  • 111. Another Look 01 // Static initialization proceeds top to bottom. 02 public class Elvis { 03 // Recursive initialization returns immediately! 04 public static final Elvis INSTANCE = new Elvis(); 05 private final int beltSize; 06 07 private static final int CURRENT_YEAR = 08 Calendar.getInstance().get(Calendar.YEAR); 09 10 private Elvis() { beltSize = CURRENT_YEAR - 1930; } 11 public int beltSize() { return beltSize; } 12 13 public static void main(String[] args) { 14 System.out.println(quot;Elvis wears size quot; + 15 INSTANCE.beltSize() + quot; belt.quot;); 16 } 17 }
  • 112. How Do You Fix It? 01 public class Elvis { 02 private final int beltSize; 03 04 private static final int CURRENT_YEAR = 05 Calendar.getInstance().get(Calendar.YEAR); 06 07 // Make instance after other initialization complete 08 public static final Elvis INSTANCE = new Elvis(); 09 10 private Elvis() { beltSize = CURRENT_YEAR - 1930; } 11 public int beltSize() { return beltSize; } 12 13 public static void main(String[] args) { 14 System.out.println(quot;Elvis wears size quot; + 15 INSTANCE.beltSize() + quot; belt.quot;); 16 } 17 }
  • 113. The Moral • Watch out for circularities in static initialization One or more classes may be involved Circularities aren’t necessarily wrong but… quot; Constructors can run before class fully initialized quot; 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. 20. “What’s the Point?” 01 class Point { 02 protected final int x, y; 03 private final String name; // Cached at construction time 04 protected String makeName() { return quot;[quot; + x + quot;,quot; + y + quot;]quot;; } 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 } 11 12 public class ColorPoint extends Point { 13 private final String color; 14 protected String makeName() { return super.makeName() + quot;:quot; + 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, quot;purplequot;)); 21 } 22 }
  • 115. What Does It Print? (a) [4,2]:purple (b) [4,2]:null (c) Throws exception at runtime (d) None of the above
  • 116. What Does It Print? (a) [4,2]:purple (b) [4,2]:null (c) Throws exception at runtime (d) None of the above Superclass constructor runs a subclass method before the subclass instance is initialized.
  • 117. Another Look 01 class Point { 02 protected final int x, y; 03 private final String name; 04 protected String makeName() { return quot;[quot; + x + quot;,quot; + y + quot;]quot;; } 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 method 09 } 10 } 11 12 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() + quot;:quot; + color; } 16 ColorPoint(int x, int y, String color) { 17 super(x, y); // (2) Chains to superclass constructor 18 this.color = color; // (5) Initializes blank final instance field 19 } 20 public static void main(String[] args) { // (1) Invoke subclass cons. 21 System.out.println(new ColorPoint(4, 2, quot;purplequot;)); 22 } 23 }
  • 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 quot;[quot; + x + quot;,quot; + y + quot;]quot;; } 05 public final synchronized String toString() 06 { return (name == null ? (name = makeName()) : name); } 07 Point(int x, int y) { 08 this.x = x; this.y = y; 09 // (name initialization removed) 10 } 11 } 12 13 public class ColorPoint extends Point { 14 private final String color; 15 protected String makeName() { return super.makeName() + quot;:quot; + 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, quot;purplequot;)); 22 } 23 }
  • 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. 21. “Long Division” 01 public class LongDivision { 02 private static final long MILLIS_PER_DAY 03 = 24 * 60 * 60 * 1000; 04 private static final long MICROS_PER_DAY 05 = 24 * 60 * 60 * 1000 * 1000; 06 07 public static void main(String[] args) { 08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY); 09 } 10 }
  • 121. What Does It Print? (a) 5 (b) 1000 (c) 5000 (d) Throws an exception
  • 122. What Does It Print? (a) 5 (b) 1000 (c) 5000 (d) Throws an exception Computation does overflow
  • 123. Another Look 01 public class LongDivision { 02 private static final long MILLIS_PER_DAY 03 = 24 * 60 * 60 * 1000; 04 private static final long MICROS_PER_DAY 05 = 24 * 60 * 60 * 1000 * 1000; // >> Integer.MAX_VALUE 06 07 public static void main(String[] args) { 08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY); 09 } 10 }
  • 124. How Do You Fix It? 01 public class LongDivision { 02 private static final long MILLIS_PER_DAY 03 = 24L * 60 * 60 * 1000; 04 private static final long MICROS_PER_DAY 05 = 24L * 60 * 60 * 1000 * 1000; 06 07 public static void main(String[] args) { 08 System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY); 09 } 10 }
  • 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. 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. 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. 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. Another Look 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)) { // 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. 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(quot;Pquot;); break; 07 case 2: word = new StringBuffer(quot;Gquot;); break; 08 default: word = new StringBuffer(quot;Mquot;); break; 09 } 10 word.append('a'); 11 word.append('i'); 12 word.append('n'); 13 System.out.println(word); 14 } 15 }
  • 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. 23. “The Name Game” 01 public class NameGame { 02 public static void main(String args[]) { 03 Map m = new IdentityHashMap(); 04 m.put(quot;Mickeyquot;, quot;Mousequot;); 05 m.put(quot;Mickeyquot;, quot;Mantlequot;); 06 System.out.println(m.size()); 07 } 08 }
  • 133. What Does It Print? (a) 0 (b) 1 (c) 2 (d) It varies
  • 134. What Does It Print? (a) 0 (b) 1 (c) 2 (d) It varies We’re using an IdentityHashMap, but string literals are interned (they cancel each other out)
  • 135. Another Look 01 public class NameGame { 02 public static void main(String args[]) { 03 Map m = new IdentityHashMap(); 04 m.put(quot;Mickeyquot;, quot;Mousequot;); 05 m.put(quot;Mickeyquot;, quot;Mantlequot;); 06 System.out.println(m.size()); 07 } 08 }
  • 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(quot;Mickeyquot;, quot;Mousequot;); 05 m.put(quot;Mickeyquot;, quot;Mantlequot;); 06 System.out.println(m.size()); 07 } 08 }
  • 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. 24. “More of The Same” 01 public class Names { 02 private Map m = new HashMap(); 03 public void Names() { 04 m.put(quot;Mickeyquot;, quot;Mousequot;); 05 m.put(quot;Mickeyquot;, quot;Mantlequot;); 06 } 07 08 public int size() { return m.size(); } 09 10 public static void main(String args[]) { 11 Names names = new Names(); 12 System.out.println(names.size()); 13 } 14 }
  • 139. What Does It Print? (a) 0 (b) 1 (c) 2 (d) It varies
  • 140. What Does It Print? (a) 0 (b) 1 (c) 2 (d) It varies No programmer-defined constructor
  • 141. Another Look 01 public class Names { 02 private Map m = new HashMap(); 03 public void Names() { // Not a constructor! 04 m.put(quot;Mickeyquot;, quot;Mousequot;); 05 m.put(quot;Mickeyquot;, quot;Mantlequot;); 06 } 07 08 public int size() { return m.size(); } 09 10 public static void main(String args[]) { 11 Names names = new Names(); // Invokes default! 12 System.out.println(names.size()); 13 } 14 }
  • 142. How Do You Fix It? 01 public class Names { 02 private Map m = new HashMap(); 03 public Names() { // No return type 04 m.put(quot;Mickeyquot;, quot;Mousequot;); 05 m.put(quot;Mickeyquot;, quot;Mantlequot;); 06 } 07 08 public int size() { return m.size(); } 09 10 public static void main(String args[]) { 11 Names names = new Names(); 12 System.out.println(names.size()); 13 } 14 }
  • 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. 25. “Shades of Gray” 01 public class Gray { 02 public static void main(String[] args){ 03 System.out.println(X.Y.Z); 04 } 05 } 06 07 class X { 08 static class Y { 09 static String Z = quot;Blackquot;; 10 } 11 static C Y = new C(); 12 } 13 14 class C { 15 String Z = quot;Whitequot;; 16 } Thanks to Prof. Dominik Gruntz, Fachhochschule Aargau
  • 145. What Does It Print? (a) Black (b) White (c) Won’t compile (d) None of the above
  • 146. What Does It Print? (a) Black (b) White (c) Won’t compile (d) None of the above Field Y obscures member class Y (JLS 6.3.2) The rule: variable > type > package
  • 147. Another Look 01 public class Gray { 02 public static void main(String[] args){ 03 System.out.println(X.Y.Z); 04 } 05 } 06 07 class X { 08 static class Y { 09 static String Z = quot;Blackquot;; 10 } 11 static C Y = new C(); 12 } 13 14 class C { 15 String Z = quot;Whitequot;; 16 } The rule: variable > type > package
  • 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 } 06 07 class Ex { 08 static class Why { 09 static String z = quot;Blackquot;; 10 } 11 static See y = new See(); 12 } 13 14 class See { 15 String z = quot;Whitequot;; 16 }
  • 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. 26. “It’s Elementary” 01 public class Elementary { 02 public static void main(String[] args) { 03 System.out.println(54321 + 5432l); 04 } 05 }
  • 151. What Does It Print? (a) -22430 (b) 59753 (c) 10864 (d) 108642
  • 152. What Does It Print? (a) -22430 (b) 59753 (c) 10864 (d) 108642 Program doesn’t say what you think it does!
  • 153. Another Look 01 public class Elementary { 02 public static void main(String[] args) { 03 System.out.println(54321 + 5432l); 04 } 05 } 1 - the numeral one l - the lowercase letter el
  • 154. How Do You Fix It? We won’t insult your intelligence
  • 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. 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. What Does It Print? (a) 0 (b) 50 (c) 51 (d) None of the above
  • 158. What Does It Print? (a) 0 (b) 50 (c) 51 (d) None of the above The termination test misbehaves due to floating point “granularity.”
  • 159. Another Look 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 } // (float) START == (float) (START + 50)
  • 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. 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. 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 (quot;0123456789quot;.indexOf(ch) >= 0) 08 return quot;NUMERAL quot;; 09 if (quot;abcdefghijklmnopqrstuvwxyzquot;.indexOf(ch) >= 0) 10 return quot;LETTER quot;; 11 /* (Operators not supported yet) 12 * if (quot;+-*/&|!=quot;.indexOf(ch) >= 0) 13 * return quot;OPERATOR quot;; 14 */ 15 return quot;UNKNOWN quot;; 16 } 17 }
  • 163. What Does It Print? (a) LETTER OPERATOR NUMERAL (b) LETTER UNKNOWN NUMERAL (c) Throws an exception (d) None of the above
  • 164. What Does It Print? (a) LETTER OPERATOR NUMERAL (b) LETTER UNKNOWN NUMERAL (c) Throws an exception (d) None of the above As for the intuition, you’ll see in a moment...
  • 165. Another Look 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 (quot;0123456789quot;.indexOf(ch) >= 0) 08 return quot;NUMERAL quot;; 09 if (quot;abcdefghijklmnopqrstuvwxyzquot;.indexOf(ch) >= 0) 10 return quot;LETTER quot;; 11 /* (Operators not supported yet) 12 * if (quot;+-*/&|!=quot;.indexOf(ch) >= 0) 13 * return quot;OPERATOR quot;; 14 */ 15 return quot;UNKNOWN quot;; 16 } 17 }
  • 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 (quot;0123456789quot;.indexOf(ch) >= 0) 08 return quot;NUMERAL quot;; 09 if (quot;abcdefghijklmnopqrstuvwxyzquot;.indexOf(ch) >= 0) 10 return quot;LETTER quot;; 11 if (false) { // (Operators not supported yet) 12 if (quot;+-*/&|!=quot;.indexOf(ch) >= 0) 13 return quot;OPERATOR quot;; 14 } 15 return quot;UNKNOWN quot;; 16 } 17 }
  • 167. The Moral • You cannot reliably block-comment out code ─Comments do not nest • Use “if (false)” idiom or “//” comments
  • 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. What Does It Print? (a) cafebabe (b) 1cafebabe (c) ffffffffcafebabe (d) Throws an exception
  • 170. What Does It Print? (a) cafebabe (b) 1cafebabe (c) ffffffffcafebabe (d) Throws an exception 0xcafebabe is a negative number
  • 171. Another Look 01 public class JoyOfHex { 02 public static void main(String[] args) { 03 System.out.println( 04 Long.toHexString(0x100000000L + 0xcafebabe)); 05 } 06 } 1111111 0xffffffffcafebabeL + 0x0000000100000000L 0x00000000cafebabeL
  • 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. 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. 30. “Animal Farm” 01 public class AnimalFarm { 02 public static void main(String[] args) { 03 final String pig = quot;length: 10quot;; 04 final String dog = quot;length: quot;+pig.length(); 05 System.out.println(quot;Animals are equal: quot; 06 + pig == dog); 07 } 08 }
  • 175. What Does It Print? (a) Animals are equal: true (b) Animals are equal: false (c) It varies (d) None of the above
  • 176. What Does It Print? (a) Animals are equal: true (b) Animals are equal: false (c) It varies (d) None of the above: false The + operator binds tighter than ==
  • 177. Another Look 01 public class AnimalFarm { 02 public static void main(String[] args) { 03 final String pig = quot;length: 10quot;; 04 final String dog = quot;length: quot;+pig.length(); 05 System.out.println(quot;Animals are equal: quot; 06 + pig == dog); 07 } 08 } System.out.println( (quot;Animals are equal: quot; + pig) == dog);
  • 178. How Do You Fix It? 01 public class AnimalFarm { 02 public static void main(String[] args) { 03 final String pig = quot;length: 10quot;; 04 final String dog = quot;length: quot;+pig.length(); 05 System.out.println(quot;Animals are equal: quot; 06 + (pig == dog)); 07 } 08 }
  • 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. 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. What Does It Print? (a) 0 (b) 3 (c) 14 (d) None of the above
  • 182. What Does It Print? (a) 0 (b) 3 (c) 14 (d) None of the above Operands are evaluated left to right. Postfix increment returns old value.
  • 183. Another Look 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 }
  • 184. Another Look 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 }
  • 185. Another Look 05 tricky += tricky++; (0) (tricky == 0)
  • 186. Another Look 05 tricky += tricky++; (0) (tricky == 0)
  • 187. Another Look 05 tricky += tricky++; 0 0 (tricky == 1)
  • 188. Another Look 05 tricky += tricky++; 0 0 (tricky == 1)
  • 189. Another Look 05 tricky += tricky++; 0 0 (tricky == 0)
  • 190. Another Look 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 }
  • 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. 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. 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. What Does It Print? (a) 0 (b) 1 (c) 2 (d) None of the above
  • 195. What Does It Print? (a) 0 (b) 1 (c) 2 (d) None of the above Not only is the program repulsive, but it has a bug
  • 196. Another Look 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 }
  • 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 } 11 12 private static boolean thirdElementIsThree(int[] a) { 13 return a.length >= 3 && a[2] == 3; 14 } 15 }
  • 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. 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. What Does It Print? (a) 4950 (b) 5050 (c) 9900 (d) None of the above
  • 201. What Does It Print? (a) 4950 (b) 5050 (c) 9900 (d) None of the above Lazy initialization + eager initialization = a mess
  • 202. Another Look 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 }
  • 203. Another Look 01 class Cache { 02 static { initIfNecessary(); } 03 private static int sum; 04 public static int getSum() { 05 initIfNecessary(); 06 return sum; 07 } 08 private static boolean initialized = false; // Ouch! 09 private static synchronized void initIfNecessary() { 10 if (!initialized) { 11 for (int i = 0; i < 100; i++) 12 sum += i; 13 initialized = true; 14 } 15 } 16 public static void main(String[] args) { 17 System.out.println(getSum()); 18 } 19 }
  • 204. How Do You Fix It? 01 class Cache { 02 private static final int SUM = computeSum(); 03 04 private static int computeSum() { 05 int result = 0; 06 for (int i = 0; i < 100; i++) 07 result += i; 08 return result; 09 } 10 11 public static int getSum() { 12 return SUM; 13 } 14 15 public static void main(String[] args) { 16 System.out.println(getSum()); 17 } 18 }
  • 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. 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]; 05 06 int i = Integer.MIN_VALUE; 07 // This loop iterates over all int values 08 do { 09 histogram[Math.abs(i) % MODULUS]++; 10 } while (i++ != Integer.MAX_VALUE); 11 12 for (int j = 0; j < MODULUS; j++) 13 System.out.print(histogram[j] + quot; quot;); 14 } 15 }
  • 207. What Does It Print? (a) 1431655765 1431655765 1431655765 (b) 1431655765 1431655766 1431655765 (c) Throws an exception (d) None of the above Hint: 232 / 3 = 1,431,655,765
  • 208. What Does It Print? (a) 1431655765 1431655765 1431655765 (b) 1431655765 1431655766 1431655765 (c) Throws an exception: array out of bounds (d) None of the above Math.abs doesn’t always return a nonnegative
  • 209. Another Look 01 public class Mod { 02 public static void main(String[] args) { 03 final int MODULUS = 3; 04 int[] histogram = new int[MODULUS]; 05 06 int i = Integer.MIN_VALUE; 07 // This loop iterates over all int values 08 do { 09 histogram[Math.abs(i) % MODULUS]++; 10 } while (i++ != Integer.MAX_VALUE); 11 12 for (int j = 0; j < MODULUS; j++) 13 System.out.println(histogram[j] + quot; quot;); 14 } 15 }
  • 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. 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. 35. “Package Deal” 01 package click; 02 public class CodeTalk { 03 public void doIt() { printMessage(); } 04 void printMessage() { System.out.println(quot;Clickquot;); } 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(quot;Hackquot;); } 06 } 07 public static void main(String[] args) { 08 new ClickIt().doIt(); 09 } 10 }
  • 213. What Does It Print? (a) Click (b) Hack (c) Won’t compile (d) None of the above
  • 214. What Does It Print? (a) Click (b) Hack (c) Won’t compile (d) None of the above There is no overriding in this program
  • 215. Another Look 01 package click; 02 public class CodeTalk { 03 public void doIt() { printMessage(); } 04 void printMessage() { System.out.println(quot;Clickquot;); } 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(quot;Hackquot;); } 06 } 07 public static void main(String[] args) { 08 new ClickIt().doIt(); 09 } 10 }
  • 216. How Do You Fix It? • If you want overriding • Make printMessage public or protected • Use @Override to ensure that you got overriding
  • 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. 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. What Does It Print? (a) true (b) false (c) It varies (d) None of the above
  • 220. What Does It Print? (a) true (b) false (c) It varies (d) None of the above: it deadlocks Intuition: You wouldn’t believe us if we told you.
  • 221. Another Look 01 public class Lazy { 02 private static boolean initialized = false; 03 static { 04 Thread t = new Thread(new Runnable() { 05 public void run() { 06 initialized = true; // Deadlocks here! 07 } 08 }); 09 t. start(); 10 try { 11 t.join(); 12 } catch (InterruptedException e) { 13 throw new AssertionError(e); 14 } 15 } 16 public static void main(String[] args) { 17 System.out.println(initialized); 18 } 19 }
  • 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. The Moral • Never use background threads in class initialization • Keep class initialization simple • Don’t code like my brother
  • 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); 04 05 boolean foundOdd = false; 06 for (Iterator<Integer> it=list.iterator();it.hasNext(); ) 07 foundOdd = foundOdd || isOdd(it.next()); 08 09 System.out.println(foundOdd); 10 } 11 12 private static boolean isOdd(int i) { 13 return (i & 1) != 0; 14 } 15 }
  • 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); 04 05 boolean foundOdd = false; 06 for (Iterator<Integer> it=list.iterator(); it.hasNext(); ) 07 foundOdd = foundOdd || isOdd(it.next()); 08 09 System.out.println(foundOdd); 10 } 11 12 private static boolean isOdd(int i) { 13 return (i & 1) != 0; (a) true 14 } (b) false 15 } (c) Throws exception (d) None of the above
  • 226. What Does It Print? (a) true (b) false (c) Throws exception (d) None of the above: Nothing— Infinite loop Conditional OR operator (||) short- circuits iterator
  • 227. Another Look public class OddBehavior { public static void main(String[] args) { List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2); boolean foundOdd = false; for (Iterator<Integer> it = list.iterator(); it.hasNext(); ) foundOdd = foundOdd || isOdd(it.next()); System.out.println(foundOdd); } private static boolean isOdd(int i) { return (i & 1) != 0; } }
  • 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. …But This Is Even Better public class OddBehavior { public static void main(String[] args) { List<Integer> list = Arrays.asList(-2, -1, 0, 1, 2); System.out.println(containsOdd(list)); } private static boolean containsOdd(List<Integer> list) { for (int i : list) if (isOdd(i)) return true; return false; } private static boolean isOdd(int i) { return (i & 1) != 0; } }
  • 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. 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 + quot; quot; + list); } }
  • 232. (a) [-3, -2, -1] [-3, -2, -1] What Does It Print? (b) [-3, -2, -1] [-2, 0, 2] (c) Throws exception (d) None of the above 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 + quot; quot; + list); } }
  • 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 above Autoboxing + overloading = confusion
  • 234. Another Look public class SetList { public static void main(String[] args) { Set<Integer> set = new LinkedHashSet<Integer>(); List<Integer> list = new ArrayList<Integer>(); for (int i = -3; i < 3; i++) { set.add(i); list.add(i); } for (int i = 0; i < 3; i++) { set.remove(i); list.remove(i); // List.remove(int) } System.out.println(set + quot; quot; + list); } }
  • 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 + quot; quot; + list); } }
  • 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. 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 + quot; quot; + TEN + quot; quot; + HUNDRED); } }
  • 238. What Does It Print? (a) ONE TEN HUNDRED (b) one ten hundred public enum PowerOfTen { (c) one ten 100 ONE(1), TEN(10), (d) None of the above 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 + quot; quot; + TEN + quot; quot; + HUNDRED); } }
  • 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. Another Look public enum PowerOfTen { ONE(1), TEN(10), HUNDRED(100) { // Creates static anonymous class @Override public String toString() { return Integer.toString(val); } }; private final int val; PowerOfTen(int val) { this.val = val; } @Override public String toString() { return name().toLowerCase(); } public static void main(String[] args) { System.out.println(ONE + quot; quot; + TEN + quot; quot; + HUNDRED); } }
  • 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 + quot; quot; + TEN + quot; quot; + HUNDRED); } }
  • 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. 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(quot;Pass quot;); } catch (Throwable ex) { System.out.print(quot;Fail quot;); } } } } }
  • 244. What Does It Print? (a) Pass Fail (b) Pass Pass import java.lang.reflect.*; (c) It varies (d) None of the above @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(quot;Pass quot;); } catch (Throwable ex) { System.out.print(quot;Fail quot;); } } } } }
  • 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, both subtle
  • 246. Another Look import java.lang.reflect.*; @interface Test { } // By default, annotations are discarded at runtime public 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(quot;Passquot;); } catch (Throwable ex) { System.out.print(quot;Fail quot;); } } } } }
  • 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(quot;Pass quot;); } catch (Throwable ex) { System.out.print(quot;Fail quot;); } } } } }
  • 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. 41. “What the Bleep?” public class Bleep { String name = quot;Bleepquot;; void setName(String name) { this.name = name; } void backgroundSetName() throws InterruptedException { Thread t = new Thread() { @Override public void run() { setName(quot;Blatquot;); } }; t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException { new Bleep().backgroundSetName(); } }
  • 250. What Does It Print? (a) Bleep (b) Blat public class Bleep { String name = quot;Bleepquot;; (c) It varies void setName(String name) { (d) None of the above this.name = name; } void backgroundSetName() throws InterruptedException { Thread t = new Thread() { @Override public void run() { setName(quot;Blatquot;); } }; t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException { new Bleep().backgroundSetName(); } }
  • 251. What Does It Print? (a) Bleep (b) Blat (c) It varies (d) None of the above Bleep.setName isn’t getting called
  • 252. Another Look public class Bleep { String name = quot;Bleepquot;; 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(quot;Blatquot;); } }; t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException { new Bleep().backgroundSetName(); } }
  • 253. How Do You Fix It? public class Bleep { String name = quot;Bleepquot;; void setName(String name) { this.name = name; } void backgroundSetName() throws InterruptedException { Thread t = new Thread(new Runnable() { public void run() { setName(quot;Blatquot;); } }); t.start(); t.join(); System.out.println(name); } public static void main(String[] args) throws InterruptedException { new Bleep().backgroundSetName(); } }
  • 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. 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. 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. 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. Another Look public class BeyondCompare { public static void main(String[] args) { Object o = new Integer(3); System.out.println(new Double(3).compareTo(o) == 0); } } // Interface Comparable was generified in release 5.0 public interface Comparable<T> { int compareTo(T t); // Was Object } public class Double extends Number implements Comparable<Double>
  • 259. How Do You Fix It? // Preserves 1.4 semantics public 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 problem public class BeyondCompare { public static void main(String[] args) { Double d = 3.0; System.out.println(Double.valueOf(3).compareTo(d) == 0); } }
  • 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. 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. 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. What Does It Print? (a) [1, 1, 2, 3, 5, 8, 13] (b) Throws exception (c) It varies: Depends on hashcode [[I@ad3ba4] (d) None of the above Arrays.asList only works on arrays of object refs
  • 264. Another Look public class Fibonacci { private static final int LENGTH = 7; public static void main(String[] args) { int[] fib = new int[LENGTH]; fib[0] = fib[1] = 1; // First 2 Fibonacci numbers for (int i = 2; i < LENGTH; i++) fib[i] = fib[i - 2] + fib[i - 1]; // Idiom only works for arrays of object references System.out.println(Arrays.asList(fib)); } }
  • 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. The Moral • Use varargs sparingly in your APIs > It can hide errors and cause confusion > This program wouldn't compile under 1.4 • Arrays.asList printing idiom is obsolete > use Arrays.toString instead > Prettier, safer, and more powerful • A full complement of array utilities added in 5.0 • equals, hashCode, toString for all array
  • 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 * doesn't represent a valid integer */ public static Integer parseInt(String s) { return (s == null) ? (Integer) null : Integer.parseInt(s); } public static void main(String[] args) { System.out.println(parseInt(quot;-1quot;) + quot; quot; + parseInt(null) + quot; quot; + parseInt(quot;1quot;)); } }
  • 268. (a) -1 null 1 What Does It Print? (b) -1 0 1 (c) Throws exception public 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 * doesn't represent a valid integer */ public static Integer parseInt(String s) { return (s == null) ? (Integer) null : Integer.parseInt(s); } public static void main(String[] args) { System.out.println(parseInt(quot;-1quot;) + quot; quot; + parseInt(null) + quot; quot; + parseInt(quot;1quot;)); } }
  • 269. What Does It Print? (a) -1 null 1 (b) -1 0 1 (c) Throws exception: NullPointerException (d) None of the above Program attempts to auto-unbox null
  • 270. Another Look public class Parsing { /** * Returns Integer corresponding to s, or null if s is null. * @throws NumberFormatException if s is nonnull and * doesn't represent a valid integer. */ public static Integer parseInt(String s) { return (s == null) ? // Mixed-type computation: Integer and int (Integer) null : Integer.parseInt(s); } public static void main(String[] args) { System.out.println(parseInt(quot;-1quot;) + quot; quot; + parseInt(null) + quot; quot; + parseInt(quot;1quot;)); } }
  • 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 * doesn't represent a valid integer. */ public static Integer parseInt(String s) { return (s == null) ? null : Integer.valueOf(s); } public static void main(String[] args) { System.out.println(parseInt(quot;-1quot;) + quot; quot; + parseInt(null) + quot; quot; + parseInt(quot;1quot;)); } }
  • 272. The Moral • Mixed-type computations are confusing • Especially true for ?: expressions • Avoid null where possible • Auto-unboxing and null are a dangerous mix
  • 274. Resources • Send more puzzles puzzlers@javapuzzles.com –
  • 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 aren't sure what a program • does, it probably doesn't do what you want it to