亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何從Java 8流中拋出檢查過的異常?

如何從Java 8流中拋出檢查過的異常?

呼啦一陣風 2019-07-04 12:37:25
如何從Java 8流中拋出檢查過的異常?如何從Java 8流/lambda中拋出檢查過的異常?換句話說,我希望像這樣編譯代碼:public List<Class> getClasses() throws ClassNotFoundException {          List<Class> classes =          Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")               .map(className -> Class.forName(className))               .collect(Collectors.toList());                       return classes;     }此代碼不編譯,因為Class.forName()以上拋出方法ClassNotFoundException,這是檢查過的。請注意,我不希望將選中的異常包裝在運行時異常中,而是拋出已包裝的未檢查異常。我想拋出檢查過的異常本身。,而不加丑陋try/catches去小溪。
查看完整描述

3 回答

?
慕的地10843

TA貢獻1785條經驗 獲得超8個贊

這,這個LambdaExceptionUtilHelper類允許您使用Java流中的任何檢查異常,如下所示:

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
      .map(rethrowFunction(Class::forName))
      .collect(Collectors.toList());

Class::forName拋出ClassNotFoundException,也就是查證..流本身也拋出ClassNotFoundException,而不是一些未經檢查的異常。

public final class LambdaExceptionUtil {@FunctionalInterfacepublic interface Consumer_WithExceptions<T, E extends Exception> {
    void accept(T t) throws E;
    }@FunctionalInterfacepublic interface BiConsumer_WithExceptions<T, U, E extends Exception> {
    void accept(T t, U u) throws E;
    }@FunctionalInterfacepublic interface Function_WithExceptions<T, R, E extends Exception> {
    R apply(T t) throws E;
    }@FunctionalInterfacepublic interface Supplier_WithExceptions<T, E extends Exception> {
    T get() throws E;
    }@FunctionalInterfacepublic interface Runnable_WithExceptions<E extends Exception> {
    void run() throws E;
    }/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .
    forEach(rethrowConsumer(ClassNameUtil::println)); */public static <T, E extends Exception> Consumer<T>
     rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
    return t -> {
        try { consumer.accept(t); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
    return (t, u) -> {
        try { biConsumer.accept(t, u); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) 
    */public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
    return t -> {
        try { return function.apply(t); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), 
    */public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
    return () -> {
        try { return function.get(); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }/** uncheck(() -> Class.forName("xxx")); */public static void uncheck(Runnable_WithExceptions t)
    {
    try { t.run(); }
    catch (Exception exception) { throwAsUnchecked(exception); }
    }/** uncheck(() -> Class.forName("xxx")); */public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
    {
    try { return supplier.get(); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }/** uncheck(Class::forName, "xxx"); 
    */public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
    try { return function.apply(t); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }@SuppressWarnings ("unchecked")private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E 
    { throw (E)exception; }}

關于如何使用它的許多其他示例(靜態導入之后)LambdaExceptionUtil):

@Testpublic void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));

    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(System.out::println));
    }@Testpublic void test_Function_with_checked_exceptions() throws ClassNotFoundException {
    List<Class> classes1          = Stream.of("Object", "Integer", "String")
                  .map(rethrowFunction(className -> Class.forName("java.lang." + className)))
                  .collect(Collectors.toList());

    List<Class> classes2          = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                  .map(rethrowFunction(Class::forName))
                  .collect(Collectors.toList());
    }@Testpublic void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
    Collector.of(
          rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
          StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
    }@Test    public void test_uncheck_exception_thrown_by_method() {
    Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));

    Class clazz2 = uncheck(Class::forName, "java.lang.String");
    }@Test (expected = ClassNotFoundException.class)public void test_if_correct_exception_is_still_thrown_by_method() {
    Class clazz3 = uncheck(Class::forName, "INVALID");
    }

附注1:這個rethrow方法LambdaExceptionUtil上面的類可以毫無畏懼地使用,并且是可以在任何情況下使用..這在很大程度上要感謝用戶@PaoloC,他幫助解決了最后一個問題:現在編譯器將要求您添加拋出子句,這一切就好像您可以在Java 8流上本地拋出檢查異常一樣。


附注2:這個uncheck方法LambdaExceptionUtil上面的類是額外的方法,如果您不想使用它們,可以將它們安全地從類中刪除。如果您確實使用了它們,請謹慎使用它們,而不是在了解以下用例、優點/缺點和限制之前:

·您可以使用uncheck方法,如果您正在調用一個方法,該方法實際上永遠不能拋出它聲明的異常。例如:新字符串(byteArr,“UTF-8”)拋出UnsuptedEncodingException,但是Java規范保證UTF-8始終存在。在這里,“拋出”聲明是一個討厭的問題,任何用最少的樣板使其保持沉默的解決方案都是受歡迎的:String text = uncheck(() -> new String(byteArr, "UTF-8"));

·您可以使用uncheck方法,如果您正在實現一個嚴格的接口,而您沒有添加拋出聲明的選項,那么拋出異常是完全合適的。包裝一個異常只是為了獲得拋出它的特權,結果會產生帶有虛假異常的堆棧跟蹤,這些異常不會提供關于實際出錯的信息。一個很好的例子是Runnable.run(),它不會拋出任何檢查過的異常。

·無論如何,如果您決定使用uncheck方法,請注意拋出檢查過的異常而沒有拋出子句的兩個后果:1)調用代碼將無法按名稱捕獲它(如果您嘗試,編譯器會說:異常永遠不會拋出在相應的try語句中)。它會出現氣泡,并且可能會被某些“捕捉異常”或“捕捉Throwable”捕獲,這可能是您想要的。2)這違反了“最不吃驚”的原則:它將不再足以抓住RuntimeException才能保證捕捉所有可能的異常。因此,我認為這不應該在框架代碼中完成,而應該只在您完全控制的業務代碼中完成。


查看完整回答
反對 回復 2019-07-04
?
慕桂英4014372

TA貢獻1871條經驗 獲得超13個贊

你不能安全地這么做。你可以作弊,但你的程序被破壞了,這不可避免地會回來咬人(應該是你,但我們的欺騙往往會對別人造成打擊)。

這里有一個稍微安全的方法(但我還是不推薦這樣做)。

class WrappedException extends RuntimeException {
    Throwable cause;

    WrappedException(Throwable cause) { this.cause = cause; }}static WrappedException throwWrapped(Throwable t) {
    throw new WrappedException(t);}try 
    source.stream()
          .filter(e -> { ... try { ... } catch (IOException e) { throwWrapped(e); } ... })
          ...}catch (WrappedException w) {
    throw (IOException) w.cause;}

在這里,您要做的是捕獲lambda中的異常,從流管道中拋出一個信號,該信號表示計算異常失敗,捕獲信號,并對該信號執行操作以拋出潛在的異常。關鍵是,您總是捕獲合成異常,而不是允許檢查的異常泄漏而不聲明該異常被拋出。


查看完整回答
反對 回復 2019-07-04
  • 3 回答
  • 0 關注
  • 2012 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號