views:

437

answers:

7

E.G. to create an ArrayList of Strings we have to do something like

List<String> list = new ArrayList<String>();

whereas it should be able to infer the parameter type for the constructor so that we only have to type

List<String> list = new ArrayList();

Why can't the type be infered in the same way that type parameters are infered for generic methods.

+2  A: 

It can be and it's a feature slated for inclusion in JDK7.

Allain Lalonde
+14  A: 

This is a Java 7 improvement. The syntax will be:

List<String> strings = new ArrayList<>();

The official proposal, accepted for inclusion in Project Coin is Improved Type Inference for Generic Instance Creation

According to Rémi Forax, the change is already in the mercurial repository.

Robert Munteanu
While this is good to know, it doesn't answer the question why the current version *doesn't* support this.
Joachim Sauer
@Joachim Sauer: I can't offer a definitive answer as to why, but by reading the bug reports referred by the Diamond proposal I can see that the solution was not well understood in the Java 5 timeframe. Heck, generics are a bit borked even without pushing constructor inference in Java 5.
Robert Munteanu
@Joachim...I believe the phrase you're looking for is "design oversight".
Alex Feinman
+1  A: 

The type can be inferred, but the authors just decided it is better not to have type inference at all then have some limited type inference in some cases.

If you want type inference on jvm, check out scala.

Dev er dev
The problem is that there is some type inference! Type parameters on parameterized methods are infered just fine! Why can't the same rules be applied to object creation?
Joachim Sauer
+3  A: 

As others have said, this is on the list for Java 7. However, I'd like to point out that the Google Collections Library already sort of supports this for various collections, if you're happy to use static imports. For instance, I frequently write code such as:

List<String> list = newArrayList();

All you need is the static import and remove the space between new and ArrayList() :)

(The static import would be to the Lists class, btw. There are similar methods for maps etc.)

Jon Skeet
Personally I think that this is very ugly. :)
Bombe
It's odd when you first see it, but when you're used to it it can significantly reduce clutter.
Jon Skeet
+1. I use this without thinking these days, because Eclipse will insert the import when autocompleting, and I have Google Collections on my default build path.
finnw
+1  A: 

Aside from JDK7 features, I'm guessing so you can use extends and super.

class Animal {}
class  Dog extends Animal {}

List<? extends Animal> anims = new ArrayList<Dog>();
List<? super Dog> superdogs = new ArrayList<Animal>();

You wouldn't be able to infer in these two cases.

Shin
Type inference would only be used if you didn't specify it manually (just as it is with typed methods right now), so it wouldn't make this impossible.
Joachim Sauer
+2  A: 

You want a reason the current Java doesn't support it.

I can only say that Java typically takes little steps wherever possible. I would guess that there was some little technical glitch that they weren't sure about getting "Right" before Java 7--probably something to do with being absolutely certain it wouldn't create an ambiguous case in some older or non-generic code.

Notice how Robert pointed out that the syntax will be this:

List<String> strings = new ArrayList<>();

Notice the empty <>? I'm guessing that's to disambiguate this type of inference from older non-generic code; it's probably just something they didn't think of at first.

Bill K
Yeh, I've just read Robert's links and the <> is to disambiguate from raw types ass you say.
Tarski
Interesting that this sort of the opposite direction taken in C# where the explicit type is on the right hand side and the the type of the variable instead is inferred. Note that in C#'s implementation that this also allows you to infer return types from other method calls without having to explicitly define the type.var strings = new ArrayList<String>();I have to add that at first I didn't so much care for the var keyword in C# but the more I get to use it and together with type inference of generics and anonymous types it all becomes very cohesive.
jpierson
A: 

I'm no Java super-expert, so I'm not completely sure about what I will state. Here are my thoughts:

As Java implements generics by erasure, for every generic type there is an underlying raw type. If you define a generic type, there will be an underlying raw type that will use Object all around.

When you instantiate a new ArrayList, it would be wrong for compiler to infer the type parameter from the instantiation class (ArrayList<String> in your example), as there is a class with that exact name and no type parameter (that is the raw type, ArrayList). I also guess that this is why in java 7 you will have to add <> to the constructor call to tell the compiler to infer the type.

One could argue that the compiler should instantiate the raw type only when the definition class is the raw type, but I think that it would be confusing. I think that the compiler have to infer from incomplete expressions that would be invalid with no given context, which is not the case for the new ArrayList() statement.

I hope this is clear, and that if I'm wrong someone can correct me.


Side note:

Also, beware that the raw class is not the same as the type using Object as type parameter:

List<String> list = new ArrayList();

is valid, where as

List<String> list = new ArrayList<Object>();

is not. In the first case, the raw type can be used as if it was a generic type, but in the second case you ask for contravariance which is not available (not if you don't use wildcards).

Philippe
I felt like answering this question because I think none of the answers (which are all excellent!) here really address the initial question that is *why* :)
Philippe