2015-01-12 6 views
6

Mit folgendem CodeWie kann ich eine Exception in einem Lambda-Block wie vom äußeren Block erneut werfen?

void key(Key) throws SomeCheckedException { 
} 

void supplier(Supplier<Key> s) throws SomeCheckedException { 
    ofNullable(s).ifPresent(s -> {     // | 
     try {          // | 
      key(s.get());       // | 
     } catch (final SomeCheckedException sce) { // | 
      // sce is coming from key() method  // | 
      // How can I throw sce for outer method? // --/ 
     } 
    }); 
} 

Wie kann ich werfen sce als ob das Verfahren (supplier) -Methode werfen wird?

Bitte beachten Sie, dass der obige Code nur ein Beispiel ist. Ich brauche die key(s.get()) in einem Lambda-Ausdruck zu sein.

void supplier(Supplier<Key> s) throws SomeCheckException { 
    key(s.get()); 
} 
+2

verwenden Ah, ich dachte nicht, dass '' Schlüssel (...) 'die geprüfte Ausnahme werfen kann. Jedoch [meine Antwort] (http://stackoverflow.com/a/27900544/2711488) behandelt auch diesen Fall. – Holger

Antwort

2

Wenn Sie geprüfte Ausnahmen auf sichere Weise verarbeiten möchten, benötigen Sie eine Hilfsmethode, die die Möglichkeit bietet, die Ausnahme in einen Untertyp von RuntimeException zu verpacken. Hier ist so eine Hilfsfunktion, die verwendet Allgemein die Typsicherheit zu gewährleisten, dass nur Ausnahmen erklärt wird wieder geworfen werden (es sei denn, Sie einen unsicheren Betrieb verwenden):

public static <E extends Throwable> void attempt(
    Consumer<Function<E,RuntimeException>> action) throws E { 

    final class CarryException extends RuntimeException { 
     final E carried; 
     CarryException(E cause) { 
      super(cause); 
      carried=cause; 
     } 
    } 

    try { action.accept(CarryException::new); } 
    catch(CarryException ex) { throw ex.carried; } 
} 

Es ist eine willkürliche action unterstützt, die eine Funktion erhalten, die tut das temporäre Umbrechen des geprüften Ausnahmetyps auf RuntimeException. Dieser Umbruch wird transparent sein, die Methode attempt wird entweder normal abgeschlossen oder die ursprüngliche überprüfte Ausnahme E (oder eine nicht verwandte ungeprüfte Ausnahme, falls eine auftritt) ausgelöst.

So können Sie es wie folgt verwenden:

public static void processIterm(Supplier<Key> s) 
    throws SomeCheckedException { 

    attempt((Function<SomeCheckedException, RuntimeException> thrower) -> 
     Optional.ofNullable(s).ifPresent(nonNull -> { 
      try { key(nonNull.get()); } // assuming key may throw SomeCheckedException 
      catch(SomeCheckedException e) { throw thrower.apply(e); } 
     })); 
} 

Aufgrund der verschachtelten Operationen der Compiler kann nicht mehr die Ausnahme Typ automatisch schließen. Der obige Code verwendet eine explizite Deklaration des Parametertyps thrower. Alternativ können Sie einen Typenaufruf der Hilfsmethode wie

ContainingClass.<SomeCheckedException>attempt(thrower -> 
    Optional.ofNullable(s).ifPresent(nonNull -> { 
     try { key(nonNull.get()); } 
     catch(SomeCheckedException e) { throw thrower.apply(e); } 
    })); 
7

Sie können nicht. Supplier#get() deklariert nicht, irgendwelche (geprüfte) Ausnahmen zu werfen. Denken Sie daran, dass ein Lambda-Ausdruck einfach eine Instanz erstellt, er ruft jedoch nicht die Zielfunktionsschnittstellenmethode auf.

Wenn Sie möchten, können Sie die geprüfte Ausnahme in eine ungeprüfte Ausnahme umbrechen und diese übergeben.

Verwandte Themen