2015-11-18 13 views
5

Per quanto ne so, non si può gestire l'eccezione lanciata nella lambda se il metodo astratto implementato dalla lambda non ha throws nella sua firma.Gestione dell'eccezione nella lambda senza try-catch nella lambda

Ho incontrato il seguente codice, funziona. Perchénon richiede la gestione IOException? Posso vedere try-catch nel tryWithResources ma non capisco il meccanismo dietro di esso.

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collection; 
import java.util.Map; 
import java.util.concurrent.Callable; 
import java.util.concurrent.ConcurrentSkipListMap; 
import java.util.function.Function; 
import java.util.function.Supplier; 

public class Main { 

    public static <AUTOCLOSEABLE extends AutoCloseable, OUTPUT> Supplier<OUTPUT> tryWithResources(
      Callable<AUTOCLOSEABLE> callable, Function<AUTOCLOSEABLE, Supplier<OUTPUT>> function, 
      Supplier<OUTPUT> defaultSupplier) { 
     return() -> { 
      try (AUTOCLOSEABLE autoCloseable = callable.call()) { 
       return function.apply(autoCloseable).get(); 
      } catch (Throwable throwable) { 
       return defaultSupplier.get(); 
      } 
     }; 
    } 

    public static <INPUT, OUTPUT> Function<INPUT, OUTPUT> function(Supplier<OUTPUT> supplier) { 
     return i -> supplier.get(); 
    } 

    public static void main(String... args) { 
     Map<String, Collection<String>> anagrams = new ConcurrentSkipListMap<>(); 
     int count = tryWithResources(
       () -> new BufferedReader(new InputStreamReader(
         new URL("http://www.puzzlers.org/pub/wordlists/unixdict.txt").openStream())), 
       reader ->() -> reader.lines().parallel().mapToInt(word -> { 
        char[] chars = word.toCharArray(); 
        Arrays.parallelSort(chars); 
        String key = Arrays.toString(chars); 
        Collection<String> collection = anagrams.computeIfAbsent(key, function(ArrayList::new)); 
        collection.add(word); 
        return collection.size(); 
       }).max().orElse(0),() -> 0).get(); 
     anagrams.values().stream().filter(ana -> ana.size() >= count).forEach((list) -> { 
      for (String s : list) 
       System.out.print(s + " "); 
      System.out.println(); 
     }); 
    } 
} 

risposta

8

Ho semplificato il tuo esempio per la parte del centro:

public static void main(String[] args) { 
    withCallable(() -> new URL("url").openStream()); // compiles 
    withSupplier(() -> new URL("url").openStream()); // does not compile 
} 

public static <T> void withCallable(Callable<T> callable) { } 

public static <T> void withSupplier(Supplier<T> callable) { } 

Se provate con questo, si vedrà che withCallable compilerà bene, ma che withSupplier non viene compilato correttamente; anche se l'espressione lambda è compatibile con la firma di entrambe le interfacce funzionali.

La ragione di ciò è che il metodo funzionale dell'interfaccia , che è call(), dichiara throws Exception nella sua firma. Supplier.get() no.

Citando il JLS section 11.2.3:

Si tratta di un errore di compilazione se un corpo lambda può gettare un po 'di classe di eccezioni E quando E è una classe eccezione controllata ed E non è una sottoclasse di una classe dichiarata nel la clausola throws del tipo di funzione bersagliato dall'espressione lambda.

1

Per quanto ne so, non si poteva gestire eccezione generata nel lambda se il metodo astratto attuato dal lambda non ha getta la sua firma.

C'è una soluzione alternativa, nota come sneaky throw; qui un simpler example senza gli helper funzionali.

Di avere un paio di funzioni di supporto statiche che trasformano le vostre firme lancio in quelli non-lancio che trucco del compilatore in rethrowing eccezioni controllate è possibile attivare

.stream().map(x -> { 
    try { 
    return this.throwingFunction(x) 
    } catch(Exception e) { 
    throw new RuntimeException(e); 
    } 
}).forEach(...) 

in

.stream().map(uncheckedFunc(this::throwingFunction)).forEach(...)

senza avvolgere l'eccezione in un'eccezione di runtime generica.

+1

Ma questa non è la domanda qui. Questo è più un commento. – Tunaki