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