无法在一个流中进行filter-> forEach-> collect?

nim*_*o23 16 java lambda java-8 java-stream

我希望实现这样的目标:

items.stream()
    .filter(s-> s.contains("B"))
    .forEach(s-> s.setState("ok"))
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

过滤,然后从过滤结果中更改属性,然后将结果收集到列表中.但是,调试器说:

无法collect(Collectors.toList())在原始类型上调用void.

我需要2个流吗?

Grz*_*rek 17

forEach被设计成一个终端操作,是的 - 你打电话后你什么也做不了.

惯用的方法是先应用转换,然后将collect()所有内容应用到所需的数据结构.

可以使用map针对非变异操作设计的变换来执行变换.

如果您正在执行非变异操作:

 items.stream()
   .filter(s -> s.contains("B"))
   .map(s -> s.withState("ok"))
   .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

where withState是一个返回原始对象副本的方法,包括提供的更改.


如果您正在执行副作用:

items.stream()
  .filter(s -> s.contains("B"))
  .collect(Collectors.toList());

items.forEach(s -> s.setState("ok"))
Run Code Online (Sandbox Code Playgroud)

  • 根据JavaDoc,peek应该用于调试:https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-另见/sf/ask/2354500221/ (2认同)
  • 在JDK 9中,澄清了`peek()`的规范,以明确实现可以优化`peek()`. (2认同)

Eug*_*ene 11

替换forEachmap.

 items.stream()
      .filter(s-> s.contains("B"))
      .map(s-> {s.setState("ok");return s;})
      .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

forEachcollect这两个终端业务-流必须只有一个.任何返回a Stream<T>intermediate operation东西都是a ,其他任何东西都是a terminal operation.


Mis*_*sha 6

抵制在没有充分理由的情况下从流内部使用副作用的冲动。制作新列表,然后应用更改:

List<MyObj> toProcess = items.stream()
    .filter(s -> s.contains("B"))
    .collect(toList());

toProcess.forEach(s -> s.setState("ok"));
Run Code Online (Sandbox Code Playgroud)


Jea*_*nès 6

forEach是一个终端操作,意味着它产生非流结果。forEach不产生任何东西并collect返回一个集合。您需要的是根据您的需要修改元素的流操作。此操作可map让您指定要应用于输入流的每个元素的函数并生成转换后的元素流。所以你需要这样的东西:

items.stream()
     .filter (s -> s.contains("B"))
     .map    (s -> { s.setState("ok"); return s; }) // need to return a value here
     .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用peek其意图是将函数应用于遍历的每个元素(但其主要目的是用于调试):

items.stream()
     .filter (s -> s.contains("B"))
     .peek   (s -> s.setState("ok")) // no need to return a value here
     .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)