Alok Patwal
Alok Patwal

Reputation: 33

Redundant wording in a Java array and ArrayList declaration

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

Answers (5)

hoan
hoan

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

Makoto
Makoto

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

Klitos Kyriacou
Klitos Kyriacou

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

Erick G. Hagstrom
Erick G. Hagstrom

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

shiladitya
shiladitya

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

Related Questions