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