Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Java Generics

Tips and Traps

Contents

What are Generics?

Java Language Guide

"allow a type or method to operate on objects of various types while providing compile-time type safety"

This...

List ducks = new ArrayList();
ducks.put(new Duck());
Duck duck = (Duck)ducks.get(0);
        	

...becomes this

List<Duck> ducks 
    = new ArrayList<Duck>();
ducks.put(new Duck());
Duck duck = ducks.get(0);
        	

so compiler can help

List<Duck>ducks 
    = new ArrayList<Duck>();
ducks.put(new Duck());
Spoon spoon = ducks.get(0);
        	

Shiny Uses

Express Capabilities

interface Walks { void walk(); }
interface Quacks { void quack(); }

<T extends Walks & Quacks> void foo(T duck) {
	duck.walk();
	duck.quack();
}
        	

Typesafe Builder

Maintaining state in type parameters

new Recipe(
  mix().milk(milk).eggs(eggs).flour(flour)
);
new Recipe(
  mix().eggs(eggs).flour(flour).milk(milk)
);
new Recipe(
  mix().eggs(eggs).milk(milk)
);
    
public static class Present {}
public static class Missing {}
	
public Recipe(Builder<Present, Present, Present> builder) {
  this.milk = builder.milk;
  this.eggs = builder.eggs;
  this.flour = builder.flour;
}

   
static Builder<Missing, Missing, Missing> mix() {
    return new Builder<Missing, Missing, Missing>();
}

public Builder<Present, EggState, FlourState> milk(Milk milk) {
    return new Builder<Present, EggState, FlourState>(
        milk, 
        this.eggs, 
        this.flour
    );
}
    

Heterogenous Lists

Use the same technique

It's a Trap

Type Erasure

class Foo {
  void foo(List<Wishes> wishes) {
  }
  void foo(List<Horses> horses) {
  }
}

Type Erasure

class Foo {
  void foo(List wishes) {
  }
  void foo(List horses) {
  }
}

Covariance

Egg is-a Food
but
List-of-eggs is-not-a List-of-food

Covariance

interface Food {}
class Egg implements Food {}

List<Food> food = new ArrayList<Egg>();

Covariance

interface Food {}
class Egg implements Food {}

class ListOfFood implements List {}
class ListOfEgg implements List {}

ListOfFood food = new ListOfEgg();

Covariance - Fixed

interface Food {}
class Egg implements Food {}

List<? extends Food> food = new ArrayList<Egg>();

Contravariance

A Comparator-for-Food is not suitable for comparing Eggs

Contravariance

class FoodComparator implements Comparator<Food> {
        	
eggsactly(egg1, egg2, new FoodComparator());        	
        	
static boolean eggsactly(Egg egg1, Egg egg2, 
  Comparator<Egg> comparator) {
    return comparator.compare(egg1, egg2) == 0;
}

     	

Contravariance

class FoodComparator implements Comparator<Food> {
        	
eggsactly(egg1, egg2, new FoodComparator());        	
        	
static boolean eggsactly(Egg egg1, Egg egg2, 
  Comparator<? super Egg> comparator) {
    return comparator.compare(egg1, egg2) == 0;
}

     	

Tips

Everything Erased?

Myth

What is available

Supertype Params

class Foo<T> { }
class Baz extends Foo<Bar> { }
   		
Declarations
private List<String> strings;
   		

Supertype Params

((ParameterizedType)getClass()
  .getGenericSuperclass())
    .getActualTypeArguments()[0];

Declarations

Foo.class
  .getDeclaredField("listOfStrings")
  .getGenericType();
   		

Class<T> fixes everything

<T> void foo(Class<T> cls) {
  cls.isAssignableFrom();
  cls.newInstance();	
  return (T) somethingDynamic();
   		

Be Specific

Collections.sort(Collections.emptyList());
Collections.sort(
  Collections.<Comparable>emptyList()
);
   		

Further Reading

Use a spacebar or arrow keys to navigate