Java 无法进行筛选->;forEach->;在一条流中收集?

Java 无法进行筛选->;forEach->;在一条流中收集?,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我想实现这样的目标: items.stream() .filter(s-> s.contains("B")) .forEach(s-> s.setState("ok")) .collect(Collectors.toList()); 筛选,然后更改筛选结果中的属性,然后将结果收集到列表中。然而,调试器说: 无法对基元类型void调用collector(Collectors.toList()) 我需要两条流吗?用map替换forEach items.stream()

我想实现这样的目标:

items.stream()
    .filter(s-> s.contains("B"))
    .forEach(s-> s.setState("ok"))
.collect(Collectors.toList());
筛选,然后更改筛选结果中的属性,然后将结果收集到列表中。然而,调试器说:

无法对基元类型
void
调用
collector(Collectors.toList())


我需要两条流吗?

map
替换
forEach

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

forEach
collect
都是终端操作-流必须只有一个。任何返回
流的操作都是
中间操作
,其他任何操作都是
终端操作

不能在同一个流上执行两个终端操作

您可以在中间操作中设置对象的状态,例如
map

List<YourClass> list = 
    items.stream()
         .filter(s-> s.contains("B"))
         .map(s-> {
                      s.setState("ok"); 
                      return s;
                  })
         .collect(Collectors.toList());
列表=
items.stream()
.filter(s->s.contains(“B”))
.map(s->{
s、 设置状态(“ok”);
返回s;
})
.collect(Collectors.toList());

没有很好的理由,不要急于使用流内部的副作用。创建新列表,然后应用更改:

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

toProcess.forEach(s -> s.setState("ok"));
List toProcess=items.stream()
.filter(s->s.contains(“B”))
.collect(toList());
toProcess.forEach(s->s.setState(“确定”);

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());
另一种方法是使用
peek
,其目的是将函数应用于每个元素遍历(但其主要目的是调试):


forEach的
forEach
被设计成一个终端操作
,是的-在调用它之后,你不能做任何事情

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

可以使用设计用于非突变操作的
map
执行转换

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

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

items.forEach(s -> s.setState("ok"))
其中
with state
是一种返回原始对象副本(包括提供的更改)的方法


如果您正在执行副作用:

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

items.forEach(s -> s.setState("ok"))
Stream peek(使用者操作)返回一个包含 在该流的元素中,另外执行提供的 当元素从结果中消耗时,对每个元素执行操作 流动这是一个中间操作

对于平行流管道,可以在任何位置调用该操作 时间和在任何线程中,元素由 上游操作。如果操作修改共享状态,则为 负责提供所需的同步

API注意:此方法主要用于支持调试,其中 希望在元素流过某个特定点时看到这些元素吗 管道:

 Stream.of("one", "two", "three", "four")
     .filter(e -> e.length() > 3)
     .peek(e -> System.out.println("Filtered value: " + e))
     .map(String::toUpperCase)
     .peek(e -> System.out.println("Mapped value: " + e))
     .collect(Collectors.toList());   Parameters: action - a non-interfering action to perform on the elements as they are consumed
从流返回:新流

公共静态void main(字符串[]args){
//创建并填充测试列表
List objectList=new ArrayList();
对象列表。添加(“s”);
对象列表。添加(1);
objectList.add(5L);
objectList.add(7D);
objectList.add(Boolean.TRUE);
//按一定条件过滤并收集
列表目标对象列表=
objectList.stream().filter(o->o字符串实例)
.collect(Collectors.toList());
//检查
targetObjectList.forEach(System.out::println);
}

peek
用于侧面-effects@GrzegorzPiwowarek…但是要预测它将被调用的元素有点棘手,而使用java 9(它允许通过流实现进行更多优化)不会变得更容易。您需要检查上游和下游操作(
filter
distinct
,短路终端操作,如
count()
anyMatch()
findFirst()
,…),以确保安全。对于像这样的简单情况,这可能是可以的,但一般来说,最好避免依赖它。@Hulk我知道这一点-我希望在使用应该访问所有元素的方法(如您上面提到的方法)终止流时,不能跳过peek()调用。很遗憾,这需要分两步完成,就像this@GrzegorzPiwowarekJava文档的草稿中明确提到了
count
findFirst
(“在流实现能够优化部分或所有元素的生产的情况下(例如,对于findFirst之类的短路操作,或者在count()中描述的示例中),这些元素将不会调用该操作。”),几天后,我们将确定最终版本中的措辞。当对上述代码使用“map”时,调试器会说:“无法推断map的类型参数。”(函数当使用“map”时,必须返回实例:“.map(s->{s.setState(“ok”);returns;})”。这样,它的工作原理类似于“peek”。但是,“peek”"必须不返回值。需要稍微编辑,抱歉。因为函数需要为映射返回值…感谢@nimo23,我给fast写了封信。根据JavaDoc,peek is应该用于调试:另请参见@user140547根据streams语义,根本不应该执行变异副作用
,但情况并非总是如此l、
forEach()
也会产生副作用。但是
peek()
更脆弱,因为它可能被优化掉。尽管在收集到li时可能会为每个元素调用
peek()
public static void main(String[] args) {
    // Create and populate the Test List
    List<Object> objectList = new ArrayList<>();
    objectList.add("s");
    objectList.add(1);
    objectList.add(5L);
    objectList.add(7D);
    objectList.add(Boolean.TRUE);

    // Filter by some condition and collect
    List<Object> targetObjectList = 
        objectList.stream().filter(o -> o instanceof String)
        .collect(Collectors.toList());

    // Check
    targetObjectList.forEach(System.out::println);
}