Java 8 在不破坏流链的情况下将函数应用于 Stream 的所有元素

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

在 Java 中有没有办法在不破坏 Stream 链的情况下将函数应用于 Stream 的所有元素?我知道我可以调用 forEach,但是那个方法 returns 是 void,而不是 Stream

您正在查找 Streammap() 函数。

示例:

List<String> strings = stream
.map(Object::toString)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

我认为您正在寻找 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

传递给 peek 的操作必须是 non interfering

不完全确定 breaking the stream chain 是什么意思,但是对 return 和 StreamStream 的任何操作都不会 break 使用 您的流。流由 terminal operations 消耗,正如您所指出的 forEach 不会 returnStream<T> 因此结束流,通过在 forEach 和 forEach 本身之前执行所有 intermediate 操作。

在您在评论中提供的示例中:

 myStream.map(obj -> {obj.foo(); return obj;}

你真的不能用一张衬垫做到这一点。当然你可以使用方法引用,但是你的 returned Stream 将是不同的类型(假设 foo returns 是一种类型):

  myStream.map(Obj::foo) // this will turn into Stream<T>, where T is 
           // the return type of foo, instead of Stream<Obj>

此外,您的 map 操作是 stateful,强烈建议不要这样做。您的代码可以编译,甚至可以按您希望的方式工作——但稍后可能会失败。 map 操作应该是 stateless.

有(至少)3种方法。为了示例代码,我假设您想调用 2 个消费者方法 methodAmethodB:

一个。使用 peek():

list.stream().peek(x -> methodA(x)).forEach(x -> methodB(x));

尽管文档说它只用于 "debug",但它确实有效(并且现在正在生产中)

乙。使用 map() 调用 methodA,然后 return 将元素返回流:

list.stream().map(x -> {method1(x); return x;}).forEach(x -> methodB(x));

这可能是最 "acceptable" 的方法。

摄氏度。在 forEach() 中做两件事:

list.stream().forEach(x -> {method1(x); methodB(x);});

这是最不灵活的,可能不适合您的需要。

您最好的选择是将地图应用到您的流中。其中 returns 一个流,由将给定函数应用于流元素的结果组成。 例如:

IntStream.range(1, 100)
           .boxed()
           .map(item->item+3)
           .map(item->item*2)... 

我们正在对流进行多项修改,但在某些情况下我们不想修改流。我们只想访问每个元素,然后将其不加修改地传递到流中(就像流中的 peek() 方法 API)。在这种情况下,我们可以

StreamItem peekyMethod(StreamItem streamItemX) {
   // .... visit the streamItemX
   //Then pass it down the stream
   return streamItemX;
}

我认为最干净的方法是向流中的对象添加一个修改器。

例如,

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 方法创建并 return 一个新的 Victim;这使您可以使 Victim 不可变。

您可以使用 map 方法,但您必须创建 returns 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")))