java generics

16
Generics in Java 5 Better Code in Fewer Keystrokes

Upload: jeslie

Post on 12-Jan-2015

1.742 views

Category:

Documents


1 download

DESCRIPTION

Simple introduction to the basics of Java 1.5 generics

TRANSCRIPT

Page 1: Java Generics

Generics in Java 5Generics in Java 5

Better Code in Fewer Keystrokes

Jeslie Chermak ([email protected])

Better Code in Fewer Keystrokes

Jeslie Chermak ([email protected])

Page 2: Java Generics

What is a “generic”?What is a “generic”?• Generics — An enhancement to the type

system that supports operations on objects of various types while providing compile-time type safety. Note that this lesson is for advanced users. Refer to http://java.sun.com/docs/books/tutorial

• This talk is based on information from http://java.sun.com/docs/books/tutorial/extra/generics

• Generics — An enhancement to the type system that supports operations on objects of various types while providing compile-time type safety. Note that this lesson is for advanced users. Refer to http://java.sun.com/docs/books/tutorial

• This talk is based on information from http://java.sun.com/docs/books/tutorial/extra/generics

Page 3: Java Generics

Why Should I Use It?Why Should I Use It?• COMPILE-TIME TYPE CHECKING!• Compiler enforces type correctness.• Compiler as debugger!

• Faster runtime execution.• Less code to enter, so fewer chances

for programmer error.• More readable code, so easier to

understand later.

• COMPILE-TIME TYPE CHECKING!• Compiler enforces type correctness.• Compiler as debugger!

• Faster runtime execution.• Less code to enter, so fewer chances

for programmer error.• More readable code, so easier to

understand later.

Page 4: Java Generics

Simple ClassSimple Class

• Create a new class in package com.jcc.training.generics

• Class will implement a traditional “stack” containing Integers

• Only methods are push, pop, top• Allow NULLs in stack

• Create a new class in package com.jcc.training.generics

• Class will implement a traditional “stack” containing Integers

• Only methods are push, pop, top• Allow NULLs in stack

Page 5: Java Generics

Java 1.4 ImplementationJava 1.4 Implementationpackage com.jcc.training.generics;

import java.util.ArrayList;import java.util.List;

public class Stack { private final List stack = new ArrayList(); public void push(final Integer value) { this.stack.add(value); // NULL

allowed! } public Integer top() { if (this.stack.isEmpty()) throw new IllegalStateException(); return (Integer) this.stack.get(this.stack.size() - 1); } public Integer pop() { final Integer value = this.top(); this.stack.remove(this.stack.size() - 1); return value; }}

package com.jcc.training.generics;

import java.util.ArrayList;import java.util.List;

public class Stack { private final List stack = new ArrayList(); public void push(final Integer value) { this.stack.add(value); // NULL

allowed! } public Integer top() { if (this.stack.isEmpty()) throw new IllegalStateException(); return (Integer) this.stack.get(this.stack.size() - 1); } public Integer pop() { final Integer value = this.top(); this.stack.remove(this.stack.size() - 1); return value; }}

Page 6: Java Generics

WIBNIFWIBNIF

• Problem: Collection objects always use Object as base type

• Solution: introduce type parameter

• Problem: Collection objects always use Object as base type

• Solution: introduce type parameter

Page 7: Java Generics

Java 5 ImplementationJava 5 Implementationpackage com.jcc.training.generics;

import java.util.ArrayList;import java.util.List;

public class Stack { private final List<Integer> stack = new ArrayList<Integer>(); // field typed! public void push(final Integer value) { this.stack.add(value); // NULL allowed! } public Integer top() { if (this.stack.isEmpty()) throw new IllegalStateException(); return this.stack.get(this.stack.size() - 1); // no cast! } public Integer pop() { final int value = this.top(); // OOPS! this.stack.remove(this.stack.size() - 1); return value; }}

package com.jcc.training.generics;

import java.util.ArrayList;import java.util.List;

public class Stack { private final List<Integer> stack = new ArrayList<Integer>(); // field typed! public void push(final Integer value) { this.stack.add(value); // NULL allowed! } public Integer top() { if (this.stack.isEmpty()) throw new IllegalStateException(); return this.stack.get(this.stack.size() - 1); // no cast! } public Integer pop() { final int value = this.top(); // OOPS! this.stack.remove(this.stack.size() - 1); return value; }}

Page 8: Java Generics

WIBNIFWIBNIF

• Problem: classes need to be rebuilt for differing base types

• Solution: introduce formal type parameter and parameterized type (think parameters to a method, but applied at the class level)

• Problem: classes need to be rebuilt for differing base types

• Solution: introduce formal type parameter and parameterized type (think parameters to a method, but applied at the class level)

Page 9: Java Generics

Improved

ImplementationImproved

Implementationpackage com.jcc.training.generics;

import java.util.ArrayList;import java.util.List;

public class Stack<E> { // class typed! private final List<E> stack = new ArrayList<E>(); // typed by class public void push(final E value) { // typed by class this.stack.add(value); // NULL allowed! } public E top() { // typed by class if (this.stack.isEmpty()) throw new IllegalStateException(); return this.stack.get(this.stack.size() - 1); } public E pop() { // typed by class final E value = this.top(); // typed by class this.stack.remove(this.stack.size() - 1); return value; }}

package com.jcc.training.generics;

import java.util.ArrayList;import java.util.List;

public class Stack<E> { // class typed! private final List<E> stack = new ArrayList<E>(); // typed by class public void push(final E value) { // typed by class this.stack.add(value); // NULL allowed! } public E top() { // typed by class if (this.stack.isEmpty()) throw new IllegalStateException(); return this.stack.get(this.stack.size() - 1); } public E pop() { // typed by class final E value = this.top(); // typed by class this.stack.remove(this.stack.size() - 1); return value; }}

Page 10: Java Generics

Good NewsGood News

• Each instance of a generic class shares the same code (unlike C++ template)

• Feeds upon itself: generic type parameters can propagate (e.g. List<E> within Stack<E>)

• Stack<E> x = new Stack<E>();

• Each instance of a generic class shares the same code (unlike C++ template)

• Feeds upon itself: generic type parameters can propagate (e.g. List<E> within Stack<E>)

• Stack<E> x = new Stack<E>();

Page 11: Java Generics

Bad NewsBad News

• Each instance of a generic class shares the same code!• statics can’t access generic type

information• List<String> ls = new List<Object>();• List<Object> ls = new List<String>();

• … Erasures …

• Each instance of a generic class shares the same code!• statics can’t access generic type

information• List<String> ls = new List<Object>();• List<Object> ls = new List<String>();

• … Erasures …

Page 12: Java Generics

Wildcard typesWildcard types• Old style:

public void printCol(Collection c) {Iterator i = c.iterator();for (i.hasNext()) {

System.out.println(i.next()); }

}

• Can’t do:public void printCol(Collection<Object> c) {

for (Object o : c) { System.out.println(o);

}}

• So use ? as the wildcard (supertype):public void printCol(Collection<?> c) {

for (Object o : c) { System.out.println(o);

}}

• Old style:public void printCol(Collection c) {

Iterator i = c.iterator();for (i.hasNext()) {

System.out.println(i.next()); }

}

• Can’t do:public void printCol(Collection<Object> c) {

for (Object o : c) { System.out.println(o);

}}

• So use ? as the wildcard (supertype):public void printCol(Collection<?> c) {

for (Object o : c) { System.out.println(o);

}}

Page 13: Java Generics

Bounded Wildcard typesBounded Wildcard types• What about when you want a base type

other than Object?public abstract class Shape {

public abstract void draw(Canvas c);}public class Rectangle extends Shape { … }public class Circle extends Shape { … }

Can’t do (in class Canvas):public void drawAll(List<Shape> shapes) { for (Shape s : shapes) s.draw(this);}

• So use ? extends as the bounded wildcard:public void drawAll(List<? extends Shape> shapes) { for (Shape s : shapes) s.draw(this);}

• What about when you want a base type other than Object?public abstract class Shape {

public abstract void draw(Canvas c);}public class Rectangle extends Shape { … }public class Circle extends Shape { … }

Can’t do (in class Canvas):public void drawAll(List<Shape> shapes) { for (Shape s : shapes) s.draw(this);}

• So use ? extends as the bounded wildcard:public void drawAll(List<? extends Shape> shapes) { for (Shape s : shapes) s.draw(this);}

Page 14: Java Generics

Generic methodsGeneric methods• Parameterize types based on arguments

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {

for (T o : a) {

c.add(o); // Correct

}

}

Now have compiler infer type of T: Object[] oa = new Object[100];

Collection<Object> co = new ArrayList<Object>();

fromArrayToCollection(oa, co); // T inferred to be Object

String[] sa = new String[100];

Collection<String> cs = new ArrayList<String>();

fromArrayToCollection(sa, cs); // T inferred to be String

fromArrayToCollection(sa, co); // T inferred to be Object

• Parameterize types based on argumentsstatic <T> void fromArrayToCollection(T[] a, Collection<T> c) {

for (T o : a) {

c.add(o); // Correct

}

}

Now have compiler infer type of T: Object[] oa = new Object[100];

Collection<Object> co = new ArrayList<Object>();

fromArrayToCollection(oa, co); // T inferred to be Object

String[] sa = new String[100];

Collection<String> cs = new ArrayList<String>();

fromArrayToCollection(sa, cs); // T inferred to be String

fromArrayToCollection(sa, co); // T inferred to be Object

Page 15: Java Generics

ErasuresErasures• Generic code like this …

public String loophole(Integer x) { List<String> ys = new LinkedList<String>(); List xs = ys;

xs.add(x); // Compile-time unchecked warning return ys.iterator().next();

}

Actually behaves as …public String loophole(Integer x) { List ys = new LinkedList; List xs = ys; xs.add(x); return (String) ys.iterator().next(); // run time error}

• Generics are implemented by the Java compiler as a front-end conversion called erasure!

• Generic code like this …public String loophole(Integer x) {

List<String> ys = new LinkedList<String>(); List xs = ys;

xs.add(x); // Compile-time unchecked warning return ys.iterator().next();

}

Actually behaves as …public String loophole(Integer x) { List ys = new LinkedList; List xs = ys; xs.add(x); return (String) ys.iterator().next(); // run time error}

• Generics are implemented by the Java compiler as a front-end conversion called erasure!

Page 16: Java Generics

Some minor details …Some minor details …• Working with pre-Java 5.0 code:

http://download-llnw.oracle.com/javase/tutorial/extra/generics/legacy.html

• Lower bounds and multiple bounds: http://download-llnw.oracle.com/javase/tutorial/extra/generics/morefun.html

• Wildcard capture: http://download-llnw.oracle.com/javase/tutorial/extra/generics/morefun.html

• Class literals as runtime types: http://download-llnw.oracle.com/javase/tutorial/extra/generics/literals.html

• Legacy code upgrade issues: http://download-llnw.oracle.com/javase/tutorial/extra/generics/convert.html

• Working with pre-Java 5.0 code: http://download-llnw.oracle.com/javase/tutorial/extra/generics/legacy.html

• Lower bounds and multiple bounds: http://download-llnw.oracle.com/javase/tutorial/extra/generics/morefun.html

• Wildcard capture: http://download-llnw.oracle.com/javase/tutorial/extra/generics/morefun.html

• Class literals as runtime types: http://download-llnw.oracle.com/javase/tutorial/extra/generics/literals.html

• Legacy code upgrade issues: http://download-llnw.oracle.com/javase/tutorial/extra/generics/convert.html