Effective Java Generics Spring 2013 Agenda n Material

  • Slides: 26
Download presentation
Effective Java: Generics Spring 2013

Effective Java: Generics Spring 2013

Agenda n Material From Joshua Bloch n n Cover Items 23 -29 n n

Agenda n Material From Joshua Bloch n n Cover Items 23 -29 n n “Generics” Chapter Bottom Line: n n n 2 Effective Java: Programming Language Guide Generics are safer than raw types But generics are also more complex Raw types are allowed for backwards compatibility Generics

Item 23: Don’t Use Raw Types in New Code n n A class (interface)

Item 23: Don’t Use Raw Types in New Code n n A class (interface) with one or more type parameters is a generic class (interface) Examples: n n n List is a raw type List<E> is a generic interface List<String> is a parameterized type n 3 String is the actual type parameter corresponding to E Generics

Example: Replacing raw types // Now a raw collection type – don’t do this

Example: Replacing raw types // Now a raw collection type – don’t do this private final Collection stamps = …; // Contains only Stamps // Erroneous insertion of coin into stamp collection stamps. add(new Coin(…)); // Oops! We’re set up for Class. Cast. Exception later // Parameterized collection type - typesafe private final Collection<Stamp> stamps = …; stamps. add(new Coin(…)); // result is instead a compile time error, which is good // Now a raw iterator type – don’t do this! for (Iterator I = stamps. iterator(); i. has. Next(); ) { Stamp s = (Stamp) i. next(); // Throws Class. Cast. Exception …// Do something with the stamp } // for-each loop over parameterized collection – typesafe for (Stamp s: stamps) { // No (explicit) cast …// Do something with the stamp } 4 Generics

Example: Mixing generic and raw types // Uses raw type (List) – fails at

Example: Mixing generic and raw types // Uses raw type (List) – fails at runtime public static void main(String[] args) { List<String> strings = new Array. List<String>(); unsafe. Add(strings, new Integer(42)); String s = strings. get(0); //Exception from compiler generated cast } // note use of raw types private static void unsafe. Add(List list, Object o) { list. add(o); } // There is a compile time warning: Test. java: 10: warning: unchecked call to add(E) in raw type List list. add(o); ^ // If we ignore the warning, and run the program, we get a Class. Cast. Exception // where the compiler inserted the cast // If we try the following, it won’t compile (see Item 25) private static void unsafe. Add( List<Object> list, Object o) { list. add(o); } 5 Generics

Example: Using Wildcards // Use of raw type for unknown element type – don’t

Example: Using Wildcards // Use of raw type for unknown element type – don’t do this! static int num. Elements. In. Common. Set (Set s 1, Set s 2) { int result = 0; for (Object o 1: s 1) { if (s 2. contains(o 1)) result ++; } return result; } // Unbounded wildcard type – typesafe and flexible static int num. Elements. In. Common. Set (Set<? > s 1, Set<? > s 2) { int result = 0; for (Object o 1: s 1) { if (s 2. contains(o 1)) result ++; } return result; } // We’ll revisit this type of example in Item 27 6 Generics

Example: Using Wildcards // Do the question marks really buy you anything? // Answer:

Example: Using Wildcards // Do the question marks really buy you anything? // Answer: Wildcard is typesafe, // because you can’t add *anything* (except null) to Collection<? > // Two exceptions: Raw types ok in 1) Class Literals: List. class, not List<String>. class 2) instanceof operator if (o instanceof Set) { // raw type ok Set<? > m = (Set<? >) o; // Wildcard type // Why the exceptions? Compatibility with old Java 7 Generics

Terminology Term Parameterized type Actual type parameter Generic type Formal type parameter Unbounded wildcard

Terminology Term Parameterized type Actual type parameter Generic type Formal type parameter Unbounded wildcard type Raw type Bounded type parameter Recursive type bound Bounded wildcard type Generic method Type token 8 Example Item List<String> Item 23 String Item 23 List<E> Items 23, 26 E Item 23 List<? > Item 23 List Item 23 <E extends Number> Item 26 <T extends Comparable<T>> Item 27 List<? extends Number> Item 28 static <E> List<E> as. List(E[] a) Item 27 String. class Item 29 Generics

Item 24: Eliminate Unchecked Warnings n Generics result in many compiler warnings n n

Item 24: Eliminate Unchecked Warnings n Generics result in many compiler warnings n n Eliminate them As a last resort, suppress the warnings n Do so as at local a level as possible n n n Options are class down to local declaration Use the @Suppress. Warnings annotation Some are easy: Set<Lark> exaltation = new Hash. Set(); // warning Set<Lark> exaltation = new Hash. Set <Lark>(); // no warning 9 Generics

Example: Suppressing Warnings public <T> T[] to. Array (T[] a) { if (a. length

Example: Suppressing Warnings public <T> T[] to. Array (T[] a) { if (a. length < size) return (T[]) Arrays. copy. Of(elements, size, a. get. Class()); System. arraycopy(elements, 0, a, 0, size); if (a. length > size) a[size] = null; return a; } n The compiler generates a warning: Array. List. java: 305: warning [unchecked] unchecked cast found : Object[], required T[] return (T[]) Arrays. copy. Of(elements, size, a. get. Class()); n Suppressing the warning: if (a. length < size) { // This cast is correct because the array we’re creating // is of the same type as the one passed in, which is T[] @Suppress. Warnings(“unchecked”) T[] result = (T[]) Arrays. copy. Of(elements, size, a. get. Class()); return result; } 10 Generics

Item 25: Prefer Lists to Arrays n Lists play well with generics n n

Item 25: Prefer Lists to Arrays n Lists play well with generics n n n Generic array creation not typesafe (hence illegal) No new List<E>[], new List<String>[] , or new E[] Arrays are covariant, Generics are Invariant n If Sub is a subtype of Super n n n Arrays are reified; Generics are erased n 11 Then Sub[] is a subtype of Super[] But List<Sub> is not a subtype of List<Super> Generics are compile time only Generics

Example: Covariance vs. Invariance // Fails at runtime Object[] object. Array = new Long[1];

Example: Covariance vs. Invariance // Fails at runtime Object[] object. Array = new Long[1]; object. Array[0] = “I don’t fit in!”; // Throws Array. Store. Exception // Won’t compile List<Object> o 1 = new Array. List<Long>(); o 1. add(“I don’t fit in!”); // Incompatible types 12 n Not compiling is better than a runtime exception. n This is basically an argument for why invariance is preferable to covariance for generics. n Later, we’ll see how to relax this. Generics

Example: Illustrating type (non) safety // Why generic array creation is illegal – won’t

Example: Illustrating type (non) safety // Why generic array creation is illegal – won’t compile 1) List<String>[] string. Lists = new List<String>[1]; // won’t compile 2) List<Integer> int. List = Arrays. as. List(42); 3) Object[] objects = string. Lists; 4) Objects[0] = int. List; 5) String s = string. Lists[0]. get(0); // compiler generated cast to String Suppose 1) compiled (it won’t) 2) Creates and initializes a List<Integer> with one element 3) Stores the List<String> object into an Object array variable, note, this is legal because arrays are covariant 4) Stores the List<Integer> into the sole element of the Object array this succeeds because generics are implemented by erasure. The runtime type is simply List[], so there is no exception 5) Now, we’ve stored a List<Integer> instance into an array that is declared to hold only List<String> instances. So, we get a Class. Cast. Exception 13 Generics

Example: Reduction Function // Reduction without generics, and with concurrency flaw! static Object reduce(List

Example: Reduction Function // Reduction without generics, and with concurrency flaw! static Object reduce(List list, Function f, Object init. Val) { synchronized (list) { Object result = init. Val; for (Object o: list) result = f. apply(result, o); // alien method call return result; } } interface Function { Object apply (Object arg 1, Object arg 2); } n n 14 Flaw: Calls alien method from synchronized region Flaw: Doesn’t use generics Generics

Example Continued // Reduction without generics or concurrency flaw static Object reduce(List list, Function

Example Continued // Reduction without generics or concurrency flaw static Object reduce(List list, Function f, Object init. Val) { Object[] snapshot = list. to. Array(); // Locks list internally Object result = init. Val; for (Object o: snapshot) result = f. apply(result, o); return result; } } n 15 Flaw: Still doesn’t use generics Generics

Example Continued // Naïve generic version of reduction – won’t compile static <E> E

Example Continued // Naïve generic version of reduction – won’t compile static <E> E reduce(List <E> list, Function <E> f, E init. Val) { // E[] snapshot = list. to. Array(); // Won’t compile E[] snapshot = (E[]) list. to. Array(); // Still generates a warning E result = init. Val; for (E e: snapshot) result = f. apply(result, e); return result; } } // Generic interface Function<T> { T apply (T arg 1, T arg 2); } n Flaw: Won’t compile without cast n Flaw: Cast still results in warning (that needs to be suppressed) Flaw: Possible (with minor variations) to get Class. Cast. Exception at runtime Generics 16 n

Example: Using Lists instead of Arrays // List-based generic reduction static <E> E reduce(List

Example: Using Lists instead of Arrays // List-based generic reduction static <E> E reduce(List <E> list, Function <E> f, E init. Val) { List <E> snapshot; synchronized (list) { snapshot = new Array. List<E>(list); } } n 17 E result = init. Val; for (E e: snapshot) result = f. apply(result, e); return result; } Bonus: No possibility of Class. Cast. Exception at runtime Generics

Item 26: Favor Generic Types n Parameterize collection declarations n n Implementer has to

Item 26: Favor Generic Types n Parameterize collection declarations n n Implementer has to work harder n n Use the generic types But clients have type safety Stack example: How to support this? public static void main (String[] args) { Stack<String> stack = new Stack<String>(); for (String arg: args) { stack. push(arg); } while (!stack. is. Empty()) { …stack. pop()…} } 18 Generics

Example: Converting collection to generics public class Stack { // Original Version – no

Example: Converting collection to generics public class Stack { // Original Version – no generics private Object [] elements; private int size = 0; private static final int CAP = 16; public Stack() { elements = new Object [CAP]; } public void push( Object e ) { ensure. Capacity(); elements [size++] = e; } public Object pop() { if (size == 0) { throw new ISE(…); } Object result = elements [--size]; elements[size] = null; return result; } // remainder of Stack omitted – See Bloch 19 Generics

Example: Converting collection to generics public class Stack <E> { private E [] elements;

Example: Converting collection to generics public class Stack <E> { private E [] elements; private int size = 0; private static final int CAP = 16; // First cut at generics – won’t work // Alternate 2: Leave as Object public Stack() { elements = new E [CAP]; } // error; generic array creation // Alternate 1: = (E[]) new Object [CAP]; } // warning // @Suppress. Warning(“unchecked”) // public Stack() { elements = (E[]) new Object [CAP]; } // warning suppressed public void push( E e ) { ensure. Capacity(); elements [size++] = e; } public E pop() { if (size == 0) { throw new ISE(…); } E result = elements [--size]; // Error for Alternate 2; also cast and suppress warning elements[size] = null; return result; } 20 Generics

Item 27: Favor Generic Methods n Just as classes benefit from generics n n

Item 27: Favor Generic Methods n Just as classes benefit from generics n n 21 So do methods Writing generic methods is similar to writing generic types Generics

Example: Generic method // Uses raw types – unacceptable! (Item 23) public static Set

Example: Generic method // Uses raw types – unacceptable! (Item 23) public static Set union (Set s 1, Set s 2) { Set result = new Hash. Set(s 1); // Generates a warning result. add. All(s 2); // Generates a warning return result; } // Generic method public static <E> Set <E> union (Set <E> s 1, Set <E> s 2) { Set <E> result = new Hash. Set <E> (s 1); result. add. All(s 2); return result; } // The first <E> is the type parameter list // Example from the java. util. Collection // The generics can get a bit redundant… Map <String, List<String>> anagrams = new Hash. Map<String, List<String>>(); 22 Generics

Example: Recursive Type Bound // Returns the maximum value in a list – uses

Example: Recursive Type Bound // Returns the maximum value in a list – uses recursive type bound public static <T extends Comparable<T>> T max (List <T> list) { Iterator <T> i = list. iterator(); T result = i. next(); while (i. has. Next()) { T t = i. next(); // Note: no need for a cast if (t. compare. To(result) > 0) result = t; } return result; } Questions n n n 23 What happens if the list is empty? What about null values in list? What does a contract look like for this method? Note the type parameter: <T extends Comparable<T>> Note the return type: T Generics

Item 28: Use bounded wildcards to increase API Flexibility public class Stack <E> {

Item 28: Use bounded wildcards to increase API Flexibility public class Stack <E> { public Stack() public void push( E e ) public E pop() public boolean is. Empty() } // First cut at generics – won’t work // push. All method without a wildcard type – deficient! public void push. All( Iterable<E> src) { for (E e : src) { push(e); } } // wildcard type for parameter that serves as an E producer public void push. All( Iterable<? extends E> src) { for (E e : src) { push(e); } } // wildcard type for parameter that serves as an E consumer public void pop. All ( Collection<? super E> dst) { while (!is. Empty()) { dst. add(pop()); } } 24 Generics

The PECS mnemonic // PECS – producer extends, consumer super // Recall earlier example

The PECS mnemonic // PECS – producer extends, consumer super // Recall earlier example public static <E> Set <E> union (Set <E> s 1, Set <E> s 2) // Are parameters consumers or producers? ( Producers, so, extend) public static <E> Set <E> union (Set <? extends E> s 1, Set <? extends E> s 2) // Note that return type should still be Set<E>, not Set <? extends E> // otherwise, clients will have to use wildcards… Set<Integer> integers = … Set<Double> doublse = … Set<Number> numbers = union ( integers, doubles); // compiler error Set<Number> numbers = union. <Number> ( integers, doubles); // type parameter works // max example public static <T extends Comparable<T>> T max (List <T> list ) // original public static <T extends Comparable<? super T>> T max (List<? extends T> list) // PECS 25 Generics

Item 29: Consider typesafe heterogeneous Containers // Typesafe heterogeneous container pattern – implementation public

Item 29: Consider typesafe heterogeneous Containers // Typesafe heterogeneous container pattern – implementation public class Favorites private Map<Class<? >, Object> favorites = new Hash. Map(<Class<? >, Object>(); public <T> void put. Favorite(Class<T> type, T instance) { if (type == null) { throw new NPE… } favorites. put (type, instance); } public <T> T get. Favorite(Class<T> type) { return type. cast(favorites. get(type)); } // Fairly subtle stuff… 26 Generics