SlideShare ist ein Scribd-Unternehmen logo
1 von 63
Java Puzzlers
Scraping the Bottom of The Barrel
Joshua Bloch and Jeremy Manson
May 10, 2011
Some people say seeing is believing...
4   Fraser 1908
5   Fraser 1908
6   Fraser 1908
7   Logvinenko 1999
8   Logvinenko 1999
9   Logvinenko 1999
10   Kitaoka 1998
11   Kitaoka 1998
12   Kitaoka 1998
And Now, in Code!

• Six NEW Java programming language puzzles
     – Short program with curious behavior
     – What does it print? (multiple choice)
     – The mystery revealed
     – How to fix the problem
     – The moral




13
1. “Time for a Change”

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



public class Change {
    public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
}




14
1. “A Change is Gonna Come”

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



import java.math.BigDecimal;

public class Change {
    public static void main(String args[]) {
        BigDecimal payment = new BigDecimal(2.00);
        BigDecimal cost = new BigDecimal(1.10);
        System.out.println(payment.subtract(cost));
    }
}

15
What Does It Print?

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


import java.math.BigDecimal;

public class Change {
    public static void main(String args[]) {
        BigDecimal payment = new BigDecimal(2.00);
        BigDecimal cost = new BigDecimal(1.10);
        System.out.println(payment.subtract(cost));
    }
}

16
What Does It Print?

(a) 0.9
(b) 0.90
(c) 0.8999999999999999
(d) None of the above
    0.899999999999999911182158029987476766109466552734375




We used the wrong BigDecimal constructor

17
Another Look

The specification says this:
 public BigDecimal(double val)
  Translates a double into a BigDecimal with the exact decimal
  representation of the double's binary floating-point value.


import java.math.BigDecimal;

public class Change {
    public static void main(String args[]) {
        BigDecimal payment = new BigDecimal(2.00);
        BigDecimal cost = new BigDecimal(1.10);
        System.out.println(payment.subtract(cost));
    }
}

18
How Do You Fix It?


          Prints 0.90




import java.math.BigDecimal;

public class Change {
    public static void main(String args[]) {
        BigDecimal payment = new BigDecimal("2.00");
        BigDecimal cost = new BigDecimal("1.10");
        System.out.println(payment.subtract(cost));
    }
}

19
The Moral

• Avoid float and double where exact answers are required
     – For example, when dealing with money
• Use BigDecimal, int, or long instead
• Use new BigDecimal(String), not new BigDecimal(double)
• BigDecimal.valueOf(double) is better, but not perfect;
  use it for non-constant values.
• For API designers
     – Make it easy to do the commonly correct thing
     – Make it possible to do exotic things




20
2. “Size Matters”

public class Size {
    private enum Sex { MALE, FEMALE }

     public static void main(String[] args) {
         System.out.print(size(new HashMap<Sex, Sex>()) + " ");
         System.out.print(size(new EnumMap<Sex, Sex>(Sex.class)));
     }

     private static int size(Map<Sex, Sex> map) {
         map.put(Sex.MALE,   Sex.FEMALE);
         map.put(Sex.FEMALE, Sex.MALE);
         map.put(Sex.MALE,   Sex.MALE);
         map.put(Sex.FEMALE, Sex.FEMALE);
         Set<Map.Entry<Sex, Sex>> set =
                 new HashSet<Map.Entry<Sex, Sex>>(map.entrySet());
         return set.size();
     }
}                                    Thanks to Chris Dennis, via Alex Miller

21
What Does It Print?                                       (a) 2 1
                                                          (b) 2 2
public class Size {                                       (c) 4 4
    private enum Sex { MALE, FEMALE }
                                                          (d) None of the above
     public static void main(String[] args) {
         System.out.print(size(new HashMap<Sex, Sex>()) + " ");
         System.out.print(size(new EnumMap<Sex, Sex>(Sex.class)));
     }

     private static int size(Map<Sex, Sex> map) {
         map.put(Sex.MALE,   Sex.FEMALE);
         map.put(Sex.FEMALE, Sex.MALE);
         map.put(Sex.MALE,   Sex.MALE);
         map.put(Sex.FEMALE, Sex.FEMALE);
         Set<Map.Entry<Sex, Sex>> set =
                 new HashSet<Map.Entry<Sex, Sex>>(map.entrySet());
         return set.size();
     }
}

22
What Does It Print?

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




Enumerating over entry sets works better for some Map implementations than others

23
Another Look
 EnumMap entrySet iterator repeatedly returns the same Entry :(
public class Size {
    private enum Sex { MALE, FEMALE }

     public static void main(String[] args) {
         System.out.print(size(new HashMap<Sex, Sex>()) + " ");
         System.out.print(size(new EnumMap<Sex, Sex>(Sex.class)));
     }

     private static int size(Map<Sex, Sex> map) {
         map.put(Sex.MALE,   Sex.FEMALE);
         map.put(Sex.FEMALE, Sex.MALE);
         map.put(Sex.MALE,   Sex.MALE);
         map.put(Sex.FEMALE, Sex.FEMALE);
         Set<Map.Entry<Sex, Sex>> set =
                 new HashSet<Map.Entry<Sex, Sex>>(map.entrySet());
         return set.size();
     }
}

24
WTF? Is this a bug?

• Perhaps, but it’s been around since 1997
     – Josh thought it was legal when he designed Collections
     – But the spec is, at best, ambiguous on this point
• Several Map implementations did this
     – IdentityHashMap, ConcurrentHashMap, EnumMap
     – ConcurrentHashMap was fixed a long time ago
• Happily, Android did not perpetuate this behavior




25
How Do You Fix It?
 Copy the entries and insert manually
                                                         Prints 2 2
public class Size {
    private enum Sex { MALE, FEMALE }

     public static void main(String[] args) {
         System.out.print(size(new HashMap<Sex, Sex>()) + " ");
         System.out.print(size(new EnumMap<Sex, Sex>(Sex.class)));
     }

     private static int size(Map<Sex, Sex> map) {
         map.put(Sex.MALE,   Sex.FEMALE);
         map.put(Sex.FEMALE, Sex.MALE);
         map.put(Sex.MALE,   Sex.MALE);
         map.put(Sex.FEMALE, Sex.FEMALE);
         Set<Map.Entry<Sex, Sex>> set = new HashSet<Map.Entry<Sex, Sex>>();
         for (Map.Entry<Sex, Sex> e : map.entrySet())
             set.add(new AbstractMap.SimpleImmutableEntry<Sex, Sex>(e));
         return set.size();
     }
}
26
The Moral

• Iterating over entrySet requires care
     – Entry may become invalid when Iterator advances
     – EnumMap and IdentityHashMap are the only JDK 6 Map implementations with this behavior
       • No Android Map implementations have this behavior
     – new HashSet<EntryType>(map.entrySet()) idiom fails in the face of this behavior
• For API designers
     – Don’t violate the principle of least astonishment
     – Don’t worsen your API to improve performance (unless you have no choice)
       • It may seem like a good idea at the time, but you’ll live to regret it




27
3. “The Match Game”

import java.util.regex.*;

public class Match {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("(aa|aab?)+");
        int count = 0;
        for(String s = ""; s.length() < 200; s += "a")
            if (p.matcher(s).matches())
                count++;
        System.out.println(count);
    }
}




28
What Does It Print?

import java.util.regex.*;

public class Match {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("(aa|aab?)+");
        int count = 0;
        for(String s = ""; s.length() < 200; s += "a")
            if (p.matcher(s).matches())
                count++;
        System.out.println(count);
    }
}
                                         (a) 99
                                         (b) 100
                                         (c) Throws an exception
                                         (d) None of the above

29
What Does It Print?

(a) 99
(b) 100
(c) Throws an exception
(d) None of the above: runs for >1015 years before printing anything; the Sun won’t
    last that long




The regular expression exhibits catastrophic backtracking

30
What is Catastrophic Backtracking?
 Here’s how matcher tests "aaaaa" for "(aa|aab?)+"
                                                     aa     fail

                                                     aab?
                                            aa              fail


                                           aab?
                                                      aa    fail
                                aa
                                                     aab?
                                                            fail


                                                     aa     fail
                               aab?
                                           aa        aab?
                                                            fail

                                           aab?
                                                            fail
                                                     aa
                                                     aab?
                                                            fail
This is exponential in length of string!   O(2n/2)
31
How Do You Fix It?

import java.util.regex.*;

public class Match {
    public static void main(String[] args) {                 Prints 99
        Pattern p = Pattern.compile("(aab?)+");
        int count = 0;
        for(String s = ""; s.length() < 200; s += "a")
            if (p.matcher(s).matches())
                count++;
        System.out.println(count);
    }
}




The regex "(aab?)+" matches exactly the same strings as
"(aa|aab?)+" but doesn’t exhibit catastrophic backtracking
32
The Moral

• To avoid catastrophic backtracking, ensure there’s only one way to match
  each string
• This goes way beyond Java
     – Affects most regular expression systems
     – Enables denial-of-service attacks
• Since regexes provide grouping information, they can’t just be compiled into
  optimal DFAs
     – Matcher must try all combinations of subpatterns
• Just because you can express it concisely doesn’t mean computation is fast




33
4. “That Sinking Feeling”

abstract class Sink<T> {
    abstract void add(T... elements);
    void addUnlessNull(T... elements) {
       for (T element : elements)
          if (element != null)
              add(element);
    }
}

public class StringSink extends Sink<String> {
    private final List<String> list = new ArrayList<String>();
    void add(String... elements) {
        list.addAll(Arrays.asList(elements));
    }
    public String toString() { return list.toString(); }
    public static void main(String[] args) {
        Sink<String> ss = new StringSink();
        ss.addUnlessNull("null", null);
        System.out.println(ss);
    }
}
34
What Does It Print?

abstract class Sink<T> {
    abstract void add(T... elements);
                                             (a)   [null]
    void addUnlessNull(T... elements) {      (b)   [null, null]
       for (T element : elements)
          if (element != null)
                                             (c)   NullPointerException
              add(element);                  (d)   None of the above
    }
}

public class StringSink extends Sink<String> {
    private final List<String> list = new ArrayList<String>();
    void add(String... elements) {
        list.addAll(Arrays.asList(elements));
    }
    public String toString() { return list.toString(); }
    public static void main(String[] args) {
        Sink<String> ss = new StringSink();
        ss.addUnlessNull("null", null);
        System.out.println(ss);
    }
}
35
What Does It Print?

(a) [null]
(b) [null, null]
(c) NullPointerException
(d) None of the above: ClassCastException




Varargs and generics don’t get along very well.

36
Another Look
Stack trace is very confusing!
abstract class Sink<T> {
    abstract void add(T... elements);
    void addUnlessNull(T... elements) {
       for (T element : elements)
          if (element != null)
              add(element);                    // (2)
    }
}

public class StringSink extends Sink<String> { // (3) Throws ClassCastException!
    private final List<String> list = new ArrayList<String>();
    void add(String... elements) {
        list.addAll(Arrays.asList(elements));
    }
    public String toString() { return list.toString(); }
    public static void main(String[] args) {
        Sink<String> ss = new StringSink();
        ss.addUnlessNull("null", null);         // (1)
        System.out.println(ss);
    }
}
37
What’s Going On Under the Covers?
Varargs, erasure, and a bridge method :(
abstract class Sink<T> {
    abstract void add(T... elements);    // Really Object[]
    void addUnlessNull(T... elements) { // Really Object[]
       for (T element : elements)
          if (element != null)
              add(element); // Creates Object[]
    }
}
public class StringSink extends Sink<String> {
    private final List<String> list = new ArrayList<String>();
    /** Synthetic bridge method – not present in source! */
    void add(Object[] a) { // Overrides abstract method
        add((String[]) a); // Really throws ClassCastException!
    }
    void add(String... elements) { list.addAll(Arrays.asList(elements)); }
    public String toString() { return list.toString(); }
    public static void main(String[] args) {
        Sink<String> ss = new StringSink();
        ss.addUnlessNull("null", null); // Creates String[]
        System.out.println(ss);
    }
}
38
The Compiler Tried to Warn You!

javac StringSink.java
Note: StringSink.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

And hopefully:
javac -Xlint:unchecked StringSink.java
StringSink.java:8: warning: [unchecked] unchecked generic array creation of
type T[] for varargs parameter
              add(element);
                 ^




39
How Do You Fix It?
Replace varargs and arrays with collections
abstract class Sink<T> {
    abstract void add(Collection<T> elements);
    void addUnlessNull(Collection<T> elements) {
       for (T element : elements)
          if (element != null)
                                                            Prints [null]
              add(Collections.singleton(element));
    }
}

public class StringSink extends Sink<String> {
    private final List<String> list = new ArrayList<String>();
    void add(Collection<String> elements) {
        list.addAll(elements); // No Arrays.asList
    }
    public String toString() { return list.toString(); }
    public static void main(String[] args) {
        Sink<String> ss = new StringSink();
        ss.addUnlessNull(Arrays.asList("null", null));
        System.out.println(ss);
    }
}
40
The Moral

• Varargs provide a leaky abstraction
     – Arrays leak through the veneer of varargs
• Generics and arrays don’t get along well
     – So generics and varargs don’t get along well
• Prefer collections to arrays
     – Especially in APIs
• Don't ignore compiler warnings
     – Ideally, eliminate them by fixing the code. If that’s not possible:
        • Prove that there’s no real problem and write down your proof in a comment
        • Disable the warning locally with a @SuppressWarnings annotation



41
5. “Glommer Pile”

public class Glommer<T> {
    String glom(Collection<?> objs) {
        String result = "";
        for (Object o : objs)
            result += o;
        return result;
    }

     int glom(List<Integer> ints) {
         int result = 0;
         for (int i : ints)
             result += i;
         return result;
     }
     public static void main(String args[]) {
         List<String> strings = Arrays.asList("1", "2", "3");
         System.out.println(new Glommer().glom(strings));
     }
}


42
What Does It Print?

public class Glommer<T> {                               (a) 6
    String glom(Collection<?> objs) {
        String result = "";
                                                        (b) 123
        for (Object o : objs)                           (c) Throws an exception
            result += o;
        return result;                                  (d) None of the above
    }

     int glom(List<Integer> ints) {
         int result = 0;
         for (int i : ints)
             result += i;
         return result;
     }
     public static void main(String args[]) {
         List<String> strings = Arrays.asList("1", "2", "3");
         System.out.println(new Glommer().glom(strings));
     }
}


43
What Does It Print?

(a) 6
(b) 123
(c) Throws an exception: ClassCastException
(d) None of the above




Raw types are dangerous

44
Another Look
Raw type discards all generic type information, causing incorrect overload resolution
public class Glommer<T> {
    String glom(Collection<?> objs) {
        String result = "";
        for (Object o : objs)
            result += o;
        return result;
    }

     int glom(List<Integer> ints) {
         int result = 0;
         for (int i : ints)
             result += i;
         return result;
     }
     public static void main(String args[]) {
         List<String> strings = Arrays.asList("1", "2", "3");
         System.out.println(new Glommer().glom(strings));
     }
}


45
The Compiler Tried to Warn You!

javac Glommer.java
Note: Glommer.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

And hopefully:

javac -Xlint:unchecked Glommer.java
Glommer.java:20: warning: [unchecked] unchecked call to
glom(List<java.lang.Integer>) as a member of the raw type Glommer
        System.out.println(new Glommer().glom(strings));
                                             ^




46
You Could Fix it Like This...
Specify a type parameter for Glommer
public class Glommer<T> {
    String glom(Collection<?> objs) {
        String result = "";
        for (Object o : objs)
            result += o;                            Prints 123
        return result;
    }

     int glom(List<Integer> ints) {
         int result = 0;
         for (int i : ints)
             result += i;
         return result;
     }
     public static void main(String args[]) {
         List<String> strings = Arrays.asList("1", "2", "3");
         System.out.println(new Glommer<Random>().glom(strings));
     }
}


47
Or you Could Fix it Like This...
Remove extraneous type parameter from Glommer
public class Glommer { // Look Ma, no type parameter!
    String glom(Collection<?> objs) {
        String result = "";
        for (Object o : objs)
            result += o;                           Prints   123
        return result;
    }

     int glom(List<Integer> ints) {
         int result = 0;
         for (int i : ints)
             result += i;
         return result;
     }
     public static void main(String args[]) {
         List<String> strings = Arrays.asList("1", "2", "3");
         System.out.println(new Glommer().glom(strings));
     }
}


48
But This is even better
Make Glommer a static utility class
public class Glommer {
    static String glom(Collection<?> objs) {
        String result = "";
        for (Object o : objs)
            result += o;                           Prints 123
        return result;
    }

     static int glom(List<Integer> ints) {
         int result = 0;
         for (int i : ints)
             result += i;
         return result;
     }
     public static void main(String args[]) {
         List<String> strings = Arrays.asList("1", "2", "3");
         System.out.println(glom(strings)); // No Glommer instance!
     }
}


49
The Moral

• Never use raw types in new code!
• Raw types lose all generic type information
     – Can break overload resolution
• Do not ignore compiler warnings, even when they’re indecipherable
     – Unchecked warnings mean automatically generated casts can fail at runtime




50
6. “It’s Elementary” (2004; 2010 remix)

public class Elementary {
    public static void main(String[] args) {
        System.out.print(12345 + 5432l);
        System.out.print(" ");
        System.out.print(01234 + 43210);
    }
}




51
What Does It Print?

public class Elementary {
    public static void main(String[] args) {
        System.out.print(12345 + 5432l);
        System.out.print(" ");
        System.out.print(01234 + 43210);
    }
}
                                       (a) 17777   44444
                                       (b) 17777   43878
                                       (c) 66666   44444
                                       (d) 66666   43878



52
What Does It Print?

(a) 17777 44444
(b) 17777 43878
(c) 66666 44444
(d) 66666 43878




Program doesn’t say what you think it does!
Also, leading zeros can cause trouble.

53
Another Look

public class Elementary {
    public static void main(String[] args) {
         System.out.print(12345 + 5432l);
         System.out.print(" ");
         System.out.print(01234 + 43210);
     }
}




1 - the digit one
l - the lowercase letter el
54
Another Look, Continued

public class Elementary {
    public static void main(String[] args) {
         System.out.print(12345 + 5432l);
         System.out.print(" ");
         System.out.print(01234 + 43210);
     }
}




01234 is an octal literal equal to 1,2348, or 668

55
How Do You Fix It?

public class Elementary {
    public static void main(String[] args) {
        System.out.print(12345 + 54321); // The digit 1
        System.out.print(" ");
        System.out.print( 1234 + 43210); // No leading 0
    }
}


                                         Prints 66666 44444




56
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 (l) as a variable name
     – Not this: List<String> l = ... ;
     – But this: List<String> list = ...;
• Never precede an int literal with 0 unless you actually want to express it in octal
     – When you use an octal literal, always add a comment expressing your intent




57
A Summary of the Traps

1. Use new BigDecimal(String), not new BigDecimal(double)
2. Don’t assume that Map.Entry objects in entrySet iteration are stable
     new HashSet<EntryType>(map.entrySet()) idiom fails for EnumMap, IdentityHashMap
3. Beware of catastrophic backtracking when writing regular expressions
4. Generics and arrays don’t mix–don’t ignore compiler warnings!
5. Never use raw types in new code–they lose all generic type information
6. Always use uppercase L for long literals; never use 0 to pad int literal




58
Lessons for API Designers

• Make it easy to do the commonly correct thing; possible to do exotic things
• Don’t violate the principle of least astonishment
• Don’t worsen your API to improve performance (unless you have no choice)




59
Conclusion

• Java platform is reasonably simple and elegant
     – But it has a few sharp corners—avoid them!
• Keep programs clear and simple
• If you aren’t sure what a program does, it probably doesn’t do what you want
• Use FindBugs and a good IDE
• Don’t code like my brother




60
Shameless Commerce Division

                              • 95 Puzzles
                              • 52 Illusions
                              • Tons of fun




61
Java Puzzlers
Scraping the Bottom of The Barrel

  Compliments, Marriage Proposals, Hot Tips:
     Hashtags: #io2011 #JavaPuzzlers
     Web:      http://goo.gl/sV0bg
  Complaints:   /dev/null
Java puzzlers scraping_the_bottom_of_the_barrel

Weitere ähnliche Inhalte

Was ist angesagt?

Using The Google Collections Library For Java
Using The Google Collections Library For JavaUsing The Google Collections Library For Java
Using The Google Collections Library For JavaGoogleTecTalks
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation streamRuslan Shevchenko
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheetDr. Volkan OBAN
 
peRm R group. Review of packages for r for market data downloading and analysis
peRm R group. Review of packages for r for market data downloading and analysispeRm R group. Review of packages for r for market data downloading and analysis
peRm R group. Review of packages for r for market data downloading and analysisVyacheslav Arbuzov
 
Beauty and the beast - Haskell on JVM
Beauty and the beast  - Haskell on JVMBeauty and the beast  - Haskell on JVM
Beauty and the beast - Haskell on JVMJarek Ratajski
 
A walk in graph databases v1.0
A walk in graph databases v1.0A walk in graph databases v1.0
A walk in graph databases v1.0Pierre De Wilde
 
Clojure: The Art of Abstraction
Clojure: The Art of AbstractionClojure: The Art of Abstraction
Clojure: The Art of AbstractionAlex Miller
 

Was ist angesagt? (8)

Using The Google Collections Library For Java
Using The Google Collections Library For JavaUsing The Google Collections Library For Java
Using The Google Collections Library For Java
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheet
 
peRm R group. Review of packages for r for market data downloading and analysis
peRm R group. Review of packages for r for market data downloading and analysispeRm R group. Review of packages for r for market data downloading and analysis
peRm R group. Review of packages for r for market data downloading and analysis
 
Beauty and the beast - Haskell on JVM
Beauty and the beast  - Haskell on JVMBeauty and the beast  - Haskell on JVM
Beauty and the beast - Haskell on JVM
 
Scala vs java 8
Scala vs java 8Scala vs java 8
Scala vs java 8
 
A walk in graph databases v1.0
A walk in graph databases v1.0A walk in graph databases v1.0
A walk in graph databases v1.0
 
Clojure: The Art of Abstraction
Clojure: The Art of AbstractionClojure: The Art of Abstraction
Clojure: The Art of Abstraction
 

Andere mochten auch

Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)Peter Antman
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency GotchasAlex Miller
 
Effective Java - Still Effective After All These Years
Effective Java - Still Effective After All These YearsEffective Java - Still Effective After All These Years
Effective Java - Still Effective After All These YearsMarakana Inc.
 
Effective java - concurrency
Effective java - concurrencyEffective java - concurrency
Effective java - concurrencyfeng lee
 
Beginning Object-Oriented JavaScript
Beginning Object-Oriented JavaScriptBeginning Object-Oriented JavaScript
Beginning Object-Oriented JavaScriptStoyan Stefanov
 

Andere mochten auch (6)

Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)Java 1.5 - whats new and modern patterns (2007)
Java 1.5 - whats new and modern patterns (2007)
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency Gotchas
 
Effective Java - Still Effective After All These Years
Effective Java - Still Effective After All These YearsEffective Java - Still Effective After All These Years
Effective Java - Still Effective After All These Years
 
Effective java - concurrency
Effective java - concurrencyEffective java - concurrency
Effective java - concurrency
 
Beginning Object-Oriented JavaScript
Beginning Object-Oriented JavaScriptBeginning Object-Oriented JavaScript
Beginning Object-Oriented JavaScript
 
Pollution
PollutionPollution
Pollution
 

Ähnlich wie Java puzzlers scraping_the_bottom_of_the_barrel

Java 8 Puzzlers [as presented at OSCON 2016]
Java 8 Puzzlers [as presented at  OSCON 2016]Java 8 Puzzlers [as presented at  OSCON 2016]
Java 8 Puzzlers [as presented at OSCON 2016]Baruch Sadogursky
 
Streams: The Good, The Bad And The Ugly
Streams: The Good, The Bad And The UglyStreams: The Good, The Bad And The Ugly
Streams: The Good, The Bad And The UglySimon Ritter
 
ภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐาน
ภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐานภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐาน
ภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐานNoppanon YourJust'one
 
MATLAB Questions and Answers.pdf
MATLAB Questions and Answers.pdfMATLAB Questions and Answers.pdf
MATLAB Questions and Answers.pdfahmed8651
 
Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3rsmuralirs
 
Stata cheat sheet: data processing
Stata cheat sheet: data processingStata cheat sheet: data processing
Stata cheat sheet: data processingTim Essam
 
An Intro To ES6
An Intro To ES6An Intro To ES6
An Intro To ES6FITC
 
Real Time Big Data Management
Real Time Big Data ManagementReal Time Big Data Management
Real Time Big Data ManagementAlbert Bifet
 
Introduction To Lisp
Introduction To LispIntroduction To Lisp
Introduction To Lispkyleburton
 
Why is Java relevant? New features of Java8
Why is Java relevant? New features of Java8 Why is Java relevant? New features of Java8
Why is Java relevant? New features of Java8 xshyamx
 
Best Java Problems and Solutions
Best Java Problems and SolutionsBest Java Problems and Solutions
Best Java Problems and SolutionsJava Projects
 
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?Henri Tremblay
 
Java Questions
Java QuestionsJava Questions
Java Questionsbindur87
 
Monads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevMonads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevJavaDayUA
 

Ähnlich wie Java puzzlers scraping_the_bottom_of_the_barrel (20)

Scala @ TomTom
Scala @ TomTomScala @ TomTom
Scala @ TomTom
 
Java 8 Puzzlers [as presented at OSCON 2016]
Java 8 Puzzlers [as presented at  OSCON 2016]Java 8 Puzzlers [as presented at  OSCON 2016]
Java 8 Puzzlers [as presented at OSCON 2016]
 
Streams: The Good, The Bad And The Ugly
Streams: The Good, The Bad And The UglyStreams: The Good, The Bad And The Ugly
Streams: The Good, The Bad And The Ugly
 
ภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐาน
ภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐานภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐาน
ภาษา C โปรแกรมย่อยและฟังก์ชันมาตรฐาน
 
MATLAB Questions and Answers.pdf
MATLAB Questions and Answers.pdfMATLAB Questions and Answers.pdf
MATLAB Questions and Answers.pdf
 
Scala vs Ruby
Scala vs RubyScala vs Ruby
Scala vs Ruby
 
Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3Java puzzle-1195101951317606-3
Java puzzle-1195101951317606-3
 
Stata cheat sheet: data processing
Stata cheat sheet: data processingStata cheat sheet: data processing
Stata cheat sheet: data processing
 
Data import-cheatsheet
Data import-cheatsheetData import-cheatsheet
Data import-cheatsheet
 
An Intro To ES6
An Intro To ES6An Intro To ES6
An Intro To ES6
 
Real Time Big Data Management
Real Time Big Data ManagementReal Time Big Data Management
Real Time Big Data Management
 
Introduction To Lisp
Introduction To LispIntroduction To Lisp
Introduction To Lisp
 
Gate-Cs 1996
Gate-Cs 1996Gate-Cs 1996
Gate-Cs 1996
 
Java exercise1
Java exercise1Java exercise1
Java exercise1
 
Why is Java relevant? New features of Java8
Why is Java relevant? New features of Java8 Why is Java relevant? New features of Java8
Why is Java relevant? New features of Java8
 
Best Java Problems and Solutions
Best Java Problems and SolutionsBest Java Problems and Solutions
Best Java Problems and Solutions
 
FSOFT - Test Java Exam
FSOFT - Test Java ExamFSOFT - Test Java Exam
FSOFT - Test Java Exam
 
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
 
Java Questions
Java QuestionsJava Questions
Java Questions
 
Monads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy DyagilevMonads and Monoids by Oleksiy Dyagilev
Monads and Monoids by Oleksiy Dyagilev
 

Kürzlich hochgeladen

Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 

Kürzlich hochgeladen (20)

Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 

Java puzzlers scraping_the_bottom_of_the_barrel

  • 1.
  • 2. Java Puzzlers Scraping the Bottom of The Barrel Joshua Bloch and Jeremy Manson May 10, 2011
  • 3. Some people say seeing is believing...
  • 4. 4 Fraser 1908
  • 5. 5 Fraser 1908
  • 6. 6 Fraser 1908
  • 7. 7 Logvinenko 1999
  • 8. 8 Logvinenko 1999
  • 9. 9 Logvinenko 1999
  • 10. 10 Kitaoka 1998
  • 11. 11 Kitaoka 1998
  • 12. 12 Kitaoka 1998
  • 13. And Now, in Code! • Six NEW Java programming language puzzles – Short program with curious behavior – What does it print? (multiple choice) – The mystery revealed – How to fix the problem – The moral 13
  • 14. 1. “Time for a Change” If you pay $2.00 for a gasket that costs $1.10, how much change do you get? public class Change { public static void main(String args[]) { System.out.println(2.00 - 1.10); } } 14
  • 15. 1. “A Change is Gonna Come” If you pay $2.00 for a gasket that costs $1.10, how much change do you get? import java.math.BigDecimal; public class Change { public static void main(String args[]) { BigDecimal payment = new BigDecimal(2.00); BigDecimal cost = new BigDecimal(1.10); System.out.println(payment.subtract(cost)); } } 15
  • 16. What Does It Print? (a) 0.9 (b) 0.90 (c) 0.8999999999999999 (d) None of the above import java.math.BigDecimal; public class Change { public static void main(String args[]) { BigDecimal payment = new BigDecimal(2.00); BigDecimal cost = new BigDecimal(1.10); System.out.println(payment.subtract(cost)); } } 16
  • 17. What Does It Print? (a) 0.9 (b) 0.90 (c) 0.8999999999999999 (d) None of the above 0.899999999999999911182158029987476766109466552734375 We used the wrong BigDecimal constructor 17
  • 18. Another Look The specification says this: public BigDecimal(double val) Translates a double into a BigDecimal with the exact decimal representation of the double's binary floating-point value. import java.math.BigDecimal; public class Change { public static void main(String args[]) { BigDecimal payment = new BigDecimal(2.00); BigDecimal cost = new BigDecimal(1.10); System.out.println(payment.subtract(cost)); } } 18
  • 19. How Do You Fix It? Prints 0.90 import java.math.BigDecimal; public class Change { public static void main(String args[]) { BigDecimal payment = new BigDecimal("2.00"); BigDecimal cost = new BigDecimal("1.10"); System.out.println(payment.subtract(cost)); } } 19
  • 20. The Moral • Avoid float and double where exact answers are required – For example, when dealing with money • Use BigDecimal, int, or long instead • Use new BigDecimal(String), not new BigDecimal(double) • BigDecimal.valueOf(double) is better, but not perfect; use it for non-constant values. • For API designers – Make it easy to do the commonly correct thing – Make it possible to do exotic things 20
  • 21. 2. “Size Matters” public class Size { private enum Sex { MALE, FEMALE } public static void main(String[] args) { System.out.print(size(new HashMap<Sex, Sex>()) + " "); System.out.print(size(new EnumMap<Sex, Sex>(Sex.class))); } private static int size(Map<Sex, Sex> map) { map.put(Sex.MALE, Sex.FEMALE); map.put(Sex.FEMALE, Sex.MALE); map.put(Sex.MALE, Sex.MALE); map.put(Sex.FEMALE, Sex.FEMALE); Set<Map.Entry<Sex, Sex>> set = new HashSet<Map.Entry<Sex, Sex>>(map.entrySet()); return set.size(); } } Thanks to Chris Dennis, via Alex Miller 21
  • 22. What Does It Print? (a) 2 1 (b) 2 2 public class Size { (c) 4 4 private enum Sex { MALE, FEMALE } (d) None of the above public static void main(String[] args) { System.out.print(size(new HashMap<Sex, Sex>()) + " "); System.out.print(size(new EnumMap<Sex, Sex>(Sex.class))); } private static int size(Map<Sex, Sex> map) { map.put(Sex.MALE, Sex.FEMALE); map.put(Sex.FEMALE, Sex.MALE); map.put(Sex.MALE, Sex.MALE); map.put(Sex.FEMALE, Sex.FEMALE); Set<Map.Entry<Sex, Sex>> set = new HashSet<Map.Entry<Sex, Sex>>(map.entrySet()); return set.size(); } } 22
  • 23. What Does It Print? (a) 2 1 (b) 2 2 (c) 4 4 (d) None of the above Enumerating over entry sets works better for some Map implementations than others 23
  • 24. Another Look EnumMap entrySet iterator repeatedly returns the same Entry :( public class Size { private enum Sex { MALE, FEMALE } public static void main(String[] args) { System.out.print(size(new HashMap<Sex, Sex>()) + " "); System.out.print(size(new EnumMap<Sex, Sex>(Sex.class))); } private static int size(Map<Sex, Sex> map) { map.put(Sex.MALE, Sex.FEMALE); map.put(Sex.FEMALE, Sex.MALE); map.put(Sex.MALE, Sex.MALE); map.put(Sex.FEMALE, Sex.FEMALE); Set<Map.Entry<Sex, Sex>> set = new HashSet<Map.Entry<Sex, Sex>>(map.entrySet()); return set.size(); } } 24
  • 25. WTF? Is this a bug? • Perhaps, but it’s been around since 1997 – Josh thought it was legal when he designed Collections – But the spec is, at best, ambiguous on this point • Several Map implementations did this – IdentityHashMap, ConcurrentHashMap, EnumMap – ConcurrentHashMap was fixed a long time ago • Happily, Android did not perpetuate this behavior 25
  • 26. How Do You Fix It? Copy the entries and insert manually Prints 2 2 public class Size { private enum Sex { MALE, FEMALE } public static void main(String[] args) { System.out.print(size(new HashMap<Sex, Sex>()) + " "); System.out.print(size(new EnumMap<Sex, Sex>(Sex.class))); } private static int size(Map<Sex, Sex> map) { map.put(Sex.MALE, Sex.FEMALE); map.put(Sex.FEMALE, Sex.MALE); map.put(Sex.MALE, Sex.MALE); map.put(Sex.FEMALE, Sex.FEMALE); Set<Map.Entry<Sex, Sex>> set = new HashSet<Map.Entry<Sex, Sex>>(); for (Map.Entry<Sex, Sex> e : map.entrySet()) set.add(new AbstractMap.SimpleImmutableEntry<Sex, Sex>(e)); return set.size(); } } 26
  • 27. The Moral • Iterating over entrySet requires care – Entry may become invalid when Iterator advances – EnumMap and IdentityHashMap are the only JDK 6 Map implementations with this behavior • No Android Map implementations have this behavior – new HashSet<EntryType>(map.entrySet()) idiom fails in the face of this behavior • For API designers – Don’t violate the principle of least astonishment – Don’t worsen your API to improve performance (unless you have no choice) • It may seem like a good idea at the time, but you’ll live to regret it 27
  • 28. 3. “The Match Game” import java.util.regex.*; public class Match { public static void main(String[] args) { Pattern p = Pattern.compile("(aa|aab?)+"); int count = 0; for(String s = ""; s.length() < 200; s += "a") if (p.matcher(s).matches()) count++; System.out.println(count); } } 28
  • 29. What Does It Print? import java.util.regex.*; public class Match { public static void main(String[] args) { Pattern p = Pattern.compile("(aa|aab?)+"); int count = 0; for(String s = ""; s.length() < 200; s += "a") if (p.matcher(s).matches()) count++; System.out.println(count); } } (a) 99 (b) 100 (c) Throws an exception (d) None of the above 29
  • 30. What Does It Print? (a) 99 (b) 100 (c) Throws an exception (d) None of the above: runs for >1015 years before printing anything; the Sun won’t last that long The regular expression exhibits catastrophic backtracking 30
  • 31. What is Catastrophic Backtracking? Here’s how matcher tests "aaaaa" for "(aa|aab?)+" aa fail aab? aa fail aab? aa fail aa aab? fail aa fail aab? aa aab? fail aab? fail aa aab? fail This is exponential in length of string! O(2n/2) 31
  • 32. How Do You Fix It? import java.util.regex.*; public class Match { public static void main(String[] args) { Prints 99 Pattern p = Pattern.compile("(aab?)+"); int count = 0; for(String s = ""; s.length() < 200; s += "a") if (p.matcher(s).matches()) count++; System.out.println(count); } } The regex "(aab?)+" matches exactly the same strings as "(aa|aab?)+" but doesn’t exhibit catastrophic backtracking 32
  • 33. The Moral • To avoid catastrophic backtracking, ensure there’s only one way to match each string • This goes way beyond Java – Affects most regular expression systems – Enables denial-of-service attacks • Since regexes provide grouping information, they can’t just be compiled into optimal DFAs – Matcher must try all combinations of subpatterns • Just because you can express it concisely doesn’t mean computation is fast 33
  • 34. 4. “That Sinking Feeling” abstract class Sink<T> { abstract void add(T... elements); void addUnlessNull(T... elements) { for (T element : elements) if (element != null) add(element); } } public class StringSink extends Sink<String> { private final List<String> list = new ArrayList<String>(); void add(String... elements) { list.addAll(Arrays.asList(elements)); } public String toString() { return list.toString(); } public static void main(String[] args) { Sink<String> ss = new StringSink(); ss.addUnlessNull("null", null); System.out.println(ss); } } 34
  • 35. What Does It Print? abstract class Sink<T> { abstract void add(T... elements); (a) [null] void addUnlessNull(T... elements) { (b) [null, null] for (T element : elements) if (element != null) (c) NullPointerException add(element); (d) None of the above } } public class StringSink extends Sink<String> { private final List<String> list = new ArrayList<String>(); void add(String... elements) { list.addAll(Arrays.asList(elements)); } public String toString() { return list.toString(); } public static void main(String[] args) { Sink<String> ss = new StringSink(); ss.addUnlessNull("null", null); System.out.println(ss); } } 35
  • 36. What Does It Print? (a) [null] (b) [null, null] (c) NullPointerException (d) None of the above: ClassCastException Varargs and generics don’t get along very well. 36
  • 37. Another Look Stack trace is very confusing! abstract class Sink<T> { abstract void add(T... elements); void addUnlessNull(T... elements) { for (T element : elements) if (element != null) add(element); // (2) } } public class StringSink extends Sink<String> { // (3) Throws ClassCastException! private final List<String> list = new ArrayList<String>(); void add(String... elements) { list.addAll(Arrays.asList(elements)); } public String toString() { return list.toString(); } public static void main(String[] args) { Sink<String> ss = new StringSink(); ss.addUnlessNull("null", null); // (1) System.out.println(ss); } } 37
  • 38. What’s Going On Under the Covers? Varargs, erasure, and a bridge method :( abstract class Sink<T> { abstract void add(T... elements); // Really Object[] void addUnlessNull(T... elements) { // Really Object[] for (T element : elements) if (element != null) add(element); // Creates Object[] } } public class StringSink extends Sink<String> { private final List<String> list = new ArrayList<String>(); /** Synthetic bridge method – not present in source! */ void add(Object[] a) { // Overrides abstract method add((String[]) a); // Really throws ClassCastException! } void add(String... elements) { list.addAll(Arrays.asList(elements)); } public String toString() { return list.toString(); } public static void main(String[] args) { Sink<String> ss = new StringSink(); ss.addUnlessNull("null", null); // Creates String[] System.out.println(ss); } } 38
  • 39. The Compiler Tried to Warn You! javac StringSink.java Note: StringSink.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. And hopefully: javac -Xlint:unchecked StringSink.java StringSink.java:8: warning: [unchecked] unchecked generic array creation of type T[] for varargs parameter add(element); ^ 39
  • 40. How Do You Fix It? Replace varargs and arrays with collections abstract class Sink<T> { abstract void add(Collection<T> elements); void addUnlessNull(Collection<T> elements) { for (T element : elements) if (element != null) Prints [null] add(Collections.singleton(element)); } } public class StringSink extends Sink<String> { private final List<String> list = new ArrayList<String>(); void add(Collection<String> elements) { list.addAll(elements); // No Arrays.asList } public String toString() { return list.toString(); } public static void main(String[] args) { Sink<String> ss = new StringSink(); ss.addUnlessNull(Arrays.asList("null", null)); System.out.println(ss); } } 40
  • 41. The Moral • Varargs provide a leaky abstraction – Arrays leak through the veneer of varargs • Generics and arrays don’t get along well – So generics and varargs don’t get along well • Prefer collections to arrays – Especially in APIs • Don't ignore compiler warnings – Ideally, eliminate them by fixing the code. If that’s not possible: • Prove that there’s no real problem and write down your proof in a comment • Disable the warning locally with a @SuppressWarnings annotation 41
  • 42. 5. “Glommer Pile” public class Glommer<T> { String glom(Collection<?> objs) { String result = ""; for (Object o : objs) result += o; return result; } int glom(List<Integer> ints) { int result = 0; for (int i : ints) result += i; return result; } public static void main(String args[]) { List<String> strings = Arrays.asList("1", "2", "3"); System.out.println(new Glommer().glom(strings)); } } 42
  • 43. What Does It Print? public class Glommer<T> { (a) 6 String glom(Collection<?> objs) { String result = ""; (b) 123 for (Object o : objs) (c) Throws an exception result += o; return result; (d) None of the above } int glom(List<Integer> ints) { int result = 0; for (int i : ints) result += i; return result; } public static void main(String args[]) { List<String> strings = Arrays.asList("1", "2", "3"); System.out.println(new Glommer().glom(strings)); } } 43
  • 44. What Does It Print? (a) 6 (b) 123 (c) Throws an exception: ClassCastException (d) None of the above Raw types are dangerous 44
  • 45. Another Look Raw type discards all generic type information, causing incorrect overload resolution public class Glommer<T> { String glom(Collection<?> objs) { String result = ""; for (Object o : objs) result += o; return result; } int glom(List<Integer> ints) { int result = 0; for (int i : ints) result += i; return result; } public static void main(String args[]) { List<String> strings = Arrays.asList("1", "2", "3"); System.out.println(new Glommer().glom(strings)); } } 45
  • 46. The Compiler Tried to Warn You! javac Glommer.java Note: Glommer.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. And hopefully: javac -Xlint:unchecked Glommer.java Glommer.java:20: warning: [unchecked] unchecked call to glom(List<java.lang.Integer>) as a member of the raw type Glommer System.out.println(new Glommer().glom(strings)); ^ 46
  • 47. You Could Fix it Like This... Specify a type parameter for Glommer public class Glommer<T> { String glom(Collection<?> objs) { String result = ""; for (Object o : objs) result += o; Prints 123 return result; } int glom(List<Integer> ints) { int result = 0; for (int i : ints) result += i; return result; } public static void main(String args[]) { List<String> strings = Arrays.asList("1", "2", "3"); System.out.println(new Glommer<Random>().glom(strings)); } } 47
  • 48. Or you Could Fix it Like This... Remove extraneous type parameter from Glommer public class Glommer { // Look Ma, no type parameter! String glom(Collection<?> objs) { String result = ""; for (Object o : objs) result += o; Prints 123 return result; } int glom(List<Integer> ints) { int result = 0; for (int i : ints) result += i; return result; } public static void main(String args[]) { List<String> strings = Arrays.asList("1", "2", "3"); System.out.println(new Glommer().glom(strings)); } } 48
  • 49. But This is even better Make Glommer a static utility class public class Glommer { static String glom(Collection<?> objs) { String result = ""; for (Object o : objs) result += o; Prints 123 return result; } static int glom(List<Integer> ints) { int result = 0; for (int i : ints) result += i; return result; } public static void main(String args[]) { List<String> strings = Arrays.asList("1", "2", "3"); System.out.println(glom(strings)); // No Glommer instance! } } 49
  • 50. The Moral • Never use raw types in new code! • Raw types lose all generic type information – Can break overload resolution • Do not ignore compiler warnings, even when they’re indecipherable – Unchecked warnings mean automatically generated casts can fail at runtime 50
  • 51. 6. “It’s Elementary” (2004; 2010 remix) public class Elementary { public static void main(String[] args) { System.out.print(12345 + 5432l); System.out.print(" "); System.out.print(01234 + 43210); } } 51
  • 52. What Does It Print? public class Elementary { public static void main(String[] args) { System.out.print(12345 + 5432l); System.out.print(" "); System.out.print(01234 + 43210); } } (a) 17777 44444 (b) 17777 43878 (c) 66666 44444 (d) 66666 43878 52
  • 53. What Does It Print? (a) 17777 44444 (b) 17777 43878 (c) 66666 44444 (d) 66666 43878 Program doesn’t say what you think it does! Also, leading zeros can cause trouble. 53
  • 54. Another Look public class Elementary { public static void main(String[] args) { System.out.print(12345 + 5432l); System.out.print(" "); System.out.print(01234 + 43210); } } 1 - the digit one l - the lowercase letter el 54
  • 55. Another Look, Continued public class Elementary { public static void main(String[] args) { System.out.print(12345 + 5432l); System.out.print(" "); System.out.print(01234 + 43210); } } 01234 is an octal literal equal to 1,2348, or 668 55
  • 56. How Do You Fix It? public class Elementary { public static void main(String[] args) { System.out.print(12345 + 54321); // The digit 1 System.out.print(" "); System.out.print( 1234 + 43210); // No leading 0 } } Prints 66666 44444 56
  • 57. 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 (l) as a variable name – Not this: List<String> l = ... ; – But this: List<String> list = ...; • Never precede an int literal with 0 unless you actually want to express it in octal – When you use an octal literal, always add a comment expressing your intent 57
  • 58. A Summary of the Traps 1. Use new BigDecimal(String), not new BigDecimal(double) 2. Don’t assume that Map.Entry objects in entrySet iteration are stable new HashSet<EntryType>(map.entrySet()) idiom fails for EnumMap, IdentityHashMap 3. Beware of catastrophic backtracking when writing regular expressions 4. Generics and arrays don’t mix–don’t ignore compiler warnings! 5. Never use raw types in new code–they lose all generic type information 6. Always use uppercase L for long literals; never use 0 to pad int literal 58
  • 59. Lessons for API Designers • Make it easy to do the commonly correct thing; possible to do exotic things • Don’t violate the principle of least astonishment • Don’t worsen your API to improve performance (unless you have no choice) 59
  • 60. Conclusion • Java platform is reasonably simple and elegant – But it has a few sharp corners—avoid them! • Keep programs clear and simple • If you aren’t sure what a program does, it probably doesn’t do what you want • Use FindBugs and a good IDE • Don’t code like my brother 60
  • 61. Shameless Commerce Division • 95 Puzzles • 52 Illusions • Tons of fun 61
  • 62. Java Puzzlers Scraping the Bottom of The Barrel Compliments, Marriage Proposals, Hot Tips: Hashtags: #io2011 #JavaPuzzlers Web: http://goo.gl/sV0bg Complaints: /dev/null