将数组转换为列表

57

为了将整数数组转换为整数列表,我尝试了以下几种方法:

  1. 初始化一个列表(类型为Integer),迭代数组并插入到列表中

  2. 使用Java 8流:

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

从性能的角度来看,哪个更好?


2
什么是问题? - Pavlo
为什么不使用这个方法:https://dev59.com/UXVC5IYBdhLWcg3w4VRz? - user1803551
你也可以使用 Arrays.asList()。 - Arnab Biswas
5
@ArnabBiswas 实际上不行,他必须有一个 Integer[] 而不是 int[] 才行。 - JB Nizet
1
直接使用Arrays.asList()会返回int[]列表,而不是Integer列表。 - Jobs
显示剩余2条评论
9个回答

70
第二个方法创建一个新的整数数组(第一次遍历),然后将此新数组的所有元素添加到列表中(第二次遍历)。因此,它比第一个方法效率低,因为第一个方法只进行一次遍历,不会创建不必要的整数数组。
更好的使用流的方式是:
List<Integer> list = Arrays.stream(ints).boxed().collect(Collectors.toList());

第二个代码应该与第一个代码的性能大致相同。

请注意,在这样一个小数组的情况下,不会有任何显著的差异。你应该尽量编写正确、可读、易于维护的代码,而不是关注性能。


盒装,完美! - ScanQR

64

只需尝试类似于

Arrays.asList(array)

3
但是在某些情况下,我们不需要一个不可变的集合,这可能会导致问题。 - Mikhail
13
特别是当它不能处理基本类型值的数组时: int[] array = new int[] {1,2,3,4}; Arrays.asList(array) :: List<int[]> - Zorg

23

如果您不想改变列表:

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

但是如果您想修改它,可以使用以下方法:

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

或者只需像以下这样使用Java 8:

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

Java9 引入了这个方法:

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

然而,这会返回一个不可变的列表,您无法添加元素。

要使其可变,需要执行以下操作:

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

2
如果您不介意使用第三方依赖,您可以使用原生支持基本类型集合(如Eclipse Collections)的库,从而完全避免装箱操作。如果需要,您还可以使用基本类型集合创建装箱的常规集合。
int[] ints = {1, 2, 3};
MutableIntList intList = IntLists.mutable.with(ints);
List<Integer> list = intList.collect(Integer::valueOf);

如果你最终想要盒装集合(boxed collection),那么 IntArrayList 上的 collect 代码实际上是在做什么呢:
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;
}

由于问题特别涉及性能,我使用了您提供的解决方案、得票最高的答案以及 Eclipse Collections 的基本类型和封装类型,编写了一些 JMH 基准测试。
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);
    }
}

这些是在我的Mac Book Pro上进行的测试结果。单位是每秒操作次数,数字越大越好。我在ecPrimitive基准测试中使用了ImmutableIntList,因为Eclipse Collections中的MutableIntList默认不会复制数组。它只是适配你提供的数组。这导致ecPrimitive报告更大的数字,但误差非常大,因为它本质上只测量了单个对象创建的成本。
# 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

如果有人发现基准测试存在问题,我很乐意进行更正并重新运行测试。
注:我是 Eclipse Collections 的提交者。

0
Arrays.stream(ints).forEach(list::add);

这基本上是使用Java 8执行1(迭代数组)和2(使用Java 8)。(其中1和2指的是您最初的问题)


0

第一种方式更好,第二种方式需要更多的时间来创建一个新数组并转换为列表。


0

0

如果你处理的是String[]而不是int[],我们可以使用

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

-4

int numeros[] = {4, 10, 7, 25, 60, 1}; List lista = IntStream.of(numeros).boxed().collect(Collectors.toList());

int数组numeros[] = {4, 10, 7, 25, 60, 1}; List列表 = IntStream.of(numeros).boxed().collect(Collectors.toList());


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接