0% found this document useful (0 votes)
24 views57 pages

Java Generics

Uploaded by

quocnguyen.elt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views57 pages

Java Generics

Uploaded by

quocnguyen.elt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Java™ Generics and

Collections: Tools for


Productivity
Maurice Naftalin,
Morningside Light Ltd

Philip Wadler,
University of Edinburgh

TS-2890

2007 JavaOneSM Conference | Session TS-2890 |


The Right Tools for the Job

What you can – and can’t! – do with the


Generics and Collections features
introduced in Java 5 and Java 6

2007 JavaOneSM Conference | Session TS-2890 | 2


Agenda
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 3


Generics
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 4


Cleaner code

Before:
List ints = [Link](1,2,3);
int s = 0;
for (Iterator it = [Link](); [Link]();){
s += [Link]();
}

After:
List<Integer> ints = [Link](1,2,3);
int s = 0;
for (int n : ints) { s += n; }

2007 JavaOneSM Conference | Session TS-2890 | 5


Detect more errors at compile-time
Strategy pattern for paying tax: Payer

Trust Person

interface Strategy<P extends Payer>{ long computeTax(P p); }


class DefaultStrategy<P extends Payer>
implements Strategy<P> { long computeTax(P p){…} }
class TrustTaxStrategy extends DefaultStrategy<Trust> {
public long computeTax(Trust t) {
return [Link] ? 0 : [Link](t);
}
}
new TrustTaxStrategy().computeTax(person)
fails at compile time with generics
2007 JavaOneSM Conference | Session TS-2890 | 6
Detect more errors at compile-time
ArrayStoreExceptions become compile errors
• Arrays:
Integer[] ints = new Integer[]{1,2,3}
Number[] nums = ints;
nums[2] = 3.14; // run-time error
Integer[] is a subtype of Number[]
• Collections:
List<Integer> ints = [Link](1,2,3);
List<Number> nums = ints; // compile-time error
[Link](2, 3.14);

List<Integer> is not a subtype of List<Number>


2007 JavaOneSM Conference | Session TS-2890 | 7
More Expressive Interfaces
From [Link]
• Before
interface Relation {
public Map getReferencedMBeans()

}
• After
interface Relation {
public Map<ObjectName,List<String>>
getReferencedMBeans()

}

Explicit types in client code – much easier to maintain


2007 JavaOneSM Conference | Session TS-2890 | 8
Generics
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 9


Migration Compatibility
Major design constraint for generics: Binary for
legacy client must link to generified library

With erasure:
Generified Legacy
=
library binary library binary
Allows piecewise generification of libraries
Erasure Eases Evolution
2007 JavaOneSM Conference | Session TS-2890 | 10
From Legacy…
Library
interface Stack {
void push(Object elt);
Object pop();
}
class ArrayStack implements Stack {
private List li = new ArrayList();
public void push(Object elt) { [Link](elt); }
public Object pop(){ return [Link]([Link]()-1); }
}
Client
Stack stack = new ArrayStack();
[Link]("first");
String top = (String)[Link]();

2007 JavaOneSM Conference | Session TS-2890 | 11


…to Generic
Library
interface Stack<E> {
void push(E elt);
E pop();
}
class ArrayStack<E> implements Stack<E> {
private List<E> li = new ArrayList<E>();
public void push(E elt) { [Link](elt); }
public E pop() { return [Link]([Link]()-1); }
}
Client
Stack<String> stack = new ArrayStack<String>();
[Link]("first");
String top = [Link]();

2007 JavaOneSM Conference | Session TS-2890 | 12


Generic Library with Legacy
Client
Library
interface Stack<E> {
void push(E elt);
E pop();
}
class ArrayStack<E> implements Stack<E> {
private List<E> li = new ArrayList<E>();
public void push(E elt) { [Link](elt); }
public E pop() { return [Link]([Link]()-1); }
}
Client
Stack stack = new ArrayStack();
[Link]("first"); // unchecked call
String top = (String)[Link]();

2007 JavaOneSM Conference | Session TS-2890 | 13


Legacy Library with Generic
Client
Three options
• Minimal changes (surface generification)
• Stubs
• Wrappers - not recommended!

2007 JavaOneSM Conference | Session TS-2890 | 14


Minimal Changes

Library with “Surface Generification”


class ArrayStack<E> implements Stack<E> {
private List li = new ArrayList();
public void push(E elt){[Link](elt);} //unchecked call
public E pop(){
return (E)[Link]([Link]()-1); //unchecked cast
}
}

2007 JavaOneSM Conference | Session TS-2890 | 15


Stubs
Stubs
class ArrayStack<E> implements Stack<E> {
public void push(E elt) { throw new StubException(); }
public E pop() { throw new StubException(); }

}

Compile with stubs, execute with legacy library


$ javac -classpath stubs [Link]
$ java -ea -classpath legacy Client

2007 JavaOneSM Conference | Session TS-2890 | 16


Wrappers (not recommended!)
Generified wrapper class
interface GenericStack<E> {
void push(E elt);
E pop();
public Stack unwrap();
}
class StackWrapper<E> implements GenericStack<E> {
private Stack st = new ArrayStack();
public void push(E elt) { [Link](elt); }
public E pop(){ return (E)[Link](); } //unchecked cast
}
Generic client
GenericStack<String> stack = new StackWrapper<String>();
[Link]("first");
String top = [Link]();
2007 JavaOneSM Conference | Session TS-2890 | 17
Problems With Wrappers
• Parallel class hierarchies
• Stack/GenericStack etc
• Nested structures lead to multiple wrapper layers
• E.g. a stack of stacks
• Library essentially in two versions
• For generified and legacy clients

Wrappers recreate the problems that


erasure solves

2007 JavaOneSM Conference | Session TS-2890 | 18


Generics
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 19


Problems of Erasure
• Parameter types are not reified – they are not
represented at run-time
• Constructs requiring run-time type information
don’t work well (or don’t work)
• Casts and instanceof
• Parametric exceptions
• Problems with arrays
• array run-time typing doesn’t play well with erasure

2007 JavaOneSM Conference | Session TS-2890 | 20


No Arrays Of Generic Types
Converting a collection to an array:
class ConversionAttemptOne {
static <T> T[] toArray(Collection<T> c) {
T[] a = new T[[Link]()]; // compile error
int i = 0;
for (T x : c) {
a[i++] = x;
}
return a;
}
}

2007 JavaOneSM Conference | Session TS-2890 | 21


The Principle of Truth in Advertising
Converting a collection to an array:
class AttemptTwo {
static <T> T[] toArray(Collection<T> c) {
T[] a = (T[])new Object[[Link]()]; // unchecked cast
int i = 0;
for (T x : c) {
a[i++] = x;
}
return a;
}
}

Is the return type from toArray an honest description?

2007 JavaOneSM Conference | Session TS-2890 | 22


The Principle of Truth in Advertising

An innocent client tries to use AttemptTwo :

public static void main (String[] args) {


List<String> strings = [Link]("one","two");
String[] sa =
[Link](strings); //ClassCastException!
}

What happened?

2007 JavaOneSM Conference | Session TS-2890 | 23


The Principle of Truth in Advertising
This is AttemptTwo after erasure:
class AttemptTwo {
static Object[] toArray(Collection c) {
Object[] a = (Object[])new Object[[Link]()];

return a;
}
}

And this is the innocent client:


String[] sa = (String[])[Link](strings);

2007 JavaOneSM Conference | Session TS-2890 | 24


The Principle of Truth in Advertising

Static type of the Compiler inserts Reified (ie run-time)


array cast to static type type is Object[]

String[] sa = (String[]) [Link](strings);

The reified type of an array must be a subtype


of the erasure of its static type
(and here, it’s not)

2007 JavaOneSM Conference | Session TS-2890 | 25


Converting A Collection To An Array
Get type information at run-time from array or class token
class SuccessfulConversion {
static <T> T[] toArray(Collection<T> c, T[] a) {
if ([Link] < [Link]())
a = (T[])[Link]( // unchecked cast
[Link]().getComponentType(),[Link]());
int i = 0; for (T x : c) a[i++] = x;
if (i < [Link]) a[i] = null;
return a;
}
static <T> T[] toArray(Collection<T> c, Class<T> k) {
T[] a = (T[])Array. // unchecked cast
newInstance(k, [Link]());
int i = 0; for (T x : c) a[i++] = x;
return a;
}
}
2007 JavaOneSM Conference | Session TS-2890 | 26
Principle of Indecent Exposure
Don’t ignore unchecked warnings!
class Cell<T> {
private T value;
Cell(T v) { value = v; }
T getValue() { return value; }
}
class DeceptiveLibrary {
static Cell<Integer>[] createIntCellArray(int size) {
return (Cell<Integer>[]) // unchecked cast
new Cell[size];
}
}
class InnocentClient {
Cell<Integer>[] intCellArray = createIntCellArray(3);
Cell<? extends Number>[] numCellArray = intCellArray;
numCellArray[0] = new Cell<Double>(1.0);
int i = intCellArray[0].getValue(); //ClassCastException
}
2007 JavaOneSM Conference | Session TS-2890 | 27
Principle of Indecent Exposure

return (Cell<Integer>[])new Cell[size];

Don’t publicly expose an array whose


components do not have a reifiable type
(and here, we have done)

2007 JavaOneSM Conference | Session TS-2890 | 28


Generics
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 29


What Next For Generics?
• Reification?
• The debate rages on…
• Technically feasible?
• Compatibility problems
• One possible approach: distinguish reified type
parameters with new syntax
• interface NewCollection<class E> extends
Collection<E> { ... }
• Discussion on Java 7 still in early stages

2007 JavaOneSM Conference | Session TS-2890 | 30


Collections
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 31


Collections concurrency policy
How has it changed?
• JDK 1.0
• Synchronized collection methods
• JDK 1.2
• Java Collections Framework – unsynchronized
● Optional method synchronization with synchronized wrappers
• Java 5
• [Link] (JSR166)
● Thread-safe classes designed for efficient concurrent access

2007 JavaOneSM Conference | Session TS-2890 | 32


Many [Link] Collections Aren’t
Thread-Safe (by design)
• From [Link]
public boolean add(E e) {
ensureCapacity(size + 1);
elementData[size++] = e;
return true;
}
• The value in elementData is set, then size is incremented
Two threads could execute add concurrently, with size == 0 initially:
1. Thread A sets elementData[0]
2. Thread B sets elementData[0]
3. Thread A increments size
4. Thread B increments size
• Unsynchronized method access leaves the ArrayList in an
inconsistent state
2007 JavaOneSM Conference | Session TS-2890 | 33
Some [Link] Collections Are Thread-
Safe (at a cost)
From [Link] (JDK 1.0)
public synchronized void addElement(E obj){
ensureCapacityHelper(elementCount + 1)
elementData[elementCount++] = obj;
}

From [Link] (JDK 1.2)


static class SynchronizedList<E> implements List<E> {
final List<E>; final Object mutex;
SynchronizedList(List<E> list) {[Link] = list;}
public void add(int index, E element) {
synchronized(mutex) {[Link](index, element);}
}

}
2007 JavaOneSM Conference | Session TS-2890 | 34
Thread-Safe != Concurrent
Even thread-safe [Link] collections have fail-fast iterators
List<String> sl = new ArrayList<String>();
[Link]([Link](1000000,"x"));

• Thread A:
for( Iterator<String> itr = [Link]();
[Link](); ) {
[Link]([Link]());
}
• Thread B:
for( int i = 999999; i > 0; i-- ) {
[Link](i);
}
Thread A throws ConcurrentModificationException
immediately after thread B first modifies the List
2007 JavaOneSM Conference | Session TS-2890 | 35
Using [Link] Collections
Concurrently
Additional safeguards needed for concurrent access
• Use client-side locking
• Subclass or wrap the collection:
public class WrappedList<T> implements List<T> {
private final List<T> list;
public WrappedList<T> list){ [Link] = list; }
public synchronized void addIfAbsent(T x) {
if (![Link](x))
[Link](x);
}
}
// delegate other methods
}
For concurrent use, [Link] collections must often
be locked for all operations, including iteration!
2007 JavaOneSM Conference | Session TS-2890 | 36
Concurrent Collections
No safeguards needed for [Link] classes
Collections in [Link] don’t
require external locking:
• Atomic operators provided where necessary
• ConcurrentMap operations
• atomic test-then-act: putIfAbsent, remove, replace
• Blocking{Queue|Deque} operations
• blocking operations: take, put
• operations from Queue or Deque now required to be atomic
• Iterators are snapshot or weakly consistent
• Never throw ConcurrentModificationException

2007 JavaOneSM Conference | Session TS-2890 | 37


Concurrent Collections
Two kinds of iterator behavior
• Copy-on-write collections
• CopyOnWriteArraySet,CopyOnWriteArrayList
• snapshot iterators
• underlying array is effectively immutable
• iterators do not reflect changes in underlying collection
• never fail with ConcurrentModificationException
• Other concurrent collections
• weakly consistent (wc) iterators
• Iterators may reflect changes in underlying collection
• never fail with ConcurrentModificationException

2007 JavaOneSM Conference | Session TS-2890 | 38


Collections
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 39


Java Collections Framework at Java 2

Interface-based API:
Collection

Set List Map

SortedSet SortedMap

2007 JavaOneSM Conference | Session TS-2890 | 40


Implementations: JDK 1.2 – JDK 1.4

Increasing choice of implementations:


Collection

Set List Map


IdentityHashMap

HashSet
ArrayList LinkedList HashMap WeakHashMap
SortedSet SortedMap
LinkedHashSet
LinkedHashMap
TreeMap
TreeSet
2007 JavaOneSM Conference | Session TS-2890 | 41
Collections in Java 5 and Java 6
Additions to the Collections Framework
• Top-level Interface
• Queue
• Subinterfaces
• Deque, NavigableMap, NavigableSet
• Concurrent interfaces in [Link]
• BlockingQueue, BlockingDeque,
ConcurrentMap, ConcurrentNavigableMap
• 18 implementation classes

2007 JavaOneSM Conference | Session TS-2890 | 42


Collections in Java 5 and Java 6
Eight new interfaces

Collection

Set List Map Queue

SortedSet SortedMap BlockingQueue Deque

NavigableSet NavigableMap ConcurrentMap BlockingDeque

ConcurrentNavigableMap

2007 JavaOneSM Conference | Session TS-2890 | 43


Queue and Deque
• Queues hold elements prior to processing
• yield them in order for processing
• typically in producer-consumer problems
• [Link]
• offer/add, poll/remove, peek/element
• implementations provide FIFO, delay, or priority
ordering
• [Link]
• offerLast/addLast, pollFirst/removeFirst,
peekFirst/elementFirst
• FIFO or LIFO ordering

2007 JavaOneSM Conference | Session TS-2890 | 44


Navigable Collections
• Navigable{Set|Map} improve on Sorted{Set|Map}
• NavigableXXX extends and replaces SortedXXX
• TreeSet and TreeMap retrofitted to implement new
interfaces
• Concurrent implementations: ConcurrentSkipListSet,
ConcurrentSkipListMap

• Operations on NavigableSet
• ceiling/floor, higher/lower,
pollFirst/pollLast
• headSet,tailSet,subSet overloaded to allow choice of
inclusive or exclusive limits (unlike SortedSet operations)

2007 JavaOneSM Conference | Session TS-2890 | 45


Example Use of NavigableSet
• A set of dates suitable for use in an events calendar
• A date is in the set if there is an event on that date
• We use [Link] to represent dates

NavigableSet<LocalDate> calendar = new TreeSet<LocalDate>();


LocalDate today = new LocalDate();
[Link](today); // the next date, starting with
// today, that is in the calendar
[Link](today); // the first date in the future
// that is in the calendar
[Link](); // the first date in the calendar
[Link](today,false);
// all future dates in the calendar

2007 JavaOneSM Conference | Session TS-2890 | 46


Collections
Generics
Why have them?
Implementation by erasure – benefits …
… and problems
What next?
Collections
Trends in concurrency policy
Trends in API design
How to choose an implementation

2007 JavaOneSM Conference | Session TS-2890 | 47


Choosing a Collection
Implementation
• Choose on the basis of
• Functional behavior
• Performance characteristics
• Concurrency policies
• Not all combinations available
• Like buying a car – if you want VXR trim, you have to
have the 2.8i engine
• Some customization
• Synchronized wrappers

2007 JavaOneSM Conference | Session TS-2890 | 48


Choosing a Set Implementation
• Special-purpose implementations:
• EnumSet – for sets of enum – not thread-safe; wc iterators
• CopyOnWriteArraySet – thread-safe, snapshot iterators, used
when there are more reads than writes and set is small
• General-purpose implementations:
• HashSet, LinkedHashSet – not thread-safe; fail-fast iterators
• LinkedHashSet faster for iteration, provides access ordering
add contains next
HashSet O(1) O(1) O(n/h)
LinkedHashSet O(1) O(1) O(1)
• TreeSet, ConcurrentSkipListSet – provide ordering
• ConcurrentSkipListSet thread-safe, slower for large sets

2007 JavaOneSM Conference | Session TS-2890 | 49


Choosing a List Implementation
• Special-purpose implementation:
• CopyOnWriteArrayList – thread-safe, snapshot iterators, used
when there are more reads than writes and list is small
• General-purpose implementations:
• LinkedList – not thread-safe; fail-fast iterators
• May be faster for insertion and removal using iterators
• ArrayList – not thread-safe; fail-fast iterators
• Still the best general-purpose implementation (until Java 7?)
iterator.
get add(e) add(i,e) remove
ArrayList O(1) O(1) O(n) O(n)
LinkedList O(n) O(1) O(1) O(1)

2007 JavaOneSM Conference | Session TS-2890 | 50


Choosing a Queue
Implementation
• Don’t need thread safety?
• FIFO ordering – use ArrayDeque (not LinkedList!)
• Priority ordering – PriorityQueue
• Thread-safe queues:
• Specialised orderings:
• PriorityBlockingQueue, DelayQueue
• Best general purpose non-blocking thread-safe queue:
• ConcurrentLinkedQueue
• Blocking queue without buffering
• SynchronousQueue
• Bounded blocking queues, FIFO ordering:
• LinkedBlocking{Queue|Deque}, ArrayBlockingQueue
• LinkedBlockingQueue typically performs better with many threads

2007 JavaOneSM Conference | Session TS-2890 | 51


Choosing a Map Implementation
• Special-purpose implementations:
• EnumMap – mapping from enums – non-thread-safe, wc iterators
• IdentityHashMap – keys on identity instead of equality
• WeakHashMap – allows garbage collection of “abandoned” entries
• General-purpose implementations:
• HashMap, LinkedHashMap – non-thread-safe, fail-fast iterators
• LinkedHashMap faster for iteration, provides access ordering, useful
for cache implementations
• TreeMap, ConcurrentSkipListMap – provide ordering
• ConcurrentSkipListMap thread-safe, slower for large maps
• ConcurrentMap – thread-safe, uses lock striping
• Map divided into separately locked segments (not locked for reads)

2007 JavaOneSM Conference | Session TS-2890 | 52


Summary
• Generics and new Collections major step in Java
Platform evolution
• Generics are a quick win in client code
• Primary use-case: collections
• Understand the corner cases for API design
• Collections Framework evolution
• Fixing many deficiencies
• [Link] – great new toolset for the
Java programmer

2007 JavaOneSM Conference | Session TS-2890 | 53


For More Information
• Angelika Langer’s Generics FAQ
• [Link]

• Java Concurrency in Practice (Goetz, et al)


Addison-Wesley, 2006
• JavaDoc for [Link], [Link]
• Concurrency-interest mailing list
• [Link]

2007 JavaOneSM Conference | Session TS-2890 | 54


For Much More Information
Java Generics and
Collections
(Naftalin and Wadler)
O’Reilly, 2006

• Everything discussed today, plus


• Subtyping and Wildcards
• Reflection
• Effective Generics
• Design Patterns
• Collection Implementations
• The Collections class
• And lots more!

2007 JavaOneSM Conference | Session TS-2890 | 55


Maurice Naftalin

2007 JavaOneSM Conference | Session XXXX | 56


Java™ Generics and
Collections: Tools for
Productivity
Maurice Naftalin, Morningside Light
[Link]
Philip Wadler, University of Edinburgh
[Link]

TS-2890

2007 JavaOneSM Conference | Session TS-2890 |

You might also like