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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:10:13  来源:igfitidea点击:

Java 8 apply function to all elements of Stream without breaking stream chain

javajava-8java-streamchaining

提问by alexgbelov

Is there a way in Java to apply a function to all the elements of a Streamwithout breaking the Streamchain? 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 methodAand methodB:

有(至少)3种方式。为了示例代码,我假设您要调用 2 个使用者方法methodAmethodB

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.

您正在寻找Streammap()功能。

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 peekmust be non interfering.

传递给的操作peek必须是非干扰的

回答by Eugene

Not entirely sure what you mean by breaking the stream chain, but any operation on a Streamthat returns a Streamwill not breakor consumeyour Stream. Streams are consumed by terminal operationsand as you noted the forEachdoes not returna Stream<T>and as such ends the stream, by executing all the intermediateoperations before the forEach and the forEach itself.

不完全确定您的意思breaking the stream chain,但对Stream返回 a 的任何操作Stream都不会破坏消耗您的流。terminal operations正如您所指出的forEach那样,流被消耗,并且不会返回a Stream<T>,因此通过执行intermediateforEach 和 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 Streamwould be of a different type (assuming fooreturns 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 mapoperation is stateful, which is strongly discouraged. Your code will compile and might even work as you want it to - but it might later fail. mapoperations 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 mapmethod 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 voidmethod:

当你想调用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")))