A Syntax Trick I Was Not Aware Of
Suppose you have an incredibly powerful Gadget class:
// Example 1
public class Gadget {
public void doSomething(List<String> things) {
for (String thing : things) {
System.out.println(thing);
}
}
}
Now, somewhere else, you decide to use Gadget as follows:
// Example 2
Gadget g = new Gadget();
g.doSomething(Arrays.asList("Red", "Green", "Blue"));
Cool, no problem. You can also do this:
// Example 3 List<String> stringList = Collections.emptyList(); g.doSomething(stringList);
It’s all good. But wait…that last snippet can be inlined, right? Sorry, but this will not compile:
// Example 4 // won't compile g.doSomething(Collections.emptyList());
I think that after compiling the Gadget class, we lose some type information about List<String> things due to erasure. (although whenever I blog about generics or erasure, someone corrects my misguided theory in the comments…)
Fortunately, this syntax makes it work:
// Example 5 g.doSomething(Collections.<String>emptyList());
I think I encountered code like that a long time ago and then forgot about. Last week I wasn’t able to get something very similar to work, so I split my code into two separate lines as shown in Example 3. That worked, but I was not happy about it.
Then earlier this week I was helping a coworker, and I noticed he used the syntax shown in Example 5. I think my reaction was something like:
WTF is that?
Which led me to research the syntax in the JLS, which led me to the JLS documentation bug mentioned in my previous post.
Now I find myself wondering what other syntax I do not yet fully grasp?
Annoying, isn’t it.
It’s not to do with erasure, it’s just a weakness in the language; but Neal has said it’s fixable. You shouldn’t have to either supply that <String> or use a temp var.
It looks strange at first (some says very ugly) but Neal’s use it all the time.
I found out that it has good logic and solves some issue with Genric woodoo magic.
For example in JPA:
“MyBean = em.find(MyBean.class,pk);”
In Java 5, the casting disappear automatically with no apparent reason. And if you want to hide implementation class and make users use only interface, it does not work anymore.
So,
“MyBean = em.<MyBean>find(persistentClass, pk);”
solves the problem.
Yeah, no erasure here. Java just isn’t smart enough to infer the generic types in method arguments. It’s the classic chicken or the egg problem. The compiler needs to know the types of the arguments in order to decide which method to dispatch to, but it also needs to know which method it’s dispatching to in order to infer the type parameters. Like Kevin said, it’s tricky but doable, and it looks like this could be fixed in Java 7.
After reading all this energy to save inference, I wrote an entry to save Explicit Type Parameters
The Ugly Duckling of Java!