我想实现这样的目标:
items.stream()
.filter(s-> s.contains("B"))
.forEach(s-> s.setState("ok"))
.collect(Collectors.toList());
过滤,然后从过滤结果中更改属性,然后将结果收集到列表中。但是,调试器说:
无法在基本类型
collect(Collectors.toList())
上调用void
。
我需要2个流吗?
答案 0 :(得分:14)
forEach
旨在成为终端操作,是的 - 您在调用后无法执行任何操作。
惯用的方法是首先应用转换,然后collect()
将所有内容应用到所需的数据结构。
可以使用专为非变异操作设计的map
来执行转换。
如果您正在执行非变异操作:
items.stream()
.filter(s -> s.contains("B"))
.map(s -> s.withState("ok"))
.collect(Collectors.toList());
其中withState
是一个返回原始对象副本的方法,包括提供的更改。
如果您正在执行副作用:
items.stream()
.filter(s -> s.contains("B"))
.collect(Collectors.toList());
items.forEach(s -> s.setState("ok"))
答案 1 :(得分:11)
将forEach
替换为map
。
items.stream()
.filter(s-> s.contains("B"))
.map(s-> {s.setState("ok");return s;})
.collect(Collectors.toList());
forEach
和collect
都是终端操作 - Streams必须只有一个。任何返回Stream<T>
的内容都是intermediate operation
,其他任何内容都是terminal operation
。
答案 2 :(得分:4)
在没有充分理由的情况下,抵制在流内使用副作用的冲动。创建新列表,然后应用更改:
List<MyObj> toProcess = items.stream()
.filter(s -> s.contains("B"))
.collect(toList());
toProcess.forEach(s -> s.setState("ok"));
答案 3 :(得分:4)
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
,其意图是将函数应用于遍历的每个元素(但其主要目的是用于调试):
items.stream()
.filter (s -> s.contains("B"))
.peek (s -> s.setState("ok")) // no need to return a value here
.collect(Collectors.toList());
答案 4 :(得分:2)
您无法在同一个Stream上执行两个终端操作。
您可以在中间操作中设置对象的状态,例如map
:
List<YourClass> list =
items.stream()
.filter(s-> s.contains("B"))
.map(s-> {
s.setState("ok");
return s;
})
.collect(Collectors.toList());
答案 5 :(得分:1)
items.stream()
.filter(s-> s.contains("B"))
.peek(s-> s.setState("ok"))
.collect(Collectors.toList());
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
从流中返回:新流
答案 6 :(得分:0)
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);
}