Initialization of an ArrayList in one line

后端 未结 30 2062
北恋
北恋 2020-11-22 01:10

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

ArrayList places = new ArrayList();
places.add(\         


        
相关标签:
30条回答
  • 2020-11-22 01:40

    The simple answer

    In Java 9 or later, after List.of() was added:

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

    With Java 10 or later, this can be shortened with the var keyword.

    var 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.


    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 List.of method to of, because that 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:

    import static java.util.stream.Collectors.toList;
    
    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

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

    or in Java 8 or earlier:

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

    or using Stream:

    import static java.util.stream.Collectors.toCollection;
    
    ArrayList<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, 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 .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 讨论(0)
  • 2020-11-22 01:40

    In Java 9 we can easily initialize an ArrayList in a single line:

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

    or

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

    This new approach of Java 9 has many advantages over the previous ones:

    1. Space Efficiency
    2. Immutability
    3. Thread Safe

    See this post for more details -> What is the difference between List.of and Arrays.asList?

    0 讨论(0)
  • 2020-11-22 01:41
    import com.google.common.collect.ImmutableList;
    
    ....
    
    List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
    
    0 讨论(0)
  • 2020-11-22 01:41

    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.

    0 讨论(0)
  • 2020-11-22 01:42

    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.

    0 讨论(0)
  • 2020-11-22 01:42

    In Java, you can't do

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

    As was pointed out, you'd need to do a double brace initialization:

    List<String> places = new ArrayList<String>() {{ add("x"); add("y"); }};
    

    But this may force you into adding an annotation @SuppressWarnings("serial") or generate a serial UUID which is annoying. Also most code formatters will unwrap that into multiple statements/lines.

    Alternatively you can do

    List<String> places = Arrays.asList(new String[] {"x", "y" });
    

    but then you may want to do a @SuppressWarnings("unchecked").

    Also according to javadoc you should be able to do this:

    List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
    

    But I'm not able to get it to compile with JDK 1.6.

    0 讨论(0)
提交回复
热议问题