2015-01-12 16 views
6

W poniższym kodzieJak mogę ponownie rzucić wyjątek w bloku lambda, jak z zewnętrznego bloku?

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? // --/ 
     } 
    }); 
} 

Jak mogę rzucać sce jakby (supplier) metoda metoda rzuca go?

Należy pamiętać, że powyższy kod jest tylko przykładem. Potrzebuję, aby key(s.get()) znajdowało się wewnątrz wyrażenia lambda.

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

Ah, nie myślałem, że 'klucz (...)' może rzucić zaznaczony wyjątek. Jednak [moja odpowiedź] (http://stackoverflow.com/a/27900544/2711488) obsługuje również tę sprawę. – Holger

Odpowiedz

2

Jeśli chcesz przetworzyć zaznaczone wyjątki w bezpieczny sposób, potrzebujesz metody pomocniczej, która zapewnia możliwość zawijania wyjątku do podtypu RuntimeException. Oto taka funkcja pomocnika, który wykorzystuje bezpieczeństwa typu rodzajowego w celu zapewnienia, że ​​tylko zadeklarowane wyjątki zostanie ponownie wyrzucony (chyba, że ​​używasz niebezpiecznej pracy):

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

Obsługuje dowolną action który otrzyma funkcję, która robi tymczasowe zawijanie sprawdzanego typu wyjątku do RuntimeException. To zawijanie będzie przezroczyste, metoda attempt zakończy normalnie lub wyrzuci oryginalny sprawdzony wyjątek E (lub niespokrewniony niesprawdzony wyjątek, jeśli wystąpi).

więc można go używać tak:

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); } 
     })); 
} 

Ze względu na zagnieżdżonych operacji kompilator nie jest w stanie wywnioskować wyjątek typu automatycznie. Powyższy kod używa wyraźnej deklaracji typu parametru thrower. Alternatywnie można użyć wywołania typu metody pomocnika, takiej jak

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

Nie możesz. Supplier#get() nie deklaruje rzucania żadnych (sprawdzonych) wyjątków. Pamiętaj, że wyrażenie lambda po prostu tworzy instancję, w rzeczywistości nie wywołuje docelowej metody interfejsu funkcjonalnego.

Jeśli chcesz, możesz zawinąć zaznaczony wyjątek w niezaznaczonym wyjątku i wyrzucić go.

Powiązane problemy