Java 8将函数应用于Stream的所有元素,而不会破坏流链

时间:2017-05-05 23:52:36

标签: java java-8 java-stream chaining

Java是否有办法在不破坏Stream链的情况下将函数应用于Stream的所有元素?我知道我可以致电forEach,但该方法会返回void,而不是Stream

7 个答案:

答案 0 :(得分:24)

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

一个。使用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));

这可能是最“可接受”的方法。

℃。在forEach()中做两件事:

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

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

答案 1 :(得分:4)

您正在寻找Stream的{​​{1}}功能。

示例:

map()

答案 2 :(得分:1)

不完全确定breaking the stream chain的含义,但Stream上任何返回Stream的操作都不会中断消耗< / em>你的流。流被terminal operations消耗,正如您所指出的那样,forEach 不返回一个Stream<T>,因此通过执行所有intermediate来结束流在forEach和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操作为stateful,强烈建议不要这样做。您的代码将编译,甚至可能按照您的意愿工作 - 但它可能会失败。 map操作应为stateless

答案 3 :(得分:1)

您拥有的最佳选择是将地图应用于您的信息流。它返回一个流,该流包含将给定的函数应用于此流的元素的结果,例如:

IntStream.rangeClosed(40, 70).limit(20).mapToObj(i -> (Integer) i).map(item->item+3).map(item->item*2)... 

(StreamItemABC类型的项目流)

我们正在对流应用几个修改,但是这样我们就不能将任何参数传递给map方法来修复它:

private void applyMethod(ParameterX parX) {
 someStreamX().map(n -> methodX(n, parX))...
}

private StreamItemABC methodX (StreamItemABC item, ParameterX parX) {
  return notification;
}

答案 4 :(得分:0)

我认为您正在寻找Stream.peek。但仔细阅读文档,因为它主要是作为调试方法设计的。来自文档:

  

此方法主要用于支持调试,您希望在元素流经管道中的某个点时查看元素

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

答案 5 :(得分:0)

我认为最干净的方法是将mutator添加到流中的对象。

例如,

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方法创建并返回一个新的受害者;这可以使受害者变得一成不变。

答案 6 :(得分:0)

您可以使用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")))