Converting Array to List

匿名 (未验证) 提交于 2019-12-03 02:47:02

问题:

In order to convert an Integer array to a list of integer I have tried the following approaches:

  1. Initialize a list(Integer type), iterate over the array and insert into the list

  2. By using Java 8 Streams:

    int[] ints = {1, 2, 3}; List<Integer> list = new ArrayList<Integer>(); Collections.addAll(list, Arrays.stream(ints).boxed().toArray(Integer[]::new)); 

Which is better in terms of performance?

回答1:

The second one creates a new array of Integers (first pass), and then adds all the elements of this new array to the list (second pass). It will thus be less efficient than the first one, which makes a single pass and doesn't create an unnecessary array of Integers.

A better way to use streams would be

List<Integer> list = Arrays.stream(ints).boxed().collect(Collectors.toList()); 

Which should have roughly the same performance as the first one.

Note that for such a small array, there won't be any significant difference. You should try to write correct, readable, maintainable code instead of focusing on performance.



回答2:

Simply try something like

Arrays.asList(array) 


回答3:

If you are dealing with String[] instead of int[], We can use

ArrayList<String> list = new ArrayList<>(); list.addAll(Arrays.asList(StringArray)); 


回答4:

If you don't want to alter the list:

List<Integer> list = Arrays.asList(array) 

But if you want to modify it then you can use this:

List<Integer> list = new ArrayList<Integer>(Arrays.asList(ints)); 

Or just use java8 like the following:

List<Integer> list = Arrays.stream(ints).collect(Collectors.toList()); 

Java9 has introduced this method:

List<Integer> list = List.of(ints); 

However, this will return an immutable list that you can't add to.

You need to do the following to make it mutable:

List<Integer> list = new ArrayList<Integer>(List.of(ints)); 


回答5:

If you don't mind a third-party dependency, you could use a library which natively supports primitive collections like Eclipse Collections and avoid the boxing altogether. You can also use primitive collections to create boxed regular collections if you need to.

int[] ints = {1, 2, 3}; MutableIntList intList = IntLists.mutable.with(ints); List<Integer> list = intList.collect(Integer::valueOf); 

If you want the boxed collection in the end, this is what the code for collect on IntArrayList is doing under the covers:

public <V> MutableList<V> collect(IntToObjectFunction<? extends V> function) {     return this.collect(function, FastList.newList(this.size)); }  public <V, R extends Collection<V>> R collect(IntToObjectFunction<? extends V> function,                                                R target) {     for (int i = 0; i < this.size; i++)     {         target.add(function.valueOf(this.items[i]));     }     return target; } 

Since the question was specifically about performance, I wrote some JMH benchmarks using your solutions, the most voted answer and the primitive and boxed versions of Eclipse Collections.

import org.eclipse.collections.api.list.primitive.IntList; import org.eclipse.collections.impl.factory.primitive.IntLists; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder;  import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream;  @State(Scope.Thread) @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @Fork(2) public class IntegerArrayListFromIntArray {     private int[] source = IntStream.range(0, 1000).toArray();      public static void main(String[] args) throws RunnerException     {         Options options = new OptionsBuilder().include(                 ".*" + IntegerArrayListFromIntArray.class.getSimpleName() + ".*")                 .forks(2)                 .mode(Mode.Throughput)                 .timeUnit(TimeUnit.SECONDS)                 .build();         new Runner(options).run();     }      @Benchmark     public List<Integer> jdkClassic()     {         List<Integer> list = new ArrayList<>(source.length);         for (int each : source)         {             list.add(each);         }         return list;     }      @Benchmark     public List<Integer> jdkStreams1()     {         List<Integer> list = new ArrayList<>(source.length);         Collections.addAll(list,                 Arrays.stream(source).boxed().toArray(Integer[]::new));         return list;     }      @Benchmark     public List<Integer> jdkStreams2()     {         return Arrays.stream(source).boxed().collect(Collectors.toList());     }      @Benchmark     public IntList ecPrimitive()     {         return IntLists.immutable.with(source);     }      @Benchmark     public List<Integer> ecBoxed()     {         return IntLists.mutable.with(source).collect(Integer::valueOf);     } } 

These are the results from these tests on my Mac Book Pro. The units are operations per second, so the bigger the number, the better. I used an ImmutableIntList for the ecPrimitive benchmark, because the MutableIntList in Eclipse Collections doesn't copy the array by default. It merely adapts the array you give it. This was reporting even larger numbers for ecPrimitive, with a very large margin of error because it was essentially measuring the cost of a single object creation.

# Run complete. Total time: 00:06:52  Benchmark                                  Mode  Cnt        Score      Error  Units IntegerArrayListFromIntArray.ecBoxed      thrpt   40   191671.859 ± 2107.723  ops/s IntegerArrayListFromIntArray.ecPrimitive  thrpt   40  2311575.358 ± 9194.262  ops/s IntegerArrayListFromIntArray.jdkClassic   thrpt   40   138231.703 ± 1817.613  ops/s IntegerArrayListFromIntArray.jdkStreams1  thrpt   40    87421.892 ± 1425.735  ops/s IntegerArrayListFromIntArray.jdkStreams2  thrpt   40   103034.520 ± 1669.947  ops/s 

If anyone spots any issues with the benchmarks, I'll be happy to make corrections and run them again.

Note: I am a committer for Eclipse Collections.



回答6:

Old way but still working!

 int[] values = {1,2,3,4};  List<Integer> list = new ArrayList<>(values.length);   for(int valor : values) {      list.add(valor);  } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!