Получение списка из java.util.stream.Stream в Java 8
Я играл с Java 8 lambdas, чтобы легко фильтровать коллекции. Но я не нашел краткого способа получить результат как новый список в одном и том же выражении. Вот мой самый краткий подход:
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<>();
sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add);
Примеры в сети не ответили на мой вопрос, потому что они останавливаются, не создавая новый список результатов. Должен быть более сжатый способ. Я бы предположил, что класс Stream
имеет методы как toList()
, toSet()
,...
Есть ли способ, которым переменные targetLongList
могут быть напрямую назначены третьей строкой?
Ответы
Ответ 1
То, что вы делаете, может быть самым простым способом, если ваш поток остается последовательным и в противном случае вам придется поместить вызов в последовательный() до forEach
.
[позже изменить: причина, по которой необходим вызов для последовательного(), состоит в том, что код в его начале (forEach(targetLongList::add)
) был бы ярким, если бы поток был параллельным. Даже тогда он не достигнет предполагаемого эффекта, так как forEach
явно недетерминирован и даже в последовательном потоке порядок обработки элементов не гарантируется. Вы должны использовать forEachOrdered
для обеспечения правильного упорядочения. Намерение дизайнеров Stream API состоит в том, что вы будете использовать коллекционер в этой ситуации, как показано ниже.]
Альтернативой является
targetLongList = sourceLongList.stream()
.filter(l -> l > 100)
.collect(Collectors.toList());
Ответ 2
Обновлено:
Другой подход заключается в использовании Collectors.toList
:
targetLongList =
sourceLongList.stream().
filter(l -> l > 100).
collect(Collectors.toList());
Предыдущее решение:
Другой подход заключается в использовании Collectors.toCollection
:
targetLongList =
sourceLongList.stream().
filter(l -> l > 100).
collect(Collectors.toCollection(ArrayList::new));
Ответ 3
Мне нравится использовать метод util, который возвращает коллекционер для ArrayList
, когда это то, что я хочу.
Я думаю, что решение, использующее Collectors.toCollection(ArrayList::new)
, слишком шумно для такой общей операции.
Пример:
ArrayList<Long> result = sourceLongList.stream()
.filter(l -> l > 100)
.collect(toArrayList());
public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
return Collectors.toCollection(ArrayList::new);
}
С этим ответом я также хочу продемонстрировать, насколько просто создавать и использовать пользовательские коллекторы, что очень полезно в целом.
Ответ 4
Если у вас есть массив примитивов, вы можете использовать примитивные коллекции, доступные в Eclipse Collections.
LongList sourceLongList = LongLists.mutable.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
LongList targetLongList = sourceLongList.select(l -> l > 100);
Если вы не можете изменить sourceLongList с List
:
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList =
ListAdapter.adapt(sourceLongList).select(l -> l > 100, new ArrayList<>());
Если вы хотите использовать LongStream
:
long[] sourceLongs = new long[]{1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L};
LongList targetList =
LongStream.of(sourceLongs)
.filter(l -> l > 100)
.collect(LongArrayList::new, LongArrayList::add, LongArrayList::addAll);
Примечание. Я участвую в коллекциях Eclipse.
Ответ 5
Немного более эффективный способ (не создавайте исходный список и автоматическую распаковку фильтра):
List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
.filter(l -> l > 100)
.boxed()
.collect(Collectors.toList());
Ответ 6
collect(Collectors.toList());
Это вызов, который вы можете использовать для преобразования любого потока в список.
Ответ 7
Если вы не возражаете против использования сторонних библиотек, AOL cyclops-react lib (раскрытие я являюсь вкладчиком) имеет расширения для всех JDK Collection, включая List. Интерфейс ListX расширяет java.util.List и добавляет большое количество полезных операторов, включая фильтр.
Вы можете просто написать -
ListX<Long> sourceLongList = ListX.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
ListX<Long> targetLongList = sourceLongList.filter(l -> l > 100);
ListX также может быть создан из существующего списка (через ListX.fromIterable)
Ответ 8
Существует еще один вариант метода сбора данных, предоставляемый классом LongStream, а также классами IntStream и DoubleStream.
<R> R collect(Supplier<R> supplier,
ObjLongConsumer<R> accumulator,
BiConsumer<R,R> combiner)
Выполняет изменяемую операцию сокращения над элементами этого потока. Изменяемое сокращение - это такое, в котором уменьшенное значение представляет собой изменяемый контейнер результатов, такой как ArrayList, и элементы включаются путем обновления состояния результата, а не путем замены результата. Это дает результат, эквивалентный:
R result = supplier.get();
for (long element : this stream)
accumulator.accept(result, element);
return result;
Как и Reduce (long, LongBinaryOperator), операции сбора могут быть распараллелены без дополнительной синхронизации. Это терминальная операция.
И ответ на ваш вопрос с этим методом сбора, как показано ниже:
LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
.collect(ArrayList::new, (list, value) -> list.add(value)
, (list1, list2) -> list1.addAll(list2));
Ниже приведен справочный вариант метода, который довольно умен, но кое-что сложно понять:
LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
.collect(ArrayList::new, List::add , List::addAll);
Ниже будет вариант HashSet:
LongStream.of(1L, 2L, 3L, 3).filter(i -> i > 2)
.collect(HashSet::new, HashSet::add, HashSet::addAll);
Аналогично вариант LinkedList выглядит так:
LongStream.of(1L, 2L, 3L, 3L)
.filter(i -> i > 2)
.collect(LinkedList::new, LinkedList::add, LinkedList::addAll);
Ответ 9
В случае, если кто-то (например, я) ищет способы использования объектов вместо примитивных типов, используйте mapToObj()
String ss = "An alternative way is to insert the following VM option before "
+ "the -vmargs option in the Eclipse shortcut properties(edit the "
+ "field Target inside the Shortcut tab):";
List<Character> ll = ss
.chars()
.mapToObj(c -> new Character((char) c))
.collect(Collectors.toList());
System.out.println("List type: " + ll.getClass());
System.out.println("Elem type: " + ll.get(0).getClass());
ll.stream().limit(50).forEach(System.out::print);
печатает:
List type: class java.util.ArrayList
Elem type: class java.lang.Character
An alternative way is to insert the following VM o
Ответ 10
Вот код от AbacusUtil
LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();
Раскрытие информации: я разработчик AbacusUtil.
Ответ 11
String joined =
Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
.filter(s -> s != null && !s.isEmpty())
.collect(Collectors.joining(","));
Ответ 12
Вы можете переписать код, как показано ниже:
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = sourceLongList.stream().filter(l -> l > 100).collect(Collectors.toList());
Ответ 13
Если вы не используете parallel()
, это будет работать
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<Long>();
sourceLongList.stream().peek(i->targetLongList.add(i)).collect(Collectors.toList());