【问题标题】:Does Java compiler optimize stream filtering?Java 编译器是否优化流过滤?
【发布时间】:2018-07-08 15:19:29
【问题描述】:

我们来个案例:

x.stream().filter(X::isFlag).filter(this::isOtherFlag).reduce(...)

和这个有区别吗?

x.stream().filter(predicate(X::isFlag).and(this::isOtherFlag)).reduce(...)

【问题讨论】:

  • 您可以通过运行javap -c <class>进行检查,如果通过管道传输到文件(javap -c StreamTest > out.txt),您可以轻松比较它们
  • Java“编译器”(如 javac 中的程序)不会对此进行优化。但是,该库确实可能会折叠 Stream 中的兼容步骤,请参阅the detailed description of the different types of operations and how they interact
  • 您可以随时查看源代码以了解它如何跟踪过滤器,但在 Javadoc 中没有任何地方说实现将保持不变或是否会以任何方式优化。
  • 我不认为它们在性能方面有所不同。直到我看到基准测试结果。
  • @the8472 必须在流实现中以一种或另一种方式补偿保存的对象分配。在任何一种情况下,都必须有一段封装的代码评估两个谓词。但是,使用单个 .filter(x -> x.isFlag() && isOtherFlag(x)) 时会有所不同。然后,您在 JIT 方面稍有领先……

标签: java java-8 java-stream


【解决方案1】:

在功能上,这两个语句是等价的。但是,请考虑以下两个代码块及其各自的字节码:

public static void main(String[] args) {
    List<String> list = List.of("Seven", "Eight", "Nine");

    list.stream().filter(s -> s.length() >= 5)
                 .filter(s -> s.contains("n"))
                 .forEach(System.out::println);
}

public static void main(java.lang.String[]);
Code:
   0: ldc           #16                 // String Seven
   2: ldc           #18                 // String Eight
   4: ldc           #20                 // String Nine
   6: invokestatic  #22                 // InterfaceMethod java/util/List.of:(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/List;
   9: astore_1
  10: aload_1
  11: invokeinterface #28,  1           // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
  16: invokedynamic #35,  0             // InvokeDynamic #0:test:()Ljava/util/function/Predicate;
  21: invokeinterface #36,  2           // InterfaceMethod java/util/stream/Stream.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
  26: invokedynamic #42,  0             // InvokeDynamic #1:test:()Ljava/util/function/Predicate;
  31: invokeinterface #36,  2           // InterfaceMethod java/util/stream/Stream.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
  36: getstatic     #43                 // Field java/lang/System.out:Ljava/io/PrintStream;
  39: invokedynamic #52,  0             // InvokeDynamic #2:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;
  44: invokeinterface #53,  2           // InterfaceMethod java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V
  49: return

-

public static void main(String[] args) {
    List<String> list = List.of("Seven", "Eight", "Nine");

    list.stream().filter(s -> s.length() >= 5 && s.contains("n"))
                 .forEach(System.out::println);
}

public static void main(java.lang.String[]);
Code:
   0: ldc           #16                 // String Seven
   2: ldc           #18                 // String Eight
   4: ldc           #20                 // String Nine
   6: invokestatic  #22                 // InterfaceMethod java/util/List.of:(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/List;
   9: astore_1
  10: aload_1
  11: invokeinterface #28,  1           // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
  16: invokedynamic #35,  0             // InvokeDynamic #0:test:()Ljava/util/function/Predicate;
  21: invokeinterface #36,  2           // InterfaceMethod java/util/stream/Stream.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
  26: getstatic     #42                 // Field java/lang/System.out:Ljava/io/PrintStream;
  29: invokedynamic #51,  0             // InvokeDynamic #1:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;
  34: invokeinterface #52,  2           // InterfaceMethod java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V
  39: return

我们可以看到,在第二个示例中,缺少对 invokedynamicinvokeinterface 的调用(这是有道理的,因为我们省略了对 filter 的调用)。我确信有人可以帮助我对此字节码进行静态分析(如果需要,我可以发布详细文件),但 Java 编译器清楚地将对 filter 的单个调用视为单个 Predicate&lt;String&gt;,而不是将其拆分为运算符&amp;&amp;,稍微缩短字节码。

【讨论】:

    猜你喜欢
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-19
    相关资源
    最近更新 更多