在Java中,有没有一种方法可以对Stream
的所有元素应用一个函数,而不破坏Stream
链?我知道可以调用forEach
方法,但是该方法返回一个void
,而不是一个Stream
。
在Java中,有没有一种方法可以对Stream
的所有元素应用一个函数,而不破坏Stream
链?我知道可以调用forEach
方法,但是该方法返回一个void
,而不是一个Stream
。
至少有3种方法。为了举例说明,我假设您想调用2个消费者方法methodA
和methodB
:
A. 使用peek()
:
list.stream().peek(x -> methodA(x)).forEach(x -> methodB(x));
尽管文档上只建议将其用于“调试”,但它实际运行正常(而且现在正在生产环境中使用)
B. 使用map()
调用methodA方法,然后将元素返回到流中:
list.stream().map(x -> {method1(x); return x;}).forEach(x -> methodB(x));
这可能是最为“可接受”的方法。
C. 在 forEach()
中做两件事情:
list.stream().forEach(x -> {method1(x); methodB(x);});
这是最不灵活的,可能不适合您的需求。
map
函数中执行具有副作用的操作以及使用peek
进行此类(非调试)副作用的影响基本相同。 - Holgermethod1(x);
将完全无用。 - Holgerpeek()
的版本),当我想要收集元素(到一个 Set 中,不涉及时间敏感性,没有问题)但同时也想将流的尾部发送给一个消费者通过 forEach() 进行处理时。这不是无用的。 - BohemianList<String> strings = stream
.map(Object::toString)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
您最好的选择是将地图应用于您的流。该操作返回一个流,其中包含将给定函数应用于流元素的结果。 例如:
IntStream.range(1, 100)
.boxed()
.map(item->item+3)
.map(item->item*2)...
我们正在对流进行多个修改,但在某些情况下,我们不想修改流。我们只想访问每个元素,然后将其传递到流中而不进行修改(就像流API中的peek()方法一样)。在这种情况下,我们可以
StreamItem peekyMethod(StreamItem streamItemX) {
// .... visit the streamItemX
//Then pass it down the stream
return streamItemX;
}
Stream
的任何Stream
上的操作都不会打破或消耗您的流。流被终端操作
消耗,正如您所指出的,forEach
不返回Stream<T>
,因此在执行所有中间
操作之前和forEach
本身之后结束流。
在您提供的评论示例中:
myStream.map(obj -> {obj.foo(); return obj;}
你不可能只用一行代码就完成这个任务。当然,你可以使用方法引用,但是你返回的Stream
类型会有所不同(假设foo
返回一个类型):
myStream.map(Obj::foo) // this will turn into Stream<T>, where T is
// the return type of foo, instead of Stream<Obj>
map
操作是有状态的,这是强烈不建议的。你的代码可以编译并且可能按照你想要的方式工作,但是它可能会在以后失败。map
操作应该是无状态的。map
方法,但你需要创建一个返回 this
的帮助方法。例如:public class Fluent {
public static <T> Function<T, T> of(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return t;
};
}
}
当你想调用 void
方法时,请使用它:
list.stream().map(Fluent.of(SomeClass::method));
或者,如果你想使用带有一些参数的方法:
list.stream().map(Fluent.of(x -> x.method("hello")))
我认为你正在寻找Stream.peek
。但是请仔细阅读文档,因为它主要是作为调试方法设计的。从文档中可以看到:
此方法主要用于支持调试,您希望在管道中的某个点看到元素的流动
传递给 peek
的操作必须是非干扰性的。
class Victim {
private String tag;
private Victim withTag(String t)
this.tag = t;
return this;
}
}
List<Victim> base = List.of(new Victim());
Stream<Victim> transformed = base.stream().map(v -> v.withTag("myTag"));
如果你喜欢的话(很多人都会这样做),你可以让 withTag 方法创建并返回一个新的 Victim;这样可以使 Victim 不可变。
apply
方法,像这样:things.stream().apply(o -> o.status = newStatus).map(....)....
与forEach
类似,但不会 "break the chain",即返回的是Stream<T>
而不是void
。 - Josh M.stream().map(...)
来完成相同的操作,但需要在 lambda 中返回相同的项目,这很愚蠢。 - Josh M.