在一行中初始化数组列表

I want 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?

转载于:https://stackoverflow.com/questions/1005073/initialization-of-an-arraylist-in-one-line

csdnceshi70
笑故挽风 Stream.of("val1", "val2").collect(Collectors.toList()); //creates ArrayList, Java8 solution.
大约 3 年之前 回复
weixin_41568134
MAO-EYE It seems like you answered yourself in the question: ArrayList<String> places = new ArrayList<String>(asList("Buenos Aires", "Córdoba", "La Plata")); Arrays in Arrays.asList is not needed.
大约 3 年之前 回复
csdnceshi71
Memor.の use double bracing initialization :)
4 年多之前 回复
csdnceshi65
larry*wei See also stackoverflow.com/questions/157944/create-arraylist-from-array
大约 5 年之前 回复
csdnceshi51
旧行李 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<>();
5 年多之前 回复
csdnceshi59
ℙℕℤℝ 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"]
接近 10 年之前 回复

30个回答

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.

csdnceshi70
笑故挽风 Since this answer is the most upvoted and mentioned Project Coin I think you should call out that java 9 shipped with List.of(...) syntax: docs.oracle.com/javase/9/docs/api/java/util/List.html#of-E...-
接近 3 年之前 回复
csdnceshi79
python小菜 could you elaborate ? List<String> list = ["A", "B", "C"]; does not work here. Thanks.
大约 5 年之前 回复
csdnceshi80
胖鸭 thank you for pointing out the missing semicolon.
5 年多之前 回复
csdnceshi59
ℙℕℤℝ Well, just goes to show - one man's syntactic sugar is another mans syntactic diabetes. I'll stay away from these 'alternatives'.
5 年多之前 回复
csdnceshi75
衫裤跑路 You're missing a semicolon on the double-list initialization
5 年多之前 回复
csdnceshi57
perhaps? Only works if you aren't relying on Auto boxing List<Double> list = [1.0, 2.0, 3.0]; fails.
接近 6 年之前 回复
csdnceshi80
胖鸭 Good call for the link -- one sentence on double-brace initialization isn't enough to describe it fully.
11 年多之前 回复
csdnceshi50
三生石@ See stackoverflow.com/questions/924285 for more information about the double-brace initialization, pros and cons.
11 年多之前 回复

The simple answer

In Java 8 or earlier:

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

This will give you a List backed by the array, so it cannot change length.
But you can call List.set, so it's still mutable.


In Java 9:

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.


The shorter answer

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

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

The static import:

import static java.util.Arrays.asList;  

Which any modern IDE will suggest and automatically do for you.
For example in IntelliJ IDEA you press Alt+Enter and select Static import method....


However, i don't recommend shortening the Java 9 List.of method, because having just of becomes confusing.
List.of is already short enough and reads well.


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:

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

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


If you really specifically need a java.util.ArrayList

(You probably don't.)
To quote JEP 269 (emphasis mine):

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.


If you want to both prepopulate an ArrayList and add to it afterwards (why?), use

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

or in Java 9:

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

or using Stream:

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.


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:

// Iterable if you just need iteration, for (String s : strings):
Iterable<String> strings = new ArrayList<>();   

// Collection if you also need .size() or .stream():
Collection<String> strings = new ArrayList<>(); 

// List if you also need .get(index):
List<String> strings = new ArrayList<>();       

// Don't declare a specific list implementation
// unless you're sure you need it:
ArrayList<String> strings = new ArrayList<>();  // You don't need 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.

csdnceshi60
℡Wang Yan Or you can use import java.util.Arrays; and Arrays.asList("",""); You don't have to use a static import. You don't have to use a full path. Static methods don't care about the import. They just get annoyed if you use an instance to find them.
大约 6 年之前 回复
csdnceshi63
elliott.david If you don't want the static import you can also define the full path to the static asList method, as so: List<String> strings = java.util.Arrays.asList("","");
7 年多之前 回复
csdnceshi79
python小菜 The answer above i think you're talking about was made a year before. And no, the problem with global variables is that they are mutable. They have nothing to do with static imports.
7 年多之前 回复
csdnceshi66
必承其重 | 欲带皇冠 In that case, my novice mind tells me that static import bares strong resemblance to global variables and the perils that pertain to such usage. Is this assumption correct and is it also the reason for the similar answer above getting more votes?
7 年多之前 回复
csdnceshi79
python小菜 Arrays.asList is a static method. See docs.oracle.com/javase/1.5.0/docs/guide/language/…
7 年多之前 回复
csdnceshi66
必承其重 | 欲带皇冠 Thank you ever so much. I tried to omit 'static' import in my code, but the compiler wouldn't have any of it. Why is static necessary for the code to work?
7 年多之前 回复

If you need a simple list of size 1:

List<String> strings = new ArrayList<String>(Collections.singletonList("A"));

If you need a list of several objects:

List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");

It would be simpler if you were to just declare it as a List - does it have to be an ArrayList?

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

Or if you have only one element:

List<String> places = Collections.singletonList("Buenos Aires");

This would mean that places is immutable (trying to change it will cause an UnsupportedOperationException exception to be thrown).

To make a mutable list that is a concrete ArrayList you can create an ArrayList from the immutable list:

ArrayList<String> places = new ArrayList<>(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
csdnceshi76
斗士狗 "trying to change it will cause an exception to be thrown" <- only for operations which change the size of the list. places.set(0, "New York") should work fine.
6 年多之前 回复
csdnceshi54
hurriedly% remove and clear are optional operations in List, so asList(...) does follow the contract. Nowhere does the OP say he needs to add more elements later, the example is just of a List that needs to be initialized with three elements.
大约 8 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 Just to be clear, asList(...) returns a fixed size List that blows up on mutating operations like remove and clear, things the List contract claims to support. Even if you left declaration as List, you sill need to use List l = new ArrayList(asList(...)) in order to get an object that doesn't throw OperationNotSupported exceptions. Liskov Substitution Principle anyone?
8 年多之前 回复
csdnceshi54
hurriedly% True, except that's because of using asList(...), not because of changing the declaration from ArrayList to List. I would put it as "he will not need to use places.add("blabla")". He already changed it to asList(...) himself.
大约 9 年之前 回复
weixin_41568110
七度&光 Hammarström: if he changes the declaration to List and uses the List<String> places = Arrays.asList(...); he will not be able to use places.add("blabla")
大约 9 年之前 回复
csdnceshi54
hurriedly% As per my answer, if you're not using methods specific to ArrayList, it would be better design to change the declaration to List. Specify interfaces, not implementations.
大约 10 年之前 回复
csdnceshi65
larry*wei Monkey: I wanted to know how to initialize an ArrayList. It's not real code, I was just testing things out. So, yes I might change it to List, but that would not answer my question.
11 年多之前 回复
csdnceshi51
旧行李 Can you not change your class to use a List instead of ArrayList?
11 年多之前 回复
csdnceshi65
larry*wei Yes, my class has an private ArrayList<String>.
11 年多之前 回复
import com.google.common.collect.ImmutableList;

....

List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
csdnceshi74
7*4 There is no way this is worth it. Have you seen the answers above? There isn't a need to download a new dependency,
4 年多之前 回复
csdnceshi54
hurriedly% You're going to pass that ImmutableList to other methods that take a List, and then you've lost that documentation anyway.
6 年多之前 回复
weixin_41568110
七度&光 Instead of the immutable one, google collections also offer mutable array list: List<String> = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");
大约 8 年之前 回复
weixin_41568196
撒拉嘿哟木头 No, it's not the same. As ImmutableList is documenting its immutability in the result type when unmodifiableList masquerades it as a normal List.
接近 10 年之前 回复
csdnceshi54
hurriedly% That's the same as Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")), which becomes unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata")) with static imports. You don't need Google Collections for this.
大约 10 年之前 回复
csdnceshi50
三生石@ I don't want to add a new dependency just to do that.
10 年多之前 回复

You can use the below statements:

Code Snippet:

String [] arr = {"Sharlock", "Homes", "Watson"};

List<String> names = Arrays.asList(arr);
csdnceshi59
ℙℕℤℝ You can inline first expression to have compact solution: letters = Arrays.asList(new String[]{"A", "B", "C"});
2 年多之前 回复

Here is code by AbacusUtil

// ArrayList
List<String> list = N.asList("Buenos Aires", "Córdoba", "La Plata");
// HashSet
Set<String> set = N.asSet("Buenos Aires", "Córdoba", "La Plata");
// HashMap
Map<String, Integer> map = N.asMap("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);

// Or for Immutable List/Set/Map
ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);

// The most efficient way, which is similar with Arrays.asList(...) in JDK. 
// but returns a flexible-size list backed by the specified array.
List<String> set = Array.asList("Buenos Aires", "Córdoba", "La Plata");

Declaration: I'm the developer of AbacusUtil.

Simply use below code as follows.

List<String> list = new ArrayList<String>() {{
            add("A");
            add("B");
            add("C");
}};
weixin_41568126
乱世@小熊 double braces initialization should be avoided as far as possible. see : stackoverflow.com/a/924326/760393
接近 4 年之前 回复
csdnceshi61
derek5. You can use this method to declare the list before entering any method. So when defining class variables, content can be added to the list without having to invoke a method to do so.
大约 6 年之前 回复

Like Tom said:

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

But since you complained of wanting an ArrayList, you should firstly know that ArrayList is a subclass of List and you could simply add this line:

ArrayList<String> myPlaces = new ArrayList(places);

Although, that might make you complain of 'performance'.

In that case it doesn't make sense to me, why, since your list is predefined it wasn't defined as an array (since the size is known at time of initialisation). And if that's an option for you:

String[] places = {"Buenos Aires", "Córdoba", "La Plata"};

In case you don't care of the minor performance differences then you can also copy an array to an ArrayList very simply:

ArrayList<String> myPlaces = new ArrayList(Arrays.asList(places));

Okay, but in future you need a bit more than just the place name, you need a country code too. Assuming this is still a predefined list which will never change during run-time, then it's fitting to use an enum set, which would require re-compilation if the list needed to be changed in the future.

enum Places {BUENOS_AIRES, CORDOBA, LA_PLATA}

would become:

enum Places {
    BUENOS_AIRES("Buenos Aires",123),
    CORDOBA("Córdoba",456),
    LA_PLATA("La Plata",789);

    String name;
    int code;
    Places(String name, int code) {
      this.name=name;
      this.code=code;
    }
}

Enum's have a static values method that returns an array containing all of the values of the enum in the order they are declared, e.g.:

for (Places p:Places.values()) {
    System.out.printf("The place %s has code %d%n",
                  p.name, p.code);
}

In that case I guess you wouldn't need your ArrayList.

P.S. Randyaa demonstrated another nice way using the static utility method Collections.addAll.

Try with this code line:

Collections.singletonList(provider)
csdnceshi57
perhaps? Add a brief description of your answer.
4 年多之前 回复
共30条数据 1 3 尾页
立即提问