Categories
arraylist collections initialization java

Initialization of an ArrayList in one line

3163

I wanted to create a list of options for testing purposes. At first, I did this:

ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");

Then, I refactored the code as follows:

ArrayList<String> places = new ArrayList<String>(
    Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

Is there a better way to do this?

9

  • 42

    If this is intended for unit testing, try groovy out for a swing. You can write your test code in it while testing java code, and use ArrasyList<String> places = ["Buenos Aires", "Córdoba", "La Plata"]

    – ripper234

    Dec 31, 2010 at 21:40

  • 5

    In Java SE 7, you can substitute the parameterized type of the constructor with an empty set of type parameters (<>): Map<String, List<String>> myMap = new HashMap<>();

    – Rose

    Jul 7, 2015 at 21:12


  • 2

  • 2

    use double bracing initialization 🙂

    Apr 26, 2016 at 15:36

  • 13

    Stream.of(“val1”, “val2”).collect(Collectors.toList()); //creates ArrayList, Java8 solution.

    – torina

    Oct 13, 2017 at 17:37


2203

Actually, probably the “best” way to initialize the ArrayList is the method you wrote, as it does not need to create a new List in any way:

ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");

The catch is that there is quite a bit of typing required to refer to that list instance.

There are alternatives, such as making an anonymous inner class with an instance initializer (also known as an “double brace initialization”):

ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};

However, I’m not too fond of that method because what you end up with is a subclass of ArrayList which has an instance initializer, and that class is created just to create one object — that just seems like a little bit overkill to me.

What would have been nice was if the Collection Literals proposal for Project Coin was accepted (it was slated to be introduced in Java 7, but it’s not likely to be part of Java 8 either.):

List<String> list = ["A", "B", "C"];

Unfortunately it won’t help you here, as it will initialize an immutable List rather than an ArrayList, and furthermore, it’s not available yet, if it ever will be.

2

2203

Actually, probably the “best” way to initialize the ArrayList is the method you wrote, as it does not need to create a new List in any way:

ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");

The catch is that there is quite a bit of typing required to refer to that list instance.

There are alternatives, such as making an anonymous inner class with an instance initializer (also known as an “double brace initialization”):

ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};

However, I’m not too fond of that method because what you end up with is a subclass of ArrayList which has an instance initializer, and that class is created just to create one object — that just seems like a little bit overkill to me.

What would have been nice was if the Collection Literals proposal for Project Coin was accepted (it was slated to be introduced in Java 7, but it’s not likely to be part of Java 8 either.):

List<String> list = ["A", "B", "C"];

Unfortunately it won’t help you here, as it will initialize an immutable List rather than an ArrayList, and furthermore, it’s not available yet, if it ever will be.

2

1076

The simple answer

Java 9 or later:

List<String> strings = List.of("foo", "bar", "baz");

This will give you an immutable List, so it cannot be changed.
Which is what you want in most cases where you’re prepopulating it.

Java 8 or earlier:

List<String> strings = Arrays.asList("foo", "bar", "baz");

This will give you a List* backed by an array, so it cannot change length.
But you can call List.set(...), so it’s still mutable.

*
Implementation detail: It’s a private nested class inside java.util.Arrays, named ArrayList,
which is a different class from java.util.ArrayList, even though their simple names are the same.

Static import

You can make Java 8 Arrays.asList even shorter with a static import:

import static java.util.Arrays.asList;  
...
List<String> strings = asList("foo", "bar", "baz");

Any modern IDE* will suggest and do this for you.

I don’t recommend statically importing the List.of method as just of, because it’s confusing.

*
For example, in IntelliJ IDEA you press Alt+Enter and select Static import method...

Using Streams

Why does it have to be a List?
With Java 8 or later you can use a Stream which is more flexible:

Stream<String> strings = Stream.of("foo", "bar", "baz");

You can concatenate Streams:

Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
                                       Stream.of("baz", "qux"));

Or you can go from a Stream to a List:

import static java.util.stream.Collectors.toList;
...
var strings = Stream.of("foo", "bar", "baz").toList(); // Java 16

List<String> strings = Stream.of("foo", "bar", "baz").collect(toList()); // Java 8

But preferably, just use the Stream without collecting it to a List.

If you specifically need a java.util.ArrayList*

If you want to both prepopulate an ArrayList and add to it afterwards, use

List<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");

or in Java 8 or earlier:

List<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");

or using Stream:

import static java.util.stream.Collectors.toCollection;

List<String> strings = Stream.of("foo", "bar")
                             .collect(toCollection(ArrayList::new));
strings.add("baz");

But again, it’s better to just use the Stream directly instead of collecting it to a List.

*You probably don’t need specifically an ArrayList. To quote JEP 269:

There is a small set of use cases for initializing a mutable collection instance with a predefined set of values. It’s usually preferable to have those predefined values be in an immutable collection, and then to initialize the mutable collection via a copy constructor.

(emphasis mine)

Program to interfaces, not to implementations

You said you’ve declared the list as an ArrayList in your code, but you should only do that if you’re using some member of ArrayList that’s not in List.

Which you are most likely not doing.

Usually you should just declare variables by the most general interface that you are going to use (e.g. Iterable, Collection, or List), and initialize them with the specific implementation (e.g. ArrayList, LinkedList or Arrays.asList()).

Otherwise you’re limiting your code to that specific type, and it’ll be harder to change when you want to.

For example, if you’re passing an ArrayList to a void method(...):

// Iterable if you just need iteration, for (String s : strings):
void method(Iterable<String> strings) { 
    for (String s : strings) { ... } 
}

// Collection if you also need .size(), .isEmpty(), or .stream():
void method(Collection<String> strings) {
    if (!strings.isEmpty()) { strings.stream()... }
}

// List if you also need random access, .get(index):
void method(List<String> strings) {
    strings.get(...)
}

// Don't declare a specific list implementation
// unless you're sure you need it:
void method(ArrayList<String> strings) {
    ??? // You don't want to limit yourself to just ArrayList
}

Another example would be always declaring variable an InputStream even though it is usually a FileInputStream or a BufferedInputStream, because one day soon you or somebody else will want to use some other kind of InputStream.

0