Java 8 将函数应用于 Stream 的所有元素而不破坏流链
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43815221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8 apply function to all elements of Stream without breaking stream chain
提问by alexgbelov
Is there a way in Java to apply a function to all the elements of a Stream
without breaking the Stream
chain? I know I can call forEach
, but that method returns a void
, not a Stream
.
Java 中有没有办法将函数应用于 a 的所有元素而Stream
不会破坏Stream
链?我知道我可以调用forEach
,但该方法返回一个void
,而不是一个Stream
。
采纳答案by Bohemian
There are (at least) 3 ways. For the sake of example code, I've assumed you want to call 2 consumer methods methodA
and methodB
:
有(至少)3种方式。为了示例代码,我假设您要调用 2 个使用者方法methodA
和methodB
:
A. Use peek()
:
A. 使用peek()
:
list.stream().peek(x -> methodA(x)).forEach(x -> methodB(x));
Although the docs say only use it for "debug", it works (and it's in production right now)
尽管文档说仅将其用于“调试”,但它可以工作(并且现在正在生产中)
B. Use map()
to call methodA, then return the element back to the stream:
B.map()
用于调用methodA,然后将元素返回给流:
list.stream().map(x -> {method1(x); return x;}).forEach(x -> methodB(x));
This is probably the most "acceptable" approach.
这可能是最“可接受”的方法。
C. Do two things in the forEach()
:
C. 在 中做两件事forEach()
:
list.stream().forEach(x -> {method1(x); methodB(x);});
This is the least flexible and may not suit your need.
这是最不灵活的,可能不适合您的需要。
回答by csenga
You are looking for the Stream
's map()
function.
您正在寻找Stream
的map()
功能。
example:
例子:
List<String> strings = stream
.map(Object::toString)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
回答by Federico Peralta Schaffner
I think you are looking for Stream.peek
. But read the docs carefully, as it was designed mainly as a debug method. From the docs:
我想你正在寻找Stream.peek
。但是请仔细阅读文档,因为它主要被设计为一种调试方法。从文档:
This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline
此方法的存在主要是为了支持调试,您希望在其中查看元素流经管道中的某个点时的情况
The action passed to peek
must be non interfering.
传递给的操作peek
必须是非干扰的。
回答by Eugene
Not entirely sure what you mean by breaking the stream chain
, but any operation on a Stream
that returns a Stream
will not breakor consumeyour Stream. Streams are consumed by terminal operations
and as you noted the forEach
does not returna Stream<T>
and as such ends the stream, by executing all the intermediate
operations before the forEach and the forEach itself.
不完全确定您的意思breaking the stream chain
,但对Stream
返回 a 的任何操作Stream
都不会破坏或消耗您的流。terminal operations
正如您所指出的forEach
那样,流被消耗,并且不会返回a Stream<T>
,因此通过执行intermediate
forEach 和 forEach 本身之前的所有操作来结束流。
In the example that you provided in the comments:
在您在评论中提供的示例中:
myStream.map(obj -> {obj.foo(); return obj;}
You can't really do this with one liner. Of course you could use a method reference, but then your returned Stream
would be of a different type (assuming foo
returns a type):
你真的不能用一个衬垫来做到这一点。当然,您可以使用方法引用,但是您返回的Stream
类型将是不同的(假设foo
返回一个类型):
myStream.map(Obj::foo) // this will turn into Stream<T>, where T is
// the return type of foo, instead of Stream<Obj>
Besides that your map
operation is stateful
, which is strongly discouraged. Your code will compile and might even work as you want it to - but it might later fail. map
operations should be stateless
.
除此之外,您的map
操作是stateful
,这是强烈不鼓励的。您的代码将编译,甚至可能按您的意愿工作 - 但它可能稍后会失败。map
操作应该是stateless
。
回答by Mr.Q
The best option you have is to apply the map to your stream. which returns a stream consisting of the results of applying the given function to the elements of the stream. For example:
您拥有的最佳选择是将地图应用到您的流中。它返回一个流,其中包含将给定函数应用于流元素的结果。例如:
IntStream.range(1, 100)
.boxed()
.map(item->item+3)
.map(item->item*2)...
We are applying several modifications to the stream but in some case we don't want to modify the stream. We just want to visit every element and then pass it down the stream without modification (like the peek() method in the streams API). in such cases, we can
我们对流应用了一些修改,但在某些情况下我们不想修改流。我们只想访问每个元素,然后不加修改地将其传递到流中(如流 API 中的 peek() 方法)。在这种情况下,我们可以
StreamItem peekyMethod(StreamItem streamItemX) {
// .... visit the streamItemX
//Then pass it down the stream
return streamItemX;
}
回答by Roger Hayes
I think the cleanest way is to add a mutator to the objects in the stream.
我认为最简洁的方法是向流中的对象添加一个 mutator。
For example,
例如,
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"));
If you prefer (and many will), you can have the withTag method create and return a new Victim; this allows you to make Victim immutable.
如果你愿意(很多人愿意),你可以让 withTag 方法创建并返回一个新的受害者;这使您可以使 Victim 不可变。
回答by SalHyman
You can use map
method but you have to create helper method which returns this
. For example:
您可以使用map
方法,但您必须创建返回this
. 例如:
public class Fluent {
public static <T> Function<T, T> of(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return t;
};
}
}
And use it when you want to call void
method:
当你想调用void
方法时使用它:
list.stream().map(Fluent.of(SomeClass::method));
or if you want to use it with method with some argument:
或者,如果您想将它与带有一些参数的方法一起使用:
list.stream().map(Fluent.of(x -> x.method("hello")))