Получение списка из java.утиль.поток.Поток в 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 класс имеет методы as toList(), toSet(),...

есть таким образом, переменные targetLongList может быть непосредственно назначен третьей строкой?

11 ответов


то, что вы делаете, может быть самым простым способом, если ваш поток остается последовательным-в противном случае вам придется вызвать sequential() перед forEach.

[позже edit: причина вызова sequential () заключается в том, что код в его нынешнем виде (forEach(targetLongList::add)) было бы колоритно, если бы поток был параллельным. Даже тогда он не достигнет запланированного эффекта, как forEach явно недетерминирован-даже в последовательном потоке порядок обработки элементов не является гарантированный. Вам придется использовать forEachOrdered для обеспечения правильного заказ. Дизайнеры Stream API намерены использовать collector в этой ситуации, как показано ниже.]

альтернатива

targetLongList = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(Collectors.toList());

другой подход-использовать Collectors.toCollection:

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toList());

мне нравится использовать метод 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);
}

С этим ответом я также хочу продемонстрировать, насколько просто создавать и использовать пользовательские коллекторы, что очень полезно в целом.


если у вас есть массив примитивов, вы можете использовать примитивные коллекции, доступные в Коллекции Eclipse.

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.


немного более эффективный способ (избегайте создания списка источников и автоматической распаковки фильтром):

List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
    .filter(l -> l > 100)
    .boxed()
    .collect(Collectors.toList());

collect(Collectors.toList());

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


Если вы не против использования сторонних библиотек, aol's Циклоп-реагировать lib (disclosure I am a contributor) имеет расширения для всех коллекция JDK типы, в том числе список. Интерфейс ListX расширяет java.утиль.Список и добавляет большое количество полезных операторов, включая фильтр.

вы можете просто написать -

ListX<Long> sourceLongList = ListX.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
ListX<Long> targetLongList = sourceLongList.filter(l -> l > 100);

ListX также может быть создан из существующего списка (через ListX.fromIterable)


в случае, если кто-то (как я) ищет способы борьбы с объектами вместо примитивных типов, используйте 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

здесь код AbacusUtil

LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();

раскрытие информации: я разработчик AbacusUtil.


String joined = 
                Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
                      .filter(s -> s != null && !s.isEmpty())
                      .collect(Collectors.joining(","));

Если вы не используете 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());