3

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?

5 Answers 5

6

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.

Sign up to request clarification or add additional context in comments.

2 Comments

You could also choose a subtype of the generic parameter I think, so OP was wrong about that or not? ArrayList<Object> name = new ArrayList<SomeSubTypeOfObject>();
Surprisingly, ArrayList<SomeSubTypeOfObject> is not a subtype of ArrayList<Object>. However, this would work, as long as you didn't want to insert anything into it: `ArrayList<? extends Object> name = new ArrayList<SomeSubTypeOfObject>();'
3

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<>();

Comments

2

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?

Comments

1

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.