Effective Java: Generics - PowerPoint PPT Presentation

1 / 25
About This Presentation
Title:

Effective Java: Generics

Description:

String s = strings.get(0); //Exception from compiler generated cast // note use of raw types ... { return type.cast(favorites.get(type)); // Fairly subtle stuff... – PowerPoint PPT presentation

Number of Views:1054
Avg rating:5.0/5.0
Slides: 26
Provided by: richardb45
Category:

less

Transcript and Presenter's Notes

Title: Effective Java: Generics


1
Effective Java Generics
  • Last Updated Spring 2009

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

3
Item 23 Dont Use Raw Types in New Code
  • A class (interface) with one or more type
    parameters is a generic class (interface)
  • Examples
  • List is a raw type
  • ListltEgt is a generic interface
  • ListltStringgt is a parameterized type
  • String is the actual type parameter corresponding
    to E

4
Example Replacing raw types
  • // Now a raw collection type dont do this
  • private final Collection stamps //
    Contains only Stamps
  • // Erroneous insertion of coin into stamp
    collection
  • stamps.add(new Coin()) // Oops! Were set
    up for ClassCastException later
  • // Parameterized collection type - typesafe
  • private final CollectionltStampgt stamps
  • stamps.add(new Coin()) // result is
    instead a compile time error, which is good
  • // Now a raw iterator type dont do this!
  • for (Iterator I stamps.iterator()
    i.hasNext() )
  • Stamp s (Stamp) i.next() // Throws
    ClassCastException
  • // Do something with the stamp
  • // for-each loop over parameterized collection
    typesafe
  • for (Stamp s stamps) // No cast
  • // Do something with the stamp

5
Example Mixing generic and raw types
  • // Uses raw type (List) fails at runtime
  • public static void main(String args)
  • ListltStringgt strings new
    ArrayListltStringgt()
  • unsafeAdd(strings, new Integer(42))
  • String s strings.get(0) //Exception
    from compiler generated cast
  • // note use of raw types
  • private static void unsafeAdd(List list,
    Object o)
  • list.add(o)
  • // There is a compile time warning
  • Test.java10 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 ClassCastException
  • // where the compiler inserted the cast
  • // If we try the following, it wont compile (see
    Item 25)
  • private static void unsafeAdd( ListltObjectgt
    list, Object o) list.add(o)

6
Example Using Wildcards
  • // Use of raw type for unknown element type
    dont do this!
  • static int numElementsInCommonSet (Set s1, Set
    s2)
  • int result 0
  • for (Object o1 s1)
  • if (s2.contains(o1)) result
  • return result
  • // Unbounded wildcard type typesafe and
    flexible
  • static int numElementsInCommonSet (Setlt?gt s1,
    Setlt?gt s2)
  • int result 0
  • for (Object o1 s1)
  • if (s2.contains(o1)) result
  • return result
  • // Well revisit this type of example in Item 27

7
Example Using Wildcards
  • // Do the question marks really buy you anything?
  • // Answer Wildcard is typesafe,
  • // because you cant add anything (except null)
    to Collectionlt?gt
  • // Two exceptions Raw types ok in
  • Class Literals List.class, not
    ListltStringgt.class
  • instanceof operator
  • if (o instanceof Set) // raw type ok
  • Setlt?gt m (Setlt?gt) o // Wildcard type
  • // Why the exceptions? Compatibility with old
    Java

8
Item 24 Eliminate Unchecked Warnings
  • Generics result in many compiler warnings
  • Eliminate them
  • As a last resort, suppress the warnings
  • Do so as at local a level as possible
  • Options are class down to local declaration
  • Use the _at_SuppressWarnings annotation
  • Some are easy
  • SetltLarkgt exaltation new HashSet()
    // warning
  • SetltLarkgt exaltation new HashSet ltLarkgt()
    // no warning

9
Example Suppressing Warnings
  • public ltTgt T to Array (T a)
  • if (a.length lt size)
  • return (T) Arrays.copyOf(elements, size,
    a.getClass())
  • System.arraycopy(elements, 0, a, 0, size)
  • if (a.length gt size) a.size null
  • return a
  • The compiler generates a warning
  • ArrayList.java305 warning unchecked
    unchecked cast
  • found Object, required T
  • return (T) Arrays.copyOf(elements, size,
    a.getClass())
  • Suppressing the warning
  • if (a.length lt size)
  • // This cast is correct because the array
    were creating
  • // is of the same type as the one passed in,
    which is T
  • _at_SuppressWarnings(unchecked)
  • T result (T) Arrays.copyOf(elements,
    size, a.getClass())
  • return result

10
Item 25 Prefer Lists to Arrays
  • Lists play well with generics
  • Generic array creation not typesafe (hence
    illegal)
  • No new ListltEgt, new ListltStringgt , or new E
  • Arrays are covariant, Generics are Invariant
  • If Sub is a subtype of Super
  • Then Sub is a subtype of Super
  • But ListltSubgt is not a subtype of ListltSupergt
  • Arrays are reified Generics are erased
  • Generics are compile time only

11
Example Covariance vs. Invariance
  • // Fails at runtime
  • Object objectArray new Long1
  • objectArray0 I dont fit in! //
    Throws ArrayStoreException
  • // Wont compile
  • ListltObjectgt o1 new ArrayListltLonggt()
  • o1.add(I dont fit in!)
    // Incompatible types
  • Not compiling is better than a runtime exception.
  • This is basically an argument for why invariance
    is preferable to covariance for generics.
  • Later, well see how to relax this.

12
Example Illustrating type (non) safety
  • // Why generic array creation is illegal wont
    compile
  • 1) ListltStringgt stringLists new
    ListltStringgt1 // wont compile
  • 2) ListltIntegergt intList Arrays.asList(42)
  • 3) Object objects stringLists
  • 4) Objects0 intList
  • 5) String s stringLists0.get(0) //
    compiler generated cast to String
  • Suppose 1) compiled (it wont)
  • 2) Creates and initializes a ListltIntegergt with
    one element
  • 3) Stores the ListltStringgt object into an Object
    array variable,
  • note, this is legal because arrays are
    covariant
  • 4) Stores the ListltIntegergt 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, weve stored a ListltIntegergt instance
    into an array that is declared
  • to hold only ListltStringgt instances. So, we
    get a ClassCastException

13
Example Reduction Function
  • // Reduction without generics, and with
    concurrency flaw!
  • static Object reduce(List list, Function f,
    Object initVal)
  • synchronized (list)
  • Object result initVal
  • for (Object o list)
  • result f.apply(result, o)
  • interface Function
  • Object apply (Object arg1, Object arg2)
  • Flaw Calls alien method from synchronized
    region
  • Flaw Doesnt use generics

14
Example Continued
  • // Reduction without generics or concurrency flaw
  • static Object reduce(List list, Function f,
    Object initVal)
  • Object snapshot list.toArray() // Locks
    list internally
  • Object result initVal
  • for (Object o snapshot)
  • result f.apply(result, o)
  • Flaw Still doesnt use generics

15
Example Continued
  • // Naïve generic version of reduction wont
    compile
  • static ltEgt E reduce(List ltEgt list, Function ltEgt
    f, E initVal)
  • // E snapshot list.toArray() // Wont
    compile
  • E snapshot (E) list.toArray() // Still
    generates a warning
  • E result initVal
  • for (E e snapshot)
  • result f.apply(result, e)
  • // Generic interface
  • interface FunctionltTgt
  • T apply (T arg1, T arg2)
  • Flaw Wont compile without cast
  • Flaw Cast still results in warning (that needs
    to be suppressed)
  • Flaw Possible (with minor variations) to get
    ClassCastException at runtime

16
Example Using Lists instead of Arrays
  • // List-based generic reduction
  • static ltEgt E reduce(List ltEgt list, Function ltEgt
    f, E initVal)
  • List ltEgt snapshot
  • synchronized (list)
  • snapshot new ArrayListltEgt(list)
  • E result initVal
  • for (E e snapshot)
  • result f.apply(result, e)
  • Bonus No possibility of ClassCastException at
    runtime

17
Item 26 Favor Generic Types
  • Parameterize collection declarations
  • Use the generic types
  • Implementer has to work harder
  • But clients have type safety
  • Stack example How to support this?
  • public static void main (String args)
  • StackltStringgt stack new StackltStringgt()
  • for (String arg args) stack.push(arg)
  • while (!stack.isEmpty()) stack.pop()

18
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 )
  • ensureCapacity()
  • elements size e
  • public Object pop()
  • if (size 0) throw new ISE()
  • Object result elements --size
  • elementssize null
  • return result
  • // remainder of Stack omitted See Bloch

19
Example Converting collection to generics
  • public class Stack ltEgt // First
    cut at generics wont work
  • private E elements //
    Alternate 2 Leave as Object
  • private int size 0
  • private static final int CAP 16
  • public Stack() elements new E CAP
    // error generic array creation
  • // Alternate 1 new (E)
    Object CAP // warning
  • // _at_SuppressWarning(unchecked)
  • //public Stack() elements new (E) Object
    CAP // warning suppressed
  • public void push( E e )
  • ensureCapacity()
  • 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
  • elementssize null
  • return result

20
Item 27 Favor Generic Methods
  • Just as classes benefit from generics
  • So do methods
  • Writing generic methods is similar to writing
    generic types

21
Example Generic method
  • // Uses raw types unacceptable! (Item 23)
  • public static Set union (Set s1, Set s2)
  • Set result new HashSet(s1) //
    Generates a warning
  • result.addAll(s2)
    // Generates a warning
  • return result
  • // Generic method
  • public static ltEgt Set ltEgt union (Set ltEgt s1,
    Set ltEgt s2)
  • Set ltEgt result new HashSet ltEgt (s1)
  • result.addAll(s2)
  • return result
  • // The first ltEgt is the type parameter list
  • // Example from the java.util.Collection
  • // The generics can get a bit redundant
  • Map ltString, ListltStringgtgt anagrams new
    HashMapltString, ListltStringgtgt()

22
Example Recursive Type Bound
  • // Returns the maximum value in a list uses
    recursive type bound
  • public static ltT extends ComparableltTgtgt T max
    (List ltTgt list)
  • Iterator ltTgt i list.iterator()
  • T result i.next()
  • while (i.hasNext())
  • T t i.next() // Note no need for
    a cast
  • if (t.compareTo(result) gt 0)
  • result t
  • return result
  • Questions
  • What happens if the list is empty?
  • What does a Liskov contract look like for this
    method?
  • Note the type parameter ltT extends
    ComparableltTgtgt
  • Note the return type T

23
Item 28 Use bounded wildcards to increase API
Flexibility
  • public class Stack ltEgt // First cut at
    generics wont work
  • public Stack()
  • public void push( E e )
  • public E pop()
  • public boolean isEmpty()
  • // pushAll method without a wildcard type
    deficient!
  • public void pushAll( IterableltEgt src)
  • for (E e src) push(e)
  • // wildcard type for parameter that serves as
    an E producer
  • public void pushAll( Iterablelt? extends Egt
    src)
  • for (E e src) push(e)
  • // wildcard type for parameter that serves as an
    E consumer
  • public void popAll ( Collectionlt? super Egt
    dst)
  • while (!isEmpty()) dst.add(pop())

24
The PECS mnemonic
  • // PECS producer extends, consumer super
  • // Recall earlier example
  • public static ltEgt Set ltEgt union (Set ltEgt s1, Set
    ltEgt s2)
  • // Are parameters consumers or producers? (
    Producers, so, extend)
  • public static ltEgt Set ltEgt union (Set lt? extends
    Egt s1, Set lt? extends Egt s2)
  • // Note that return type should still be SetltEgt,
    not Set lt? extends Egt
  • // otherwise, clients will have to use wildcards
  • SetltIntegergt integers
  • SetltDoublegt doublse
  • SetltNumbergt numbers union ( integers, doubles)
    // compiler error
  • SetltNumbergt numbers union.ltNumbergt ( integers,
    doubles) // type parameter works
  • // max example

25
Item 29 Consider typesafe heterogeneous
Containers
  • // Typesafe heterogeneous container pattern
    implementation
  • public class Favorites
  • private MapltClasslt?gt, Objectgt favorites new
    HashMap(ltClasslt?gt, Objectgt()
  • public ltTgt void putFavorite(ClassltTgt type, T
    instance)
  • if (type null) throw new NPE
  • favorites.put (type, instance)
  • public ltTgt T getFavorite(ClassltTgt type)
  • return type.cast(favorites.get(type))
  • // Fairly subtle stuff
Write a Comment
User Comments (0)
About PowerShow.com