2015-11-23 32 views
1

除非我捕獲並重新捕獲Lambda表達式中的各種異常,否則下面的代碼不會編譯。任何人都可以幫我理解爲什麼?Servlet中的Java Lambda表達式

protected void doGet(HttpServletRequest req, HttpServletResponse res) 
    throws ServletException, IOException 
    { 
     Consumer <String> forwardTo =(s) -> 
     { 
      RequestDispatcher rd= req.getRequestDispatcher(s); 
      try { 
       rd.forward(req, res); 
      } catch (IOException|ServletException is) { 
       try { 
        throw new Exception(is); 
       } catch (Exception e) { 
       } 
      } 
     }; 
+0

我用javac編譯1.8.0_66 。真正的問題是,自從doGet拋出這些異常,爲什麼我必須再次捕捉它們呢? – Jerrolds

+0

Lambdas是函數,它們需要自己的異常處理。 Althouhh'doGet'拋出'IOException',它沒有考慮在lambdas中拋出的異常 –

+0

我明白,但req和res是doGet傳遞的。 – Jerrolds

回答

1

那麼doGet會拋出異常,但是您的lambda沒有在doGet中執行。你只是聲明一個變量 - 這與執行你寫的表達式不同。

在前期的java-8這相當於代碼:

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { 
    Consumer<String> forwardTo = new Consumer<String>() { 
      @Override 
      public void accept(String t) { 
       RequestDispatcher rd = req.getRequestDispatcher(t); 
       try { 
        rd.forward(req, res); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
    }; 
} 
+0

我仍然感到困惑的一些變量,爲什麼我不得不重新捕獲異常 – Jerrolds

+0

因爲你添加的代碼重新拋出異常:!拋出新的異常(是);,刪除了這一行,所以你不需要重新抓住它 – 6ton

+0

感謝稍微改變話題,我想我明白這個例子 – Jerrolds

0

只能扔出去RuntimeExceptions lambda函數的。如果將throw new Exception(is);更改爲throw new RuntimeException(is);,則不需要重新捕獲Exception

另一個支持未經檢查的異常的理由,特別是在使用Java 8流時。

0

Java 8中的默認功能接口聲明爲不引發檢查異常。這意味着您需要以某種方式處理代碼可能拋出的已檢查異常。

如果您還沒有對Java 8的功能接口硬盤的依賴,則可以只寫自己:

interface ThrowingConsumer<T,E extends Exception> { public void accept(T t) throws E;} 

就用這個代替了Java 8 Consumer的。

如果你對Java的8個功能接口硬盤的依賴,可以隨時換由此產生的異常:

public <T> Consumer<T> ignoreExceptions(ThrowingConsumer<T,?> consumer){ 
    return t -> { 
    try{consumer.accept(t);}catch(Throwable t){/*ignored*/} 
    }; 
} 

您可以使用此方法是這樣的:

Consumer<String> forwardTo = ignoreExceptions(t -> 
     req.getRequestDispatcher(t).forward(req, res)); 

或者,你可以重新拋出它們:

public <T> Consumer<T> rethrowExceptions(ThrowingConsumer<T,?> consumer){ 
    return t -> { 
    try{consumer.accept(t);}catch(Throwable t){throw new RuntimeException(e);} 
    }; 
} 
0

ServletRequest.getRequestDispatcher方法需要一個St環論。你的代碼沒有爲消費者指定一個通用類型,所以爲你的lambda參數「s」給出的類型是一個對象。如果你這樣宣佈消費者:它應該編譯消費者。

您必須捕捉異常的原因是因爲RequestDispatcher.forward方法拋出ServletException和IOException,這兩者都是java調用「Checked Exception」的原因。檢查的異常必須由調用者處理。這裏有一篇關於Java中的例外的文章(網上有很多)。 http://www.geeksforgeeks.org/checked-vs-unchecked-exceptions-in-java/

如果你想創建的檢查異常轉換爲未檢查的一個,因爲我在下面的代碼做了,你可以創建一個新的RuntimeException的方法:

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException 
{ 
    Consumer<String> forwardTo = (s) -> 
    { 
     forward(req, res, s); 
    }; 
} 

private void forward(HttpServletRequest req, HttpServletResponse res, String s) 
{ 
    RequestDispatcher rd = req.getRequestDispatcher(s); 
    try 
    { 
     rd.forward(req, res); 
    } 
    catch (IOException|ServletException is) 
    { 
     throw new RuntimeException(is); 
    } 
}