April 12, 2008

You don't know Java: Method type parameters

When someone tells you they know Java, smile and say "no, you don't". Proceed to soften them up with questions about covariance and contravariance and how they relate to parametrized types. When they start crying, go in for the kill.

But let's talk about something nice today: Method type parameters. Few people know that type parameters in Java are not limited to types, but that every method and constructor can declare their own type parameters. And if this alone wasn't cool enough, it can actually be useful!

To illustrate, I need a couple of interfaces from Java kindergarden:

interface CanWalk {
    void walk(int steps);
}

interface CanSwim {
    void swim(int strokes);
}

interface CanSleep {
    void sleep(int minutes);
    boolean isSleeping();
}

interface Animal implements CanSleep { }

interface Cat implements Animal, CanWalk { }

interface Dog implements Animal, CanWalk, CanSwim { }

Say we want to write a method that simply takes an Animal and returns it. This is the way we used to roll:

Animal returnMe(Animal animal) {
    return animal;
}

What's bad about this method is, that it returns its value as Animal, even if we gave it a Cat. So if we wanted our cat back, we need to cast it manually:

Cat cat = (Cat)returnMe(new Cat());

We can improve on this by binding a type variable to the returnMe method like this:

<A extends Animal> A returnMe(A a) {
    return a;
}

This way we don't need the cast:

Cat cat = returnMe(new Cat());

To give an actually useful example, let's write a method getAwake that is given a list of objects implementing CanSleep, and returns those objects that return false from isSleeping():

<A extends CanSleep> List<A> getAwake(List<A> potentialSleepers) {
    return Lists.select(potentialSleepers, new Filter<A>() {
        public boolean passes(A element) {
            return !element.isSleeping();
        }
    });
}

... with Lists.select working like select in Ruby lists, but you cool kids already figured that out by yourself. Again we can give getAwake a list of cats, and get a list of cats back, rather than a list of animals. You can see how method type parameters allow us to be more expressive about our method signatures.

This might be stretching the attention span of the YouTube generation, but here's one more cool thing: Method type parameters with composite upper bounds:

<Duckish extends CanWalk & CanSwim & CanSleep> void rockTheBeach(Duckish duckish) {
    duckish.walk(100); // check out the chicks
    duckish.swim(20);  // cool down in the water
    duckish.sleep(60); // take a nap
}

This is about as much fun as you'll ever be able to have writing Java. Enjoy!

Comments (0)