July 20th, 2011

silver corset

(no subject)

[Ed: I have been dealing with some very poor code recently; my tone in this post reflects that.]

The Java type system is a wonderful thing when used correctly. It lets you make very powerful statements about the intent of your code, and the compiler will guarantee them correct, or reject them as incorrect. However, it also lets you do arbitrary casts and use erasure, which most people do, while simultaneously cursing that same erasure, frequently for reasons they don't understand.

So, here is a pattern which will help you to achieve type safety in a situation where many (most?) people will use erasure or unsafe casts:

public interface Target<T> {
public T get();
public void process(T value);

public class Handler {
public void handle(Target<?> t) { ... }

Now, how do we call t.process(t.get()) safely? t.get() returns a capture of ?, which can only be assigned to Object. But Object cannot be passed to t.process(). Here is the answer: We write an auxiliary private method within which we use a temporary type variable to capture the ?.

private static <T> void _handle(Target<T> t) {
T value = t.get();

Now, in some very limited circumstances (possibly even this one, since I wrote this code cold), the Java compiler can work out that the ? has been captured, and will perform this type variable substitution automatically, but there are enough circumstances where this trick is useful that I found it worth posting.

A more complex example might be trying to call "new Outer(inner)" where Inner<? extends Foo> and Outer<? extends Foo>, given an Inner<?>. Watch for situations where all you need is to explicitly capture a type variable, and capture it.