3

Let's say I want to create an ArrayList for numbers. The way I learned it is like this:

private static List<Integer> numbers = new ArrayList<Integer>();

But IntelliJ IDEA wants to correct it to

private static List<Integer> numbers = new ArrayList<>();

And then I found out this works as well:

private static List<Integer> numbers = new ArrayList();

Now I'm confused, what's the best way? And what's the difference. Same question applies to HashMap.

SJ19
  • 1,933
  • 6
  • 35
  • 68

4 Answers4

7

The best way is:

private static List<Integer> numbers = new ArrayList<>(); // Java 7
private static List<Integer> numbers = new ArrayList<Integer>(); // Java 6

Lets take a look at the other examples:

private static ArrayList<Integer> numbers = new ArrayList<Integer>(); uses a specific class as the type, which is discouraged unless you need to access ArrayList-specific methods (I don't know any)

private static ArrayList<Integer> numbers = new ArrayList(); is type-unsafe, and your IDE should give you a warning on this line.

Mark Jeronimus
  • 9,278
  • 3
  • 37
  • 50
  • please, can you explain more detaily why last case is type unsafe? What should I do to get an error? – ka4eli Sep 06 '15 at 13:40
  • *private static ArrayList numbers = new ArrayList(); is type-unsafe, and if your IDE should give you a warning on this line.* actually android studio gives a warning if you use `<>()`, advising you to use `()` only – Tim Sep 06 '15 at 13:41
  • 1
    @ka4eli, in this particular case it doesn't matter. However in some other cases (for example if the type argument is bounded or you use constructor arguments which depend on type argument), it would make different. – Tagir Valeev Sep 06 '15 at 13:42
3

You should be using the interface in the left side:

private static List<Integer> numbers = new ArrayList<>();

Unless you really need any of the specific methods for that data structure.

IntelliJ IDEA is suggesting you that construct since you are using the JDK 1.7.x (or superior) and there is no need to specify again the type because the compiler can infer the type arguments from the context (again from Java 7 and/or later).

x80486
  • 6,627
  • 5
  • 52
  • 111
2

All the examples given will compile to the same bytecode, and do not affect subsequent type checks. The reason for using one or another is avoiding annoying warnings.

  • new ArrayList(); is the pre-generics way. The compiler will warn you because you are not caring about generics (and potentially assigning an ArrayList with elements other than Integer).
  • new ArrayList<Integer>(); is the generics-way, but before the compiler was smart enough to infer itself the element type. Therefore it warns you because it is more verbose than necessary.
  • new ArrayList<>(); is the currently preferred way (thanks to Type Inference introduced in Java 7 (see related SO question) ). Go for it unless you have to deal with older compilers.

Maybe an interesting question would be why new ArrayList<>(); is best (type inference) but new ArrayList(); is not.

Community
  • 1
  • 1
Javier
  • 678
  • 5
  • 17
1

The first example is correct, you supply everything needed. But it also means you repeat the definition of the parameter type.

Then, in Java 1.7 (or maybe 1.8, not quite sure) they introduced the shortened version - so in case you define ArrayList<Integer> numbers, there is no need to define repeat that ArrayList for Integer should be created and you just keep <> there. This is sometimes called a diamond notation and instructs compiler to use the very same data type that you used for the field definition. So, as a result it behaves exactly like the first example, but without the need to duplicate the information about data type.

The last case you have there is somewhat different as you create an ArrayList of no specified data type. This can be somewhat dangerous as it allows you to write the following code:

List listAnything = new ArrayList();
listAnything.add("string");
listAnything.add(42);
listAnything.add(false);

List<Integer> listInteger = listAnything;

The above listed code compiles perfectly fine, though there are some warnings about unchecked conversions and using raw types. You are no longer to guarantee that listInteger contains only integers.

Also, word of warning here - you should rely on abstraction as much as possible in your code. By this I mean to define your fields using an interface or an abstract class rather than concrete one. Such a code is a significantly better to read and to maintain:

ArrayList<Integer> list = new ArrayList<>(); // this is not wrong...
List<Integer> list = new ArrayList<>(); // ...but this is better
Sva.Mu
  • 1,141
  • 1
  • 14
  • 24
  • "you should rely on abstraction as much as possible in your code"...be careful on that, it's not true about 90% of the times; although there are real life situations when that's useful (I'm not talking about API development here). Nowadays, Java is bloated because of that...have a look at what many other (comparable to Java) programming languages are doing. – x80486 Sep 06 '15 at 14:31
  • @ɐuıɥɔɐɯ why do you think so? I mean, I don't want to argue, just curious about what's on your mind. This "technique" seems very widely used, so I'd like to know where you see a problem with it. Also, I didn't mean "do it everywhere and always", by saying "as much as possible" I assume the reader would use common sense :-) – Sva.Mu Sep 06 '15 at 14:37
  • Just a "tip"; I'm not arguing also. The "technique" it's widely used (and abused)...greetings! – x80486 Sep 06 '15 at 15:04