我看到一张rule in Sonar,上面写着:
与其他中间流操作的一个关键区别是,流实现可以出于优化目的自由地跳过对
peek()
的调用.这可能会导致仅针对Stream中的某些元素意外调用peek()
,或者不调用任何元素.
此外,Javadoc中也提到了这一点,上面写道:
此方法主要用于支持调试,您希望在元素流过管道中的某个点时查看元素
在什么情况下可以跳过java.util.Stream.peek()
?是不是跟调试有关?
我看到一张rule in Sonar,上面写着:
与其他中间流操作的一个关键区别是,流实现可以出于优化目的自由地跳过对
peek()
的调用.这可能会导致仅针对Stream中的某些元素意外调用peek()
,或者不调用任何元素.
此外,Javadoc中也提到了这一点,上面写道:
此方法主要用于支持调试,您希望在元素流过管道中的某个点时查看元素
在什么情况下可以跳过java.util.Stream.peek()
?是不是跟调试有关?
不仅peek
可以跳过,map
也可以跳过.这是为了优化.
例如,当调用终端操作count()
时,由于这样的操作不改变当前项的数量/计数,所以对于peek
或map
而言,各个项没有意义.
这里有两个例子:
1.Map和PEEK are not skipped,因为过滤器可以预先更改项目数.
long count = Stream.of("a", "aa")
.peek(s -> System.out.println("#1"))
.filter(s -> s.length() < 2)
.peek(s -> System.out.println("#2"))
.map(String::length)
.count();
#1 #2 #1 1
2.Map和PEEK are skipped,因为条目的数量没有变化.
long count = Stream.of("a", "aa")
.peek(s -> System.out.println("#1"))
//.filter(s -> s.length() < 2)
.peek(s -> System.out.println("#2"))
.map(String::length)
.count();
2
Important:这些方法不应该有side-effects.
一般来说,流操作的行为参数的副作用是不受鼓励的,因为它们通常会导致无意中违反无状态要求,以及其他线程安全风险.
以下实现是危险的.假设callRestApi
方法执行REST调用,则不会执行该调用,因为Stream违反了副作用.
long count = Stream.of("url1", "url2")
.map(string -> callRestApi(HttpMethod.POST, string))
.count();
/**
* Performs a REST call
*/
public String callRestApi(HttpMethod httpMethod, String url);