在Java 8中从Java .util.stream. stream中检索List

我一直在使用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可以直接由第三行赋值?

414363 次浏览

你所做的可能是最简单的方法,前提是你的流保持顺序,否则你将不得不在forEach之前调用sequential()。

[稍后编辑:调用sequential()是必要的原因是,如果流是并行的,那么当前的代码(forEach(targetLongList::add))将是不正常的。即使这样,它也不会达到预期的效果,因为forEach显式是非确定性的;即使在顺序流中,元素处理的顺序也不能保证。你必须使用forEachOrdered来确保正确的顺序。流API设计者的意图是在这种情况下使用收集器,如下所示。

另一种选择是

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

更新:

另一种方法是使用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));

如果有人(比如我)正在寻找处理对象而不是基本类型的方法,那么使用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

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

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

如果你不介意使用第三方库,AOL的cyclops-react库(披露我是贡献者)有所有JDK集合类型的扩展,包括列表。ListX接口扩展了java.util.List,并添加了大量有用的操作符,包括filter。

你可以简单地写成-

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

ListX也可以从现有的List中创建(通过ListX. fromitable)

如果你有一个基元数组,你可以使用Eclipse集合中可用的基元集合。

LongList sourceLongList = LongLists.mutable.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
LongList targetLongList = sourceLongList.select(l -> l > 100);

如果你不能从List改变sourceLongList:

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的贡献者。

如果你不使用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());

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

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

下面是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(","));
collect(Collectors.toList());

这个调用可以用来将任何流转换为列表。

更具体地说:

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

来自:

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

LongStream类和提供了另一种类型的collect方法 IntStream和DoubleStream类也类似。< / p >
<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);

你可以重写代码如下:

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

在一个可变列表中收集:

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

在一个不可变列表中收集:

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

collectJavaDoc的解释:

对该流的元素执行可变约简操作 使用收集器。Collector封装用作的函数 参数来收集(Supplier, bicconsumerer, bicconsumerer),允许 收集策略的重用和收集操作的组合 例如多级分组或分区。如果流是 并行的,收集器是并发的,流是 无序或收集器无序,则并发还原

这是一个终端操作。

当并行执行时,可能会有多个中间结果 实例化、填充和合并,以保持隔离 可变数据结构。因此,即使并行执行 对于非线程安全的数据结构(比如ArrayList),没有 并行还原需要额外的同步

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

List<Long> targetLongList = sourceLongList
.stream()
.filter(l -> l > 100)
.toList();