Why can't I use the Java 7 diamond syntax with a guava ImmutableSortedMap.Builder

351 views Asked by At

I'm using java 7 and this snippet doesn't compile

ImmutableSortedMap<Integer, String> INT_TO_WORD =
       new ImmutableSortedMap.Builder<>(Ordering.natural())
           .put(1, "one")
           .put(2, "two")
           .put(3, "three")
           .build();

whereas this one does

ImmutableSortedMap<Integer, String> INT_TO_WORD =
       new ImmutableSortedMap.Builder<Integer, String>(Ordering.natural())
           .put(1, "one")
           .put(2, "two")
           .put(3, "three")
           .build();

Why do I need to specify the types on the rhs when I have specified them on the lhs? Is there something more to the <> operator than meets the eye.

2

There are 2 answers

0
James Dunn On BEST ANSWER

As Jeffrey pointed out, Java's type inference has some quirks. The diamond syntax can be used in place of the full type syntax only when you are calling a constructor of the Object type that you are assigning the variable to.

The reason you CAN'T use the diamond syntax the way you were trying to is because you were using it with the constructor of a builder object instead of the actual final object that you are assigning the variable to.

So in other words, this works:

// Assigning directly to new object
ObjectInterface<Integer, String> object = new ObjectImplementation<>()

And this doesn't:

// Assigning to the result of a method off of a different object;
// will fail without generic arguments
ObjectInterface<Integer, String> object = new ObjectInterface.Builder<>().build();

Java's diamond syntax and generic inference isn't robust enough to figure out what you are doing with the builder, probably because such robustness would be tricky to implement, as java's generic inference would somehow have to know that your "build" method is tied to your builder's generic parameters.

4
geert3 On

This is different than for instance

ArrayList<String> l = new ArrayList<>();

Here the new on the right hand side is effectively creating the ArrayList.

In your example the new is creating a completely different type, namely Builder and only in the end an ImmutableSortedMap is created by the build() method. The compiler can't know that the Builder<> has anything do to with your ImmutableSortedMap.

Or with a silly example, this could be perfectly valid:

ArrayList<String> l = new SomethingSilly<Boolean>().getArrayListOfStrings();