Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do "var" and raw types come together?

I came across an answer that suggests to use

var list = new ArrayList();

I was surprised to find a raw type here, and I am simply wondering: does var use the <> "automatically?

( in the meantime, the answer was changed to use <String>, but I am still curious about but "principles" here )

I saw other questions such as this, but they all use the diamond operator:

var list = new ArrayList<>();

Now I am simply wondering: does var change how we should (not) be using raw types? Or is that suggestion to leave out <> simply bad practice?

like image 941
GhostCat Avatar asked Aug 06 '18 11:08

GhostCat


2 Answers

I came across an answer that suggests to use...

I would ignore that answer, because as you point out, it uses raw types and it types list as specifically ArrayList. (Update: The answerer edited their answer to add an element type.) Instead:

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

According to the second answer you linked, var will cause the compiler to infer an element type from the right-hand side if you include the <>, picking the most specific type it can. In var list = new ArrayList<>(); that would be ArrayList<Object>, though, because it doesn't have anything more specific it can choose.

But, this:

var list = new ArrayList();

...without the <>, is using a raw type (ArrayList), not a parameterized type with Object as the parameter (ArrayList<Object>), which is different.


If the use of list is sufficiently contained (a few lines in a method), having it typed ArrayList<X> rather than List<X> may be acceptable (depends on your coding style), in which case:

var list = new ArrayList<AppropriateElementType>();

But generally I prefer to code to the interface rather than the concrete class, even with locals. That said, with locals, it is less important than with instance members, and var is convenient.

like image 154
T.J. Crowder Avatar answered Oct 11 '22 16:10

T.J. Crowder


It is legal to use both var and diamond, but the inferred type will change:

var list = new ArrayList<>(); // DANGEROUS: infers as ArrayList<Object>

For its inference,  diamond  can use the target type (typically,  the left-hand side of a declaration) or the types of constructor arguments. If neither is present, it falls back to the broadest applicable type, which is often Object1.

With both diamond and generic methods, additional type information can be provided by actual args to the constructor or method, allowing the intended type to be inferred1:

var list = List.of(BigInteger.ZERO); // OK: infers as List<BigInteger>
var list = new ArrayList<String>( ); // OK: infers as ArrayList<String>

In view of the above, I don't recommend to do the following (because you will get the raw ArrayList type):

var list = new ArrayList(); // DANGEROUS: infers as ArrayList

Conclusion:

  1. Don't use raw types irrespective of the presence or absence of var.
  2. Ensure that method or constructor arguments provide enough type information so that the inferred type matches your intent. Otherwise, avoid using both var with diamond1.

1 - Style Guidelines for Local Variable Type Inference: G6. Take care when using var with diamond or generic methods.

like image 10
Oleksandr Pyrohov Avatar answered Oct 11 '22 16:10

Oleksandr Pyrohov