Effective Java™ Reloaded: This Time It's for Real

5 downloads 50614 Views 509KB Size Report
2. I am actively at work revising the book. It will be done later this year for sure. This talk has some of the new material. Effective Java Still Hasn't Been Reloaded, .
Effective Java™ Reloaded: This Time It’s for Real

Not

Joshua Bloch Chief Java Architect Google Inc. TS-2689 2007 JavaOneSM Conference | Session TS-2689 |

Disclaimer

Effective Java Still Hasn’t Been Reloaded, but I Do Have Plenty of Ammunition

I am actively at work revising the book. It will be done later this year for sure. This talk has some of the new material.

2007 JavaOneSM Conference | Session TS-2689 |

2

Topics Object Creation Generics Miscellania

(2 Sections) (6 Sections) (2 Sections)

2007 JavaOneSM Conference | Session TS-2689 |

3

Topics Object Creation Generics Miscellania

2007 JavaOneSM Conference | Session TS-2689 |

4

1. Static Factories Have Advantages Over Constructors (Old News) • Need not create a new object on each call • They have names • Allows multiple factories with same type signature

• Flexibility to return object of any subtype • But wait! There’s more…

2007 JavaOneSM Conference | Session TS-2689 |

5

New Static Factory Advantage: They Do Type Inference • Which looks better? • Map m = new HashMap(); • Map m = HashMap.newInstance();

• Regrettably HashMap has no such method (yet) • Until it does, you can write your own utility class

• Your generic classes can and should: 

public static HashMap newInstance() { return new HashMap(); } 2007 JavaOneSM Conference | Session TS-2689 |

6

2. Static Factories and Constructors Share a Problem • Ugly when they have many optional parameters • new NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate, 15 more optional params!);

• Telescoping signature pattern is a hack • NutritionFacts locoCola = new NutritionFacts(240, 8, 0, 0, 30, 28);

• Beans-style setters are not the answer! • Allows inconsistency, mandates mutability

2007 JavaOneSM Conference | Session TS-2689 |

7

The Solution: Builder Pattern • Builder constructor takes all required params • One setter for each optional parameter • Setters return the builder to allow for chaining

• One method to generate instance • Pattern emulates named optional parameters! NutritionFacts locoCola = new NutritionFacts.Builder(240, 8) .sodium(30).carbohydrate(28).build();

2007 JavaOneSM Conference | Session TS-2689 |

8

Builder Implementation Sketch public class NutritionFacts { public static class Builder { public Builder(int servingSize, int servings) { this.servingSize = servingSize; this.servings = servings; } public Builder calories(int val) { calories = val; return this; } ... // 15 more setters public NutritionFacts build() { return new NutritionFacts(this); }

}

} private NutritionFacts(Builder builder) { } 2007 JavaOneSM Conference | Session TS-2689 |

9

An Intriguing Possibility package java.util; public interface Builder { T build(); }

Much safer and more powerful than passing Class objects around and calling newInstance()

2007 JavaOneSM Conference | Session TS-2689 |

10

Topics Object Creation Generics Miscellania

2007 JavaOneSM Conference | Session TS-2689 |

11

1. Avoid Raw Types in New Code // Generic type: Good Collection coinCollection = new ArrayList(); coinCollection.add(new Stamp()); // Won’t compile ... for (Coin c : coinCollection) { ... } // Raw Type: Evil Collection coinCollection = new ArrayList(); coinCollection.add(new Stamp()); // Succeeds but should not ... for (Object o : coinCollection) { Coin c = (Coin) o; // Throws exception at runtime ... }

2007 JavaOneSM Conference | Session TS-2689 |

12

Don’t Ignore Compiler Warnings • If you’ve been using generics, you’ve seen lots • Understand each warning • Eliminate it if possible

• If you can’t eliminate a warning, suppress them @SuppressWarnings("unchecked") • But limit the scope as much as possible • Declare an extra variable if necessary

2007 JavaOneSM Conference | Session TS-2689 |

13

2. Use Bounded Wildcards to Increase Applicability of APIs // Method names are from the perspective of customer public interface Shop { T buy(); void sell(T myItem); void buy(int numToBuy, Collection myCollection); void sell(Collection myLot); } class Model { } class ModelPlane extends Model { } class ModelTrain extends Model { }

Thanks to Peter Sestoft for shop example 2007 JavaOneSM Conference | Session TS-2689 |

14

Works Fine If You Stick to One Type // Individual purchase and sale Shop modelPlaneShop = ... ; ModelPlane myPlane = modelPlaneShop.buy(); modelPlaneShop.sell(myPlane); // Bulk purchase and sale Collection myPlanes = ... ; modelPlaneShop.buy(5, myPlanes); modelPlaneShop.sell(myPlanes);

2007 JavaOneSM Conference | Session TS-2689 |

15

Simple Subtyping Works Fine // You can buy a model from a train shop Model myModel = modelTrainShop.buy(); // You can sell a model train to a model shop modelShop.sell(myTrain); public interface Shop { T buy(); void sell(T myItem); void buy(int numToBuy, Collection myCollection); void sell(Collection myLot); }

2007 JavaOneSM Conference | Session TS-2689 |

16

Collection Subtyping Doesn’t Work! // You can't buy a bunch of models from the train shop modelTrainShop.buy(5, myModelCollection); // Won't compile // You can't sell a bunch of trains to the model shop modelShop.sell(myTrains); // Won't compile public interface Shop { T buy(); void sell(T item); void buy(int numToBuy, Collection myCollection); void sell(Collection myLot); }

2007 JavaOneSM Conference | Session TS-2689 |

17

Bounded Wildcards to the Rescue public interface Shop { T buy(); void sell(T item); void buy(int numToBuy, Collection coll) { for (Object o : coll) remove(o); }

The rule: If a type variable appears only once in a method signature, use wildcard instead 2007 JavaOneSM Conference | Session TS-2689 |

22

It’s Usually Best to Avoid Bounded Wildcards in Return Types • They force client to deal with wildcards directly • Only library designers should have to think about wildcards

• Rarely, you do need to return wildcard type • For example, a read-only list of numbers List longer(List c1, List c2) { return c1.size() >= c2.size() ? c1 : c2; }

2007 JavaOneSM Conference | Session TS-2689 |

24

Don’t Overuse Wildcards (2) • In java.util.concurrent.ExecutorService public Future submit(Runnable task); • Intent: to show that Future always returned null • Result: minor pain for API users

• Correct idiom to indicate unused type parameter public Future submit(Runnable task); • Type Void is non-instantiable • Easier to use and clarifies intent

2007 JavaOneSM Conference | Session TS-2689 |

25

4. Pop Quiz: What’s Wrong With This Program? public static void rotate(List list) { if (list.size() == 0) return; list.add(list.remove(0)); }

2007 JavaOneSM Conference | Session TS-2689 |

26

Answer: It Won’t Compile public static void rotate(List list) { if (list.size() == 0) return; list.add(list.remove(0)); }

Rotate.java:6: cannot find symbol symbol : method add(java.lang.Object) location: interface java.util.List list.add(list.remove(0)); ^

2007 JavaOneSM Conference | Session TS-2689 |

27

Intuition Behind the Problem public static void rotate(List list) { if (list.size() == 0) return; list.add(list.remove(0)); }

remove and add are two distinct operations Invoking each method “captures” the wildcard type Type system doesn’t know captured types are identical

2007 JavaOneSM Conference | Session TS-2689 |

28

This Program Really Is Unsafe public class Rotate { List list; Rotate(List list) { this.list = list; } public void rotate() { if (list.size() == 0) return; list.add(list.remove(0)); } ... }

Another thread could set list field from List to List between remove and add 2007 JavaOneSM Conference | Session TS-2689 |

29

Solution: Control Wildcard-Capture public static void rotate(List list) { rotateHelper(list); } // Generic helper method captures wildcard once private static void rotateHelper(List list) { if (list.size() == 0) return; list.add(list.remove(0)); }

Now the list and the element have same type: E 2007 JavaOneSM Conference | Session TS-2689 |

30

5. Generics and Arrays Don’t Mix; Prefer Generics • Generic array creation error caused by • new T[SIZE], Set[SIZE], List[SIZE]

• Affects varargs (warning rather than error) • void foo(Class