Рассмотрим следующий код:Collection.toArray() против Collection.stream() ToArray()
List<String> myList = Arrays.asList(1, 2, 3);
String[] myArray1 = myList.toArray(new String[myList.size()]);
String[] myArray2 = myList.stream().toArray(String[]::new);
assert Arrays.equals(myArray1, myArray2);
Мне кажется, что использование потока намного проще.
Поэтому я проверял скорость каждого из них.
List<String> myList = Arrays.asList("1", "2", "3");
double start;
start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
String[] myArray1 = myList.toArray(new String[myList.size()]);
assert myArray1.length == 3;
}
System.out.println(System.currentTimeMillis() - start);
start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
String[] myArray2 = myList.stream().toArray(String[]::new);
assert myArray2.length == 3;
}
System.out.println(System.currentTimeMillis() - start);
В результате использование потока примерно в четыре раза медленнее. На моей машине 816 мс (поток) против 187 мс (без потока). Я также попытался переключить операторы синхронизации вокруг (myArray2 до myArray1), что не сильно повлияло на результаты. Почему это так медленнее? Является ли создание Stream
столь интенсивным с точки зрения вычислительной мощности?
Я последовал совету @ Хольгер и изучал немного (конечно, не достаточно) на тестировании JVM, чтение this post, this article, this article, и с помощью JMH.
Результаты (через JMH):
private static final List<String> myList = IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList());
@Benchmark
public void testMethod() {
String[] myArray = myArrayList.stream().toArray(String[]::new);
}
StreamToArrayArrayListBenchmark.testMethod avgt 5 2846,346 ± 32.500 нс/оп
private static final List<String> myList = IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList());
@Benchmark
public void testMethod() {
String[] myArray = myArrayList.toArray(new String[0]);
}
ToArrayEmptyArrayListBenchmark.testMethod avgt 5 1417.474 ± 20,725 нс/оп
private static final List<String> myList = IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList());
@Benchmark
public void testMethod() {
String[] myArray = myArrayList.toArray(new String[myList.size()]);
}
ToArraySizedArrayListBenchmark.testMethod avgt 5 1853,622 ± 178.351 нс/оп
private static final List<String> myList = new LinkedList<>(IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList()));
@Benchmark
public void testMethod() {
String[] myArray = myArrayList.stream().toArray(String[]::new);
}
StreamToArrayLinkedListBenchmark.testMethod avgt 5 4152,003 ± 59.281 нс/оп
private static final List<String> myList = new LinkedList<>(IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList()));
@Benchmark
public void testMethod() {
String[] myArray = myArrayList.toArray(new String[0]);
}
ToArrayEmptyLinkedListBenchmark.testMethod avgt 5 4089,550 ± 29.880 нс/оп
private static final List<String> myList = new LinkedList<>(IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList()));
@Benchmark
public void testMethod() {
String[] myArray = myArrayList.toArray(new String[myList.size()]);
}
ToArraySizedArrayListBenchmark.testMethod avgt 5 4115,557 ± 93.964 нс/оп
Подводя итог:
| ArrayList | LinkedList
stream | 2846 | 4152
toArray sized | 1853 | 4115
toArray empty | 1417 | 4089
Использование JMH (возможно, по наивности), я по-прежнему видим, что ArrayList::toArray
примерно в два раза быстрее, чем Stream::toArray
.Однако, похоже, это связано с тем, что ArrayList
просто выполняет копию массива, поскольку @Andreas указал, потому что, когда источником является LinkedList
, результаты примерно равны.
Это определенно полезно знать о myList.toArray(new String[0])
.
Что делать, если вы используете 'Arrays.stream()'? –
@JoshLee в моем реальном коде, у меня есть список, который я пытаюсь преобразовать в массив. Я не так, как с ним использовать Arrays.stream()? – dantiston
@ Хольджер вы говорите, отмечая это как дубликат, что мой вывод неправильный? Я не спрашиваю о том, как делать бенчмаркинг - я полагаю, что мои тесты не на 100% точны. Я действительно спрашиваю о накладных расходах «Стрим» - это не рассматривается в другом вопросе. – dantiston