Top Banner
Generics in Java 5 Better Code in Fewer Keystrokes
16

Java Generics

Jan 12, 2015

Download

Documents

jeslie

Simple introduction to the basics of Java 1.5 generics
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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