我正在使用 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
可以直接由第三行赋值?
sourceLongList
,那么为了方便起见,可以使用 Collection.removeIf(…)
。
List<Long> targetLongList = sourceLongList.stream().collect(Collectors.toList());
您所做的可能是最简单的方法,前提是您的流保持顺序 - 否则您必须在 forEach
之前调用 sequence()。
[稍后编辑:调用sequential() 是必要的原因是,如果流是并行的,则代码(forEach(targetLongList::add)
) 将是活泼的。即使这样,它也不会达到预期的效果,因为 forEach
是明确的不确定性——即使在顺序流中,也不能保证元素处理的顺序。您必须使用 forEachOrdered
来确保正确排序。 Stream 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));
Collectors::toList
javadoc:“无法保证返回的 List 的类型、可变性、可序列化性或线程安全性;如果需要对返回的 List 进行更多控制,请使用 toCollection(Supplier)
。 "
我喜欢使用一个 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);
}
有了这个答案,我还想展示创建和使用自定义收集器是多么简单,这通常非常有用。
toList
不是一个好主意。 toList
documentation 表示:“无法保证返回的 List 的类型、可变性、可序列化性或线程安全性;如果需要对返回的 List 进行更多控制,请使用 toCollection
。”我>。我的回答展示了一种在常见情况下更方便执行此操作的方法。
collect(Collectors.toList());
这是您可以用来将任何 Stream 转换为 List 的调用。
更具体地说:
List<String> myList = stream.collect(Collectors.toList());
从:
https://www.geeksforgeeks.org/collectors-tolist-method-in-java-with-examples/
Java 16 中有一个新方法 Stream.toList():
List<Long> targetLongList = sourceLongList
.stream()
.filter(l -> l > 100)
.toList();
如果您有一个基元数组,则可以使用 Eclipse Collections 中提供的基元集合。
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 的贡献者。
更有效的方法(避免创建源列表和过滤器自动拆箱):
List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
.filter(l -> l > 100)
.boxed()
.collect(Collectors.toList());
如果您不介意使用第 3 方库,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)
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);
在可变列表中收集:
targetList = sourceList.stream()
.filter(i -> i > 100) //apply filter
.collect(Collectors.toList());
在不可变列表中收集:
targetList = sourceList.stream()
.filter(i -> i > 100) //apply filter
.collect(Collectors.toUnmodifiableList());
JavaDoc 对 collect
的解释:
使用收集器对此流的元素执行可变归约操作。 Collector 封装了用作 collect(Supplier, BiConsumer, BiConsumer) 的参数的函数,允许重用收集策略和组合收集操作,例如多级分组或分区。如果流是并行的,并且收集器是并发的,并且流是无序的或者收集器是无序的,则将执行并发归约(有关并发归约的详细信息,请参见收集器。)这是一个终端操作。当并行执行时,可以实例化、填充和合并多个中间结果,以保持可变数据结构的隔离。因此,即使与非线程安全的数据结构(例如 ArrayList)并行执行,也不需要额外的同步来进行并行归约。
如果有人(像我一样)正在寻找处理对象而不是原始类型的方法,请使用 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
String joined =
Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
.filter(s -> s != null && !s.isEmpty())
.collect(Collectors.joining(","));
这是AbacusUtil的代码
LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();
披露:我是 AbacusUtil 的开发者。
com.landawn.abacus.util.stream.LongStream
或 LongStreamEx
您可以重写代码如下:
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());
如果您不使用 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());
collect
然后不保存返回值是很奇怪的。在这种情况下,您可以改用 forEach
。但这仍然是一个糟糕的解决方案。
toList
的静态导入,我认为这段代码会变得更短、更清晰、更漂亮。这是通过在文件的导入中放置以下内容来完成的:static import java.util.stream.Collectors.toList;
。然后对方付费电话仅读取.collect(toList())
。Collectors
类来完成的。 Java -> 编辑器 -> 内容辅助 -> 收藏夹。在此之后,您只需在点击 Ctr+Space 处键入toLi
即可让 IDE 填写toList
并添加静态导入。IntStream
和其他一些几乎但不完全的Stream
没有collect(Collector)
方法,您必须调用IntStream.boxed()
才能将它们转换为常规 { 2} 首先。再说一次,也许你只想要toArray()
。forEach
之前使用sequential()
或使用“forEachOrdered”