Преобразование массива в список

Чтобы преобразовать массив Integer в список integer, я пробовал следующие подходы:

  • Инициализировать список (тип Integer), перебрать массив и вставить в список

  • Используя Java 8 Streams:

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

Что лучше с точки зрения производительности?

Ответы

Ответ 1

Второй создает новый массив целых чисел (первый проход), а затем добавляет все элементы этого нового массива в список (второй проход). Таким образом, он будет менее эффективным, чем первый, который делает один проход и не создает ненужный массив целых чисел.

Лучшим способом использования потоков будет

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

который должен иметь примерно такую ​​же производительность, как и первая.

Обратите внимание, что для такого небольшого массива существенной разницы не будет. Вы должны попытаться написать правильный, читаемый, поддерживаемый код, а не фокусироваться на производительности.

Ответ 2

Просто попробуйте что-нибудь вроде

Arrays.asList(array)

Ответ 3

Если вы не хотите изменять список:

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

Но если вы хотите изменить его, вы можете использовать это:

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

Или просто используйте java8, как показано ниже:

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));

Ответ 4

Если вы имеете дело со строкой [] вместо int [], мы можем использовать

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

Ответ 5

Если вы не возражаете против сторонней зависимости, вы можете использовать библиотеку, которая изначально поддерживает коллекции примитивов, такие как Eclipse Collections, и вообще избегать упаковки. При необходимости вы также можете использовать примитивные коллекции для создания регулярных коллекций в штучной упаковке.

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

Если вы хотите получить упакованную коллекцию в конце, то, что делает код для collect в IntArrayList под прикрытием:

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;
}

Поскольку вопрос был конкретно о производительности, я написал несколько тестов JMH, используя ваши решения, ответ с наибольшим количеством голосов, а также примитивную и коробочную версии 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);
    }
}

Это результаты этих тестов на моем Mac Book Pro. Единицы - это операции в секунду, поэтому чем больше число, тем лучше. Я использовал ImmutableIntList для ecPrimitive теста, потому что MutableIntList в Eclipse, коллекции не копирует массив по умолчанию. Он просто адаптирует массив, который вы ему передаете. Это сообщало о еще больших числах для ecPrimitive, с очень большим пределом погрешности, потому что это по существу 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.

Ответ 6

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

Это в основном делает 1 (итерация по массиву) с 2 (используя Java 8). (с 1 и 2 со ссылкой на ваш оригинальный вопрос)

Ответ 8

Старый способ, но все еще работает!

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

 for(int valor : values) {
     list.add(valor);
 }