2014-09-13 5 views
11
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(); 
    }       
} 

Perché questo programma viene stampato "in modo errato"? Se rimuovo il lambda, o se divido la clausola multi-catch, allora stampa "right".Errore Java durante la combinazione di clausole lambda e 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) 

risposta

11

Questo è stato un fixed bug in 1.8.0_20, 1.8.0_11 da:

Area: strumenti/javac
Sinossi: javac genera tavolo eccezione non corretta per le dichiarazioni a più di cattura all'interno di una lambda

La gestione del try-catch con più catture all'interno di una lambda è stata corretta.

Il bug report reale è JDK-8036942

Che in realtà è andato storto è stata una perdita di informazioni di tipo supposta all'interno del compilatore:

LTM fa un uso pesante di cancellazione() durante la traduzione e la mappatura di variabili. Queste operazioni di cancellazione potrebbero essere corrette nella maggior parte dei casi, ma potrebbe portare a una perdita di informazioni come mostrato in questo caso. È anche discutibile che un uso così intenso di cancellazione() sia necessario qui in quanto LTM viene applicato dopo TransTypes che dovrebbe cancellare la maggior parte/tutti i tipi, quindi mi chiedo se questo potrebbe essere un bug in TransTypes. Penso che dovrebbe essere valutato da Robert Field, che è attuale manutentore di LTM, qual è l'approccio migliore qui, quindi lo riassegnerò a lui.

quello che vedo sul 8u20 (ho dimenticato di dare un parametro di riga di comando e non hanno più 8u20 farlo correttamente):

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% 

corretta:

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 
} 
10

Questo bug è stato risolto con 1.8.0_20 https://bugs.openjdk.java.net/browse/JDK-8036942

sono in grado di replicare 1.8.0_11 ed è fissato con 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 

funziona bene

~$ 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