【问题标题】:Java bug when combining lambdas and multi-catch clauses?结合 lambdas 和 multi-catch 子句时的 Java 错误?
【发布时间】:2014-09-13 01:50:57
【问题描述】:
import java.io.*;             
import java.net.*;            

public class Test {           
    public static void main(String[] arguments) throws Exception {
        Runnable runnable = () -> {
            try {
                throwException();
            }
            catch (SocketException|EOFException exception) {
                System.err.println("wrong");
            }
            catch (IOException exception) {
                System.err.println("right");
            }
        };

        runnable.run();
    }                         

    private static void throwException() throws IOException {
        throw new NotSerializableException();
    }                         
}

为什么这个程序打印“错误”?如果我删除了 lambda,或者如果我分解了 multi-catch 子句,那么它会打印“正确”。

$ javac -version
javac 1.8.0_11
$ java -version
java version "1.8.0_11"
Java(TM) SE Runtime Environment (build 1.8.0_11-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.11-b03, mixed mode)

【问题讨论】:

    标签: java exception lambda java-8 multi-catch


    【解决方案1】:

    这是 1.8.0_20 中的 fixed bug,来自 1.8.0_11:

    区域:工具/javac
    概要:javac 为 lambda 内的多捕获语句生成不正确的异常表

    在 lambda 中处理带有多个 catch 的 try-catch 已得到纠正。

    实际的错误报告是JDK-8036942

    实际上出错的是编译器中假定的类型信息丢失:

    LTM 在变量的翻译和映射过程中大量使用了erasure()。在大多数情况下,这些擦除操作可能是正确的,但如本例所示,它可能会导致信息丢失。也可以说,这里需要如此强烈地使用 erasure(),因为 LTM 是在 TransTypes 之后应用的,它应该擦除大多数/所有类型,所以我想知道这是否可能是 TransTypes 中的一个错误。我认为它应该由 LTM 的当前维护者 Robert Field 评估,这里最好的方法是什么,我将重新分配给他。

    我在 8u20 上看到的(我忘记提供命令行参数,不再让 8u20 正确执行):

    wlan1-loopback% /usr/lib/jvm/java-8-oracle/bin/javap -c Test
    Compiled from "Test.java"
    public class Test {
      public Test();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]) throws java.lang.Exception;
        Code:
           0: invokedynamic #2,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
           5: astore_1
           6: aload_1
           7: invokeinterface #3,  1            // InterfaceMethod java/lang/Runnable.run:()V
          12: return
    }
    wlan1-loopback% java Test 
    right
    wlan1-loopback% java -version
    java version "1.8.0_20"
    Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
    Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
    wlan1-loopback% 
    

    正确:

    public class Test {
      public Test();
        descriptor: ()V
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]) throws java.lang.Exception;
        descriptor: ([Ljava/lang/String;)V
        Code:
           0: invokedynamic #2,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
           5: astore_1
           6: aload_1
           7: invokeinterface #3,  1            // InterfaceMethod java/lang/Runnable.run:()V
          12: return
    
      private static void throwException() throws java.io.IOException;
        descriptor: ()V
        Code:
           0: new           #4                  // class java/io/NotSerializableException
           3: dup
           4: invokespecial #5                  // Method java/io/NotSerializableException."<init>":()V
           7: athrow
    
      private static void lambda$main$0();
        descriptor: ()V
        Code:
           0: invokestatic  #6                  // Method throwException:()V
           3: goto          27
           6: astore_0
           7: getstatic     #9                  // Field java/lang/System.err:Ljava/io/PrintStream;
          10: ldc           #10                 // String wrong
          12: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          15: goto          27
          18: astore_0
          19: getstatic     #9                  // Field java/lang/System.err:Ljava/io/PrintStream;
          22: ldc           #13                 // String right
          24: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          27: return
        Exception table:
           from    to  target type
               0     3     6   Class java/net/SocketException
               0     3     6   Class java/io/EOFException
               0     3    18   Class java/io/IOException
    }
    

    【讨论】:

      【解决方案2】:

      此错误已在 1.8.0_20 https://bugs.openjdk.java.net/browse/JDK-8036942 中修复

      我能够复制它 1.8.0_11 并且它已被 1.8.0_20

      修复
      $ javac -version
      javac 1.8.0_11
      $ java -version
      java version "1.8.0_11"
      Java(TM) SE Runtime Environment (build 1.8.0_11-b12)
      Java HotSpot(TM) 64-Bit Server VM (build 25.11-b03, mixed mode)
      $ javac Test.java
      $ java Test
      wrong
      

      工作正常

      ~$ javac -version
      javac 1.8.0_20
      $ javac Test.java 
      $ java -version
      java version "1.8.0_20"
      Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
      Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
      $ java Test
      right
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-15
        • 1970-01-01
        • 2010-10-14
        • 2020-12-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多