Reputation: 33
A typical ArrayList
declaration in Java is of the following type:
ArrayList<Object> name = new ArrayList<Object>();
Similarly, for an array, we have:
Object[] name = new Object[size];
Now, we certainly can not have a declaration of the following type:
ArrayList<Object> name = new ArrayList<AnotherObject>();
The specifying of the type and the name of the same object two times has always seemed quite superfluous to me. The redundancy in the above declaration can be easily done away with something like this:
ArrayList<Object> name = new();
Is there any specific reason that I am missing out as to why it is done the way it is done?
Upvotes: 3
Views: 2788
Reputation: 1098
From Java 10 on, those redundant info can be omitted, we can choose to let the compiler infer the type by using var
, e.g.
var objArray = new Object[10]; // (objArray instanceof Object[]) == true
var stringList = new ArrayList<String>(); // (stringList intanceof ArrayList) == true
To process var
, the compiler looks at the so-called initializer
(right hand side of the declaration), and uses its type for the variable. Details can be referred JEP 286.
Upvotes: 0
Reputation: 106460
There's a dusty tome out there with regards to why it's done the way it is, but let's specifically look at the declaration of ArrayList
.
To put a pin on it: the ability to reduce the verbosity when newing up a generic wasn't in the language back when Java 6 was released.
This is the grammar for declaring a new
instance of a reference, back in Java 6.
ClassInstanceCreationExpression:
new TypeArguments (opt) ClassOrInterfaceType ( ArgumentList (opt) )
ClassBody (opt)
Primary. new TypeArguments (opt) Identifier TypeArguments (opt) (
ArgumentList (opt) ) ClassBody (opt)
ArgumentList:
Expression
ArgumentList , Expression
The second production, or more specifically, the TypeArguments token is what is governing what we can put there.
That changes in Java 7, with the introduction of the diamond operator.
ClassInstanceCreationExpression:
new TypeArguments (opt) TypeDeclSpecifier TypeArgumentsOrDiamond (opt)
( ArgumentList (opt) ) ClassBody (opt)
Primary . new TypeArguments (opt) Identifier TypeArgumentsOrDiamond (opt)
( ArgumentList (opt) ) ClassBody (opt)
TypeArgumentsOrDiamond:
TypeArguments
<>
ArgumentList:
Expression
ArgumentList , Expression
So the verbosity no longer needs to be there, thanks to the TypeArgumentsOrDiamond token, but it's still supported by newer versions of Java regardless.
To your example, why we couldn't do something like this:
ArrayList<Object> name = new();
The main thing that springs to mind is, if you want to create an instance of a List
, which is an interface and thus can't be instantiated, how would the new()
method know which kind of list to pull back? Would it always pull back an ArrayList
? A LinkedList
? Or one of your own types of lists? How would Java know which one is correct without you telling it?
More directly, what should this produce...
List<Object> name = new();
...if we can choose between ArrayList
, LinkedList
, or SpecialUtilityList
which extends ArrayList
?
Upvotes: 2
Reputation: 11642
Perhaps you are familiar with other languages, such as C# or C++, that are able to infer the type of a variable; e.g.
var x = new MyObjectType(); // C#
or
auto x = someMethodThatReturnsSomething(); // C++
Java does its type inference "the wrong way around" if you are used to either of the above languages: you can omit the type parameter of a generic type on the right-hand side:
List<MyObjectType> = new ArrayList<>();
However, even though this may seem unintuitive at first, this is how type inference works and it is consistent and has advantages in other contexts; for example you can pass Collections.emptyMap()
to a method that takes a Map<Integer, MyObjectType>
and the compiler works it out without you having to specify the type of map you want emptyMap
to return.
As for why you still have to specify the type on the LHS, that's the Java philosophy - you specify your desired interface on the LHS and your desired concrete type on the RHS.
Upvotes: 1
Reputation: 4945
It isn't. At least, not any more. Now you can do:
ArrayList<Object> name = new ArrayList<>();
You can't leave off the second ArrayList
because it doesn't necessarily have to match the first. For example, you can do this:
List<Object> name = new ArrayList<>();
and you'll get an ArrayList
but see it as a List
.
Upvotes: 6
Reputation: 2310
From JDK7 onwards, type inference is present. You do not need to specify type on right hand side. Look here for an example: http://www.javacodegeeks.com/2012/05/type-inference-from-java-7.html
You can write like this:
List<Object> values = new ArrayList<>();
Upvotes: 3