[英]Java 8 lambda catching exception
摘自Cay Horstmann 的《不耐煩的Java 8 》一書:
您是否不總是討厭必須在Runnable中處理檢查的異常? 編寫一個
uncheck
的方法來捕獲所有選中的異常,並將它們轉變為未選中的異常。 例如,new Thread(uncheck( () -> { System.out.println("Zzz"); Thread.sleep(1000); })).start(); // Look, no catch (InterruptedException)!
提示:定義接口
RunnableEx
其run
方法可能會引發任何異常。 然后實施public static Runnable uncheck(RunnableEx runner)
在uncheck函數中使用lambda表達式。
為此,我編寫如下代碼:
public interface RunnableEx {
void run() throws Exception;
}
public class TestUncheck {
public static Runnable uncheck(RunnableEx r) {
return new Runnable() {
@Override
public void run() {
try {
r.run();
} catch (Exception e) {
}
}
};
}
public static void main(String[] args) {
new Thread(uncheck(
() -> {
System.out.println("Zzz");
Thread.sleep(1000);
}
)).start();
}
}
我按照提示做了嗎? 有更好的方法嗎?
另外還有一個補充問題:
為什么不能只使用
Callable<Void>
而不是RunnableEx?
您的代碼無法將已檢查的異常包裝為未檢查的異常。 此外,它沒有遵循使用lambda表達式的提示。 更正后的版本為:
public static Runnable uncheck(RunnableEx r) {
return () -> {
try {
r.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
確實有可能進一步改善這一點。 由於RunnableEx
接口的全部用途是包裝Runnable
,因此可以將factory方法放置在接口本身內:
public interface RunnableEx {
void run() throws Exception;
public static Runnable uncheck(RunnableEx r) {
return () -> {
try {
r.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
當然,現在您的調用代碼必須適用於:
public static void main(String[] args) {
new Thread(RunnableEx.uncheck(
() -> {
System.out.println("Zzz");
Thread.sleep(1000);
}
)).start();
}
現在,該接口本身可以實現包裝功能,從而與Runnable
兼容,從而消除了使用Runnable
和RunnableEx
實例來表示單個動作的需要:
public interface RunnableEx extends Runnable {
void runWithException() throws Exception;
@Override default void run() {
try {
runWithException();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Runnable uncheck(RunnableEx r) {
return r;
}
}
請注意,盡管調用代碼不會在語法上進行更改,但它會首先隱式地創建一個Runnable
實例,這在創建RunnableEx
實例時RunnableEx
,這就是為什么uncheck
成為no-op的原因,而只是充當應創建RunnableEx
的標記而非Runnable
。 使用此接口定義,您可以通過
public static void main(String[] args) {
new Thread( (RunnableEx) () -> {
System.out.println("Zzz");
Thread.sleep(1000);
}
).start();
}
在這里不能“僅使用” Callable<Void>
是, Callable<Void>
仍然是Callable
,要求實現代碼返回一個值。 換句話說,沒有從void
到Void
隱式轉換。 因此,您可以使用它,但是lambda表達式需要return null;
然后在其末尾聲明( null
是唯一與Void
兼容的值)。
public class TestUncheck {
public static Runnable uncheck(Callable<Void> r) {
return () -> {
try { r.call(); }
catch (Exception e) { throw new RuntimeException(e); }
};
}
public static void main(String[] args) {
new Thread(uncheck(
() -> {
System.out.println("Zzz");
Thread.sleep(1000);
return null;
}
)).start();
}
}
從lambdas捕獲異常的這種方法很好用,並且是(還有一些附加功能)在流行的Java庫jOOλ的Unchecked
類中實現的一種方法。
為了進行比較,請參見其靜態方法Unchecked.runnable
,該方法與您的解決方案相同,除了其Exception
處理程序和lambda縮寫了返回值。
關於從Java 8分配給Im Patients的分配,您的uncheck
方法不使用lambda(為此,請參見Unchecked.runnable
方法),並且不會引發未檢查的異常。 為此,您的catch
塊(當前為空)需要將異常包裝為未經檢查的異常。 有很多方法可以做到,而有關SO的許多問題都與之相關:
但是一個簡單的方法是:
throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
最后,為了回答Callable<Void>
問題,我假設您的意思是“而不是Runnable
”? 如果是這樣,那是因為Thread
的構造函數將Runnable
作為參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.