478

我正在使用 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(), ...</p>

targetLongList有没有办法可以通过第三行直接分配变量?

4

15 回答 15

653

如果您的流保持顺序,您正在做的可能是最简单的方法 - 否则您将不得不在forEach.

forEach(targetLongList::add)[稍后编辑:调用sequential() 是必要的原因是,如果流是并行的,则代码( ) 将是活泼的。即使这样,它也不会达到预期的效果,因为forEach它是明确的非确定性的——即使在顺序流中,也不能保证元素处理的顺序。您必须使用forEachOrdered以确保正确排序。Stream API 设计者的意图是您将在这种情况下使用收集器,如下所示。]

另一种选择是

targetLongList = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(Collectors.toList());
于 2013-02-12T12:22:50.387 回答
192

更新:

另一种方法是使用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));
于 2013-03-17T06:28:20.593 回答
13

我喜欢使用一个 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);
}

有了这个答案,我还想展示创建和使用自定义收集器是多么简单,这通常非常有用。

于 2015-11-20T09:15:39.923 回答
6
collect(Collectors.toList());

这是您可以用来将任何 Stream 转换为 List 的调用。

更具体地说:

    List<String> myList = stream.collect(Collectors.toList()); 

从:

https://www.geeksforgeeks.org/collectors-tolist-method-in-java-with-examples/

于 2017-09-18T10:03:46.913 回答
5

如果您有一组原语,则可以使用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 Collections 的贡献者。

于 2016-03-27T00:08:41.900 回答
5

更有效的方法(避免创建源列表和过滤器自动拆箱):

List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
    .filter(l -> l > 100)
    .boxed()
    .collect(Collectors.toList());
于 2016-10-06T07:13:23.923 回答
4

Java 16 中有一个新方法Stream.toList() :

List<Long> targetLongList = sourceLongList
         .stream()
         .filter(l -> l > 100)
         .toList();
于 2021-01-04T08:36:03.173 回答
1

如果您不介意使用 3rd 方库,AOL 的cyclops-react库(披露我是贡献者)具有所有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)

于 2016-02-25T10:18:01.997 回答
1

LongStream 类和类似的 IntStream 和 DoubleStream 类提供了 collect 方法的另一种变体。

<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) 一样,collect 操作可以并行化,无需额外同步。这是终端操作。

用这个收集方法回答你的问题如下:

    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);
于 2019-01-25T11:57:29.987 回答
0

如果有人(像我一样)正在寻找处理对象而不是原始类型的方法,那么使用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
于 2015-10-02T15:42:21.093 回答
0

这是AbacusUtil的代码

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

披露:我是 AbacusUtil 的开发者。

于 2016-12-02T07:46:37.757 回答
0
String joined = 
                Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
                      .filter(s -> s != null && !s.isEmpty())
                      .collect(Collectors.joining(","));
于 2017-02-23T22:54:23.510 回答
0

您可以重写代码如下:

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());
于 2019-07-26T12:15:06.483 回答
0

在可变列表中收集:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toList());

在不可变列表中收集:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toUnmodifiableList());

collect来自JavaDoc的解释:

使用收集器对此流的元素执行可变归约操作。Collector 封装了用作 collect(Supplier, BiConsumer, BiConsumer) 的参数的函数,允许重用收集策略和组合收集操作,例如多级分组或分区。如果流是并行的,并且收集器是并发的,并且流是无序的或收集器是无序的,则将执行并发归约(有关并发归约的详细信息,请参阅收集器。)

这是终端操作。

当并行执行时,可以实例化、填充和合并多个中间结果,以保持可变数据结构的隔离。因此,即使与非线程安全的数据结构(例如 ArrayList)并行执行,也不需要额外的同步来进行并行归约。

于 2020-06-06T18:25:20.177 回答
-3

如果你不使用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());
于 2016-08-12T07:04:25.367 回答