Generics
> Click or hit Control-Enter to run Example.main above
Java Generics
Lists and maps are the two data structures you meet in heaven. Together you can use them to solve almost any problem.
But you’ll usually use Java`s built-in implementations.
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
import java.util.TreeMap;
List list = new ArrayList();
List anotherList = new LinkedList();
Map map = new HashMap();
Map anotherMap = new TreeMap();
> Click or hit Control-Enter to run Example.main above
Compiler Errors v. Runtime Errors
Java and many languages that followed it have tried to transform runtime errors into compiler errors. Why?
-
You compile your code before it runs: and so before you have to demo it to a client, or before you deploy it to hundreds of users.
-
Catching errors at this stage is critical.
Generics
Java generics allow us to create reusable classes while allowing the compiler to check our code for correctness.
Type parameters tell the compiler what we are going to do with each data structure.
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
List<Integer> integerlist = new ArrayList<>(); // This is list of Integers
Map<Integer, String> = new HashMap<>(); // This maps Integers to Strings
Generic Rationale
Java generics allow to combine two desirable features of the language:
-
Polymorphism: because every object inherits from
Object
it is easy to build general purpose data structures that can operate on every Java object -
Type Checking: however, upcasting everything to
Object
makes it impossible for the compiler to perform compile-time type checking -
Generics are intended to allow us to have the best of both worlds
> Click or hit Control-Enter to run Example.main above
Generifying Your Classes
So we know how to use existing generic class. But how do we provide our own?
Class Type Parameters
First, we have to declare our class to accept type parameters:
// T is a type parameter that can be used throughout our class
public class SimpleLinkedList<E> {
// get returns a reference of type E
public E get(int index) {
}
// set takes a reference of type T as its second argument
public void set(int index, E value) {
}
}
Parameters Are Not Variables
Class parameters are not variables.
I can use them where I would normally provide a type, but I can’t get or set their values.
public class SimpleLinkedList<E> {
// I can use the parameter here as a return type...
public E get(int index) {
E = String; // But I can't do something like this
}
}
Compiling Generic Classes
To help understand how generics work you can imagine the compiler rewriting them when it compiles your code.
Original and Rewritten List
public class List<E> {
public E get(int i) {
}
public void set(int i, E value) {
}
}
List<String> list = new List<>();
public class List {
public String get(int i) {
}
public void set(int i, String value) {
}
}
List list = new List<>();
Original and Rewritten List
public class List<E> {
public E get(int i) {
}
public void set(int i, E value) {
}
}
List<Integer> list = new List<>();
public class List {
public Integer get(int i) {
}
public void set(int i, Integer value) {
}
}
List list = new List<>();
Type Erasure
Note that this is not actually what happens.
-
The compiler only creates one instance of each generic class
-
Type information is used during compilation to check access but then erased
-
But this isn’t a bad mental model of how generics work in practice
Multiple Type Parameters
Classes can use one or several type parameters:
// This is a generic list storing elements of type T
public class SimpleLinkedList<T> { }
// This is a generic map mapping elements of type K to type V
public class SimpleMap<K,V> { }
Parameter Naming Conventions
To avoid confusing type parameters with variable names or other keywords, Java has established conventions for naming them.
-
By convention type names are single uppercase letters:
T
,K
,V
,E
, etc. -
Note that this is just a convention: it’s not enforced by the compiler
-
Certain type parameters have conventional meanings:
-
E
for element (which we’ll use for our lists) -
K
for key andV
for value, (which we’ll use for our maps) -
N
for a number
-
Original and Rewritten Map
public class Map<K, V> {
public V get(K key) {
}
public void put(K key, V val) {
}
}
Map<String, Double> map = new Map<>();
public class Map {
public Double get(String key) {
}
public void put(String key, Double val) {
}
}
Map map = new Map();
Original and Rewritten Map
public class Map<K, V> {
public V get(K key) {
}
public void put(K key, V val) {
}
}
Map<Integer, String> map = new Map<>();
public class Map {
public String get(Integer key) {
}
public void put(Integer key, String val) {
}
}
Map map = new Map();
> Click or hit Control-Enter to run Example.main above
Questions So Far?
Because it’s about to get more interesting…
> Click or hit Control-Enter to run Example.main above
Bounded Type Parameters
The compiler knows all about the relationship between different types, and so it can help us ensure that our generic classes receive appropriate type parameters.
-
<T extends S>
: typeT
extends classS
or implements interfaceS
-
<T extends S & U & V>
: typeT
extends or implementsS
,U
, andV
> Click or hit Control-Enter to run Example.main above
Generic Interfaces
Just like classes, interface definitions can use type parameters:
public interface SimpleList<E> {
public E get(int index);
public void set(int index, E element);
public void add(int index, E element);
public E remove(int index);
public int size();
}
Generic Gotchas
I’ve elided many of the details of working with generics. Review the official documentation to learn more.
But here’s one of the more obvious things that doesn’t work the way you’d want:
public class LastTen<T> {
private T[] values;
private List<T> listOfValues;
LastTen() {
value = new T[10]; // You can't create an array of a generic type
// As a solution you can use a collection type like a list
listOfValues = new ArrayList<T>(); // This works
}
}
Questions About Generics?
Next Few Classes
-
Monday: streams and functional Java
-
Wednesday: wrap up and ICES forms
Announcements
-
The third and final midterm starts Sunday. Good luck!
-
Lab next week will be final project evaluations and choosing the best projects to feature at the fair next week. Good luck wrapping up your cool projects! I’m very excited to see what you all built…
-
I have today from 1–3PM in Siebel 2227. Please stop by!