306

I am aware that you can initialize an array during instantiation as follows:

String[] names = new String[] {"Ryan", "Julie", "Bob"};

Is there a way to do the same thing with an ArrayList? Or must I add the contents individually with array.add()?

bluish
  • 26,356
  • 27
  • 122
  • 180
Jonathan
  • 3,311
  • 3
  • 22
  • 15

8 Answers8

385

Arrays.asList can help here:

new ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21));
meriton
  • 68,356
  • 14
  • 108
  • 175
  • 62
    It's worth mentioning that unless you strictly need an `ArrayList` it's probably better to just use the `List` that's returned by `Arrays#asList`. – maerics May 03 '10 at 20:51
  • 26
    @maerics, it's also worth mentioning that `Arrays.asList()` return an **unmodifiable** collection. :) – Konstantin Yovkov Oct 09 '13 at 09:46
  • It will throw compilation error "The method asList(Object[]) in the type Arrays is not applicable for the arguments (int, int, int, int, int, int, int)".. – R K Jan 20 '14 at 12:30
  • Actual implementation should be "new ArrayList(Arrays.asList(new Object[]{1,2,3,5,8,13,21}));" – R K Jan 20 '14 at 12:30
  • @RK: With which compiler? My eclipse compiles it just fine ... – meriton Jan 20 '14 at 19:35
  • @meriton: I have set the compiler level and JRE pointed to 1.5... – R K Jan 21 '14 at 06:19
  • @RK: On my eclipse, it still compiles with Java 5 compliance against a JRE 6. Seing that the method signature hasn't changed since JRE 5, I doubt the JRE matters. And anyway, Java 5 had been end of live by the time I wrote this answer. (you aren't really still using it, are you?) – meriton Jan 21 '14 at 20:04
  • 14
    The list returned by `Arrays.asList()` is _NOT_ unmodifiable, @kocko. It has a fixed size, but you can change the references to point to entirely different objects like `Arrays.asList(...).set(0,new String("new string"))` This code will work and set the first element of the list to the String object with value "new string". And in fact, it writes through to the native array! Definitely _not_ unmodifiable. – Jason Apr 19 '14 at 15:22
  • 5
    Why do people never mention correct import/include/require statement in their posts? – Tomáš Zato Feb 09 '16 at 20:58
  • 3
    Because a well configured IDE will write the imports for you, as long as there is a single matching class, as is the case here. – meriton Feb 09 '16 at 22:25
  • @KonstantinYovkov ...which is entirely within the contract of a List object – forresthopkinsa Aug 14 '17 at 19:30
  • Works perfectly! – Mert Kahraman Sep 21 '18 at 07:28
64

Yes.

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

What this is actually doing is creating a class derived from ArrayList<String> (the outer set of braces do this) and then declare a static initialiser (the inner set of braces). This is actually an inner class of the containing class, and so it'll have an implicit this pointer. Not a problem unless you want to serialise it, or you're expecting the outer class to be garbage collected.

I understand that Java 7 will provide additional language constructs to do precisely what you want.

EDIT: recent Java versions provide more usable functions for creating such collections, and are worth investigating over the above (provided at a time prior to these versions)

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • Probably because people don't know this is possible. This is actually my favorite way to initialize maps and other more complex collections but for lists, i prefer Arrays.asList. – nicerobot May 03 '10 at 21:20
  • 27
    Not my downvote, but I consider this a pretty nasty abuse of anonymous classes. At least you're not trying to pass it off as a special feature... – Michael Borgwardt May 03 '10 at 21:34
  • Bad because it creates an anonymous class. – Steve Kuo May 03 '10 at 23:08
  • 7
    I don't believe that creating an anonymous class is bad *in itself*. You should be aware of it though. – Brian Agnew May 08 '10 at 08:39
  • 7
    I'm guessing that it keeps getting downvoted because it does just what the OP wanted to avoid: using add() for each element. – WXB13 Jan 14 '14 at 09:04
  • Be careful, the solution can cause memory leak – anstarovoyt Jan 15 '15 at 12:27
  • 4
    I would consider downvoting, because *creating a class*, just to initialize a single object, strikes me as overkill. But I'm not sufficiently an expert in java to know whether this is a bad thing to do. Maybe creating thousands of unnecessary classes, in a large program, is considered good java coding? Its also horrendously verbose, if there are many elements. Is there *any advantage* to this approach, versus other proposed answers? – ToolmakerSteve Sep 13 '15 at 16:40
  • 1
    It might have been downvoted because it only works for final values. I agree your solution does work for what the question asked, but you know some people are on StackOverflow. – Josh Dec 15 '15 at 16:50
  • It's probably being downvoted because, in all likelihood, the majority of the users who will use this solution will not read/understand the explanation. It's *crucial* that anyone who uses this really, fully understands what they are doing and how it works. – forresthopkinsa Aug 14 '17 at 19:28
  • 1
    While this looks nice it's a very bad idea, this will generate unnecessary class objects that will immediately need to be garbage collected. Having this in your code is inviting difficult to diagnose future memory problems just for a little syntactic sugar. – Justin Ohms Nov 15 '17 at 00:31
  • Whilst there are known downsides to such initialisation, I would question your assertion re. memory problems, particularly given the notes above and the limited scenario presented – Brian Agnew Nov 15 '17 at 09:50
  • 1
    Looks like @BrianAgnew discusses this further in [another SO answer](https://stackoverflow.com/a/1958961/1265245). – Tommy Stanton Dec 23 '18 at 20:39
  • It's not a "static initialiser" , it's an "instance initialization block" – Mideel Sep 17 '21 at 07:31
39

Here is the closest you can get:

ArrayList<String> list = new ArrayList(Arrays.asList("Ryan", "Julie", "Bob"));

You can go even simpler with:

List<String> list = Arrays.asList("Ryan", "Julie", "Bob")

Looking at the source for Arrays.asList, it constructs an ArrayList, but by default is cast to List. So you could do this (but not reliably for new JDKs):

ArrayList<String> list = (ArrayList<String>)Arrays.asList("Ryan", "Julie", "Bob")
Fred Haslam
  • 8,873
  • 5
  • 31
  • 31
  • 11
    The ArrayList constructed by asList is not a java.util.ArrayList, only shares the same. In fact, it cannot be, as the return value of asList is specified to be a fixed size list, but an ArrayList must be of variable size. – meriton May 03 '10 at 20:38
  • 1
    I stand corrected. I did not read far enough into the source. – Fred Haslam May 04 '10 at 03:28
33
Arrays.asList("Ryan", "Julie", "Bob");
Idos
  • 15,053
  • 14
  • 60
  • 75
John D
  • 786
  • 4
  • 5
9

Well, in Java there's no literal syntax for lists, so you have to do .add().

If you have a lot of elements, it's a bit verbose, but you could either:

  1. use Groovy or something like that
  2. use Arrays.asList(array)

2 would look something like:

String[] elements = new String[] {"Ryan", "Julie", "Bob"};
List list = new ArrayList(Arrays.asList(elements));

This results in some unnecessary object creation though.

jayshao
  • 2,167
  • 2
  • 15
  • 17
6

The selected answer is: ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21));

However, its important to understand the selected answer internally copies the elements several times before creating the final array, and that there is a way to reduce some of that redundancy.

Lets start by understanding what is going on:

  1. First, the elements are copied into the Arrays.ArrayList<T> created by the static factory Arrays.asList(T...).

    This does not the produce the same class as java.lang.ArrayListdespite having the same simple class name. It does not implement methods like remove(int) despite having a List interface. If you call those methods it will throw an UnspportedMethodException. But if all you need is a fixed-sized list, you can stop here.

  2. Next the Arrays.ArrayList<T> constructed in #1 gets passed to the constructor ArrayList<>(Collection<T>) where the collection.toArray() method is called to clone it.

    public ArrayList(Collection<? extends E> collection) {
    ......
    Object[] a = collection.toArray();
    }
    
  3. Next the constructor decides whether to adopt the cloned array, or copy it again to remove the subclass type. Since Arrays.asList(T...) internally uses an array of type T, the very same one we passed as the parameter, the constructor always rejects using the clone unless T is a pure Object. (E.g. String, Integer, etc all get copied again, because they extend Object).

    if (a.getClass() != Object[].class) {      
        //Arrays.asList(T...) is always true here 
        //when T subclasses object
        Object[] newArray = new Object[a.length];
        System.arraycopy(a, 0, newArray, 0, a.length);
        a = newArray;
    }
    array = a;
    size = a.length;
    

Thus, our data was copied 3x just to explicitly initialize the ArrayList. We could get it down to 2x if we force Arrays.AsList(T...) to construct an Object[] array, so that ArrayList can later adopt it, which can be done as follows:

(List<Integer>)(List<?>) new ArrayList<>(Arrays.asList((Object) 1, 2 ,3, 4, 5));

Or maybe just adding the elements after creation might still be the most efficient.

NameSpace
  • 10,009
  • 3
  • 39
  • 40
5

How about this one.

ArrayList<String> names = new ArrayList<String>();
Collections.addAll(names, "Ryan", "Julie", "Bob");
Ken de Guzman
  • 2,790
  • 1
  • 19
  • 33
2

This is how it is done using the fluent interface of the op4j Java library (1.1. was released Dec '10) :-

List<String> names = Op.onListFor("Ryan", "Julie", "Bob").get();

It's a very cool library that saves you a tonne of time.

crsedgar
  • 23
  • 2