gpt4 book ai didi

java - java Stream.peek() 如何影响字节码?

转载 作者:行者123 更新时间:2023-12-03 02:04:38 25 4
gpt4 key购买 nike

据我所知,如果我有一个带有两个过滤器的流,它们将在字节码中与 && 组合。

例如

IntStream.range(1,10)
.filter(i -> i % 2 == 0)
.filter(i -> i % 3 == 0)
.sum();

类似于 i % 2 == 0 && i % 3 == 0。

peek 会影响这个吗?

如果你在第一个文件管理器之后查看,你会得到 2468,如果你在第二个文件管理器之后查看,你只会得到 6(当然)。

但是如果你同时查看这两个地方

IntStream.range(1,10)
.filter(integer -> integer % 2 == 0)
.peek(i-> System.out.print(i))
.filter(integer -> integer % 3 == 0)
.peek(i-> System.out.print(i))
.sum();

你得到24668。

我的假设是,这必定意味着操作因 peek 调用而以某种方式分离。类似的东西

if(i%2==0)
peek
if(i%3==0)

这是真的吗?如果是的话,它会影响性能吗(我认为不会)。

最佳答案

Stream API 是 ordinary Java API ,正如您所看到的那样。 It’s filter method接收任意 Predicate 实例,无论它是通过 lambda 表达式还是普通 class(或 enum 来命名所有可能性)实现的。

如果您随后调用 filter 两次,底层实现可以通过调用 Predicate.and 将它们连接到单个过滤器。但对于通过 lambda 表达式实现的谓词来说,无论是否存在都没有任何后果。

与自定义 Predicate 实现不同,自定义 Predicate 实现可以覆盖 and 方法,并在识别第二个 Predicate 实现的情况下提供优化的内容,为 lambda 表达式生成的类不会覆盖任何default 方法,而仅覆盖一个abstract 函数方法,此处为 Predicate.test,因此在本例中,调用 and 将获得 default 方法返回的内容,即一个新的 Predicate,它保存对两个源谓词的引用并将它们组合起来,就像不使用 Predicate.and 的流实现即可。

因此,这些可能的实现之间没有实质性差异,并且如果您在中间插入另一个操作(例如传递给 peekConsumer),则不会有任何差异。当然,它现在比不执行此操作时执行的操作要多,因此它会对性能产生影响,但与谓词无关。

但您普遍的误解似乎是您认为以下之间存在重大区别:

for(int i=1; i<10; i++) {
if(i%2==0 && i%3==0)
System.out.print(i);
}

for(int i=1; i<10; i++) {
if(i%2==0) {
System.out.print(i);
if(i%3==0)
System.out.print(i);
}
}

看一下编译方法的字节码:

//  first variant            second variant
0: iconst_1 0: iconst_1
1: istore_1 1: istore_1
2: iload_1 2: iload_1
3: bipush 10 3: bipush 10
5: if_icmpge 33 5: if_icmpge 40
8: iload_1 8: iload_1
9: iconst_2 9: iconst_2
10: irem 10: irem
11: ifne 27 11: ifne 34
14: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_1
18: invokevirtual #3 // Method java/io/PrintStream.print:(I)V
14: iload_1 21: iload_1
15: iconst_3 22: iconst_3
16: irem 23: irem
17: ifne 27 24: ifne 34
20: getstatic #2 27: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
23: iload_1 30: iload_1
24: invokevirtual #3 31: invokevirtual #3 // Method java/io/PrintStream.print:(I)V
27: iinc 1, 1 34: iinc 1, 1
30: goto 2 37: goto 2
33: return 40: return

正如您所看到的,打印语句的插入会导致打印语句的插入,仅此而已。或者,换句话说,&& 运算符并不是与两个嵌套 if 语句不同的神奇融合。两者在语义上和字节码中的作用完全相同。

这同样适用于 Stream API 的使用,尽管在那里,代码会更加复杂,因为条件表达式表示为 Predicate 实例,而插入的语句是 Consumer s。但在最好的情况下,HotSpot 优化器将为 Stream 变体生成与循环变体完全相同的优化 native 代码。

关于java - java Stream.peek() 如何影响字节码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36600728/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com