6

I've learned today that you can create a new ArrayList object utilizing a static method like so:

List<String> listDummy = Arrays.asList("Coding", "is", "fun"); 
ArrayList<String> stringList = new ArrayList<>(listDummy);

Or even more concisely:

ArrayList<String> stringList = new ArrayList<>(Arrays.asList("Coding", "is", "fun"));

My question is: How expensive is this performance-wise compared to the "traditional" way? (below)

ArrayList<String> stringList = new ArrayList<>();
stringList.add("Coding");
stringList.add("is");
stringList.add("fun");

I realize the upper way of creating an ArrayList includes an extra List object creation, however, I prefer the shorter and more compact syntax to an extent that I'm willing to sacrifice some performance but gotta draw the line somewhere.

PS. leaving the type information(<>) empty in "new ArrayList<>()" is a Java SE 7 feature, not an error.

Thank you beforehand for any answers!

straville
  • 986
  • 3
  • 15
  • 21

7 Answers7

5

The performance difference is likely to be 30 - 300 ns depending on your system and how warmed up your code is. I suspect the performance difference is small.

I always say, if in doubt; write the code as simpler and clear as you can and it will often perform ok as well.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

The usual add() way calls three methods.

The asList() way makes an array, then does clone() on it (which does a shallow copy), then does copy all the elements manually because of this bug. And afterwards, if you want to add another element to stringList, the array will have to be made larger and elements re-copied, because the size was exact for the elements provided. (all this is implementation dependant and assumes Oracle JDK)

For three elements, the latter will be slower, but for any practical use, it will be negligible. For many elements, the two approaches might get equal in performance and the former one might even get slower.

Write what you think will read the best, the performance penalty is minimal and you should not care about it until it proves itself to be bottleneck.


All that said, if you're after consice syntax, you could like Google Guava's Lists:

List<String> stringList = Lists.newArrayList("Coding", "is", "fun");

I haven't used a classic ArrayList constructor for quite a while now.

Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
  • 1
    Accepting this one. @Peter Lawrey had similar answer right off the bat, but this one goes a bit deeper. Thank you all for your insights! – straville Jun 11 '13 at 11:11
1

You can do it in one line without creating additional lists:

ArrayList<String> stringList = new ArrayList<>(){{
    add("Coding");
    add("is");
    add("fun");
}};

This is an anonymous class, which is a subclass of ArrayList, with an instance block.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • +1 – Wow, that's some nice and creative abuse of Java syntax! :) – thejh Jun 11 '13 at 10:18
  • 4
    but anonymous inner classes are rather slow, and its not *really* 1 line. I used to like double brace initialization, but everyone else seems to dislike them. – NimChimpsky Jun 11 '13 at 10:19
  • 2
    @Dariusz: He's making an anonymous class (a class without its own name) that extends `ArrayList`. This class has an instance block in it, that's a piece of code that runs whenever a new instance of the class is created. – thejh Jun 11 '13 at 10:21
  • @nim why do you say they are slow? Do you have evidence of slowness? – Bohemian Jun 11 '13 at 10:22
  • Well you create an anonymous class with an anonymous initializer. A lot of work for simply initializing a list plus it's not exactly concise. I would stick to Arrays.asList... – Jan Thomä Jun 11 '13 at 10:22
  • 1
    @Bohemian yes, give me a min - well there is a benchmark on stackoverflow. They are very much slower. I used to use this style all over the place, then i read lots of answers where people didn't like it, and then I found the performance benchmark. I realized its really not any better than just doing stringlist.add() without the double brace initialization - it just looks *tricky*. – NimChimpsky Jun 11 '13 at 10:22
  • http://stackoverflow.com/questions/924285/efficiency-of-java-double-brace-initialization – NimChimpsky Jun 11 '13 at 10:25
  • @NimChimpsky: That benchmark only proves that loading 1000 classes takes longer than loading 1 class... – jlordo Jun 11 '13 at 10:39
  • @jlordo doesn't really matter why it is slower. Only that it is. – s3rius Jun 11 '13 at 10:42
  • Ok, I don't want to have the same discussion here as in the other thread. If you benchmark a warmed up system, there will be no difference. Let's settle this with: the best solution is to use the most readable code. – jlordo Jun 11 '13 at 10:46
  • @NimChimpsky: As I see it, it shows 10 **individual runs** of each `Test` class, so there is no warmup phase before he takes the time... – jlordo Jun 11 '13 at 10:50
  • 1
    @NimChimpsky: yes, but if you take the code of that benchmark and put it in a loop, you'll get the high number for the first run of the loop, and `0` for all other runs. So, the benchmark proves that having 1000 anonymous classes is more expensive than having none, but there will be no performance difference at all once all of them are loaded (ergo, no difference after the warmup. When talking about efficiency of a car, I consider how many gallons it uses per mile, and don't care how much it uses to start the motor) – jlordo Jun 11 '13 at 10:58
  • @jlordo yeah OK, maybe they are not so bad afterall. – NimChimpsky Jun 11 '13 at 11:51
1

If you are not going to add /remove elements from the list after creation then the best way is not to create ArrayList at all, this will be really efficient

List<String> listDummy = Arrays.asList("Coding", "is", "fun"); 

otherwise new ArrayList<>(listDummy) is more efficient than manual adding elements one by one, see ArrayList(Collection) src:

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

it's optimized:

1) it creates the array of exact size
2) it uses native copying of elements

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
1

The list you get from Arrays.asList is already an ArrayList, so it is not necessary to wrap it with an ArrayList again:

  public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
    }

Caveat: The list is read-only, so if you need to write it, you will need to wrap it indeed using new ArrayList(..).

Nevertheless, I think using Arrays.asList should be better than creating a list using repeated calls of "add", because the ArrayList's internal array is initialized with the correct size. So the best way would be

List<String> myList= Arrays.asList("Coding", "is", "fun");
// or if you need to write the list
List<String> myList = new ArrayList(Arrays.asList("Coding", "is", "fun"));

Also this is the most readable IMHO, and readability for me always wins over very small performance gains unless you really need that extra performance. If you really need to do performance tuning, use a profiler. The bottleneck is usually where you wouldn't expect it to be. A profiler can give you exact information about what parts of your program are slow and you can optimize them as needed.

Jan Thomä
  • 13,296
  • 6
  • 55
  • 83
0

The performance difference depends on size of the source array.

If you are adding items one by one multiple reallocations inside destination array will happen.

If you are adding whole collection at once only one allocation should be done, because the size is known beforehand.

Grzegorz Żur
  • 47,257
  • 14
  • 109
  • 105
0

I sometimes use a convenience function:

public static <T> ArrayList<T> asArrayList(T... args) {
    ArrayList<T> list = new ArrayList<T>(args.length);
    Collections.addAll(list, args);
    return list;
}

This is a bit quicker than the Arrays.asList route. (Not that it would ever really matter for hard-coded lists.)

maybeWeCouldStealAVan
  • 15,492
  • 2
  • 23
  • 32