如何在Stream链中调用setter

ric*_*oon 10 java java-8 java-stream

如何在不使用forEach()的情况下调用Stream链中的setter?

List<Foo> newFoos = foos.stream()
        .filter(foo -> Foo::isBlue)
        .map(foo -> foo.setTitle("Some value")) //I am unable to use this because also changing the data type into Object
        .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

sak*_*029 13

使用像这样的偷看方法.它不会影响流.

    List<Foo> newFoos = foos.stream()
            .filter(Foo::isBlue)
            .peek(foo -> foo.setTitle("Some value"))
            .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • @Tunaki,非干扰动作意味着动作不对源进行结构修改(例如,不向`foos`集合添加新元素).修改元素本身是完全可以的.毕竟,即使是"forEach",也可以通过合同接受非干涉消费者.请参阅[non-interference](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#NonInterference). (4认同)
  • @TagirValeev是对的,这不是干涉,但Tunaki也是对的,这是对'peek()`方法的滥用,并可能产生令人惊讶的结果.如果你想变异,请使用`forEach()`.如果这意味着您需要两个管道,那就这样吧.我们的目标不是尽可能多地填充管道; 它是为了清楚地表达正在发生的事情. (4认同)
  • 实际的结果是不能保证`peek` 看到每个流元素。它的操作是针对在终端操作特定处理期间遇到的元素执行的,并且可能会受到流管道优化的影响。你可能会得到意想不到的结果…… (3认同)

ETO*_*ETO 8

不要那样做。

如果您使用函数式模式,请勿在其中引入任何命令式/过程式内容。

目的map是将一个物体转变成另一个物体。它的设计目的是纯粹的功能性(无副作用)。不要违反其功能意义。

改用forEach

List<Foo> newFoos = foos.stream()
                        .filter(foo -> Foo::isBlue)
                        .collect(toList());

newFoos.forEach(foo -> foo.setTitle("Some value"));
Run Code Online (Sandbox Code Playgroud)

你在这里没有什么可失去的。甚至行数也保持不变(如果您担心的话)。但代码的可读性和安全性要高得多。

如果您需要两条管道而不是一条,那就继续吧。不要试图使代码更短。这种情况下的代码长度与安全性和可维护性无关。


Mur*_*nik 5

forEach似乎是一个更适合这项工作的工具,但如果您不想使用它,您可以随时定义一个匿名多行 lambda:

List<Foo> foos = foos.stream()
        .filter(foo -> Foo::isBlue)
        .map(foo -> {
                        foo.setTitle("Some value");
                        return foo;
                    })
        .collect(Collectors.toList()); 
Run Code Online (Sandbox Code Playgroud)

  • 不要那样滥用`.map`,你会搬起石头砸自己的脚…… (13认同)