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,或者如果我分开了多个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)
解决方法
Area: tools/javac
Synopsis: javac generates incorrect exception table for multi-catch statements inside a lambdaHandling of try-catch with multiple catches inside a lambda has been corrected.
实际的错误报告是JDK-8036942
实际出错的是编译器中的类型信息丢失:
LTM makes a heavy use of erasure() during translations and mapping of variables. These erasure operations may be correct in most cases but it may lead to an information loss as this case shows. It’s also arguably that such an intense use of erasure() is needed here as LTM is applied after TransTypes which is supposed to erase most / all types,so I wonder if this may be a bug in TransTypes. I think that it should be evaluated by Robert Field,which is current maintainer of LTM,what is the best approach here,I will thus reassigning[sic] it to him.
我在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,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 }