[英]Is there a way to make Runnable's run() throw an exception?
您可以使用Callable
相反,它提交給ExecutorService
,並等待結果FutureTask.isDone()
的返回ExecutorService.submit()
當isDone()
返回true時,您調用FutureTask.get()
。 現在,如果你的Callable
拋出了一個Exception
那么FutureTask.get()
也會拋出一個Exception
並且你可以使用Exception.getCause()
來訪問原始的Exception。
如果run()
拋出一個已檢查的異常,那會有什么結果呢? 您無法在處理程序中包含該run()
調用,因為您沒有編寫調用它的代碼。
您可以在run()
方法中捕獲已檢查的異常,並在其位置拋出未檢查的異常(即RuntimeException
)。 這將使用堆棧跟蹤終止線程; 也許這就是你所追求的。
如果您希望run()
方法在某處報告錯誤,那么您可以為run()
方法的catch
塊提供一個回調方法來調用; 該方法可以在某處存儲異常對象,然后您感興趣的線程可以在該位置找到該對象。
如果你想將一個實現Runnable
的類傳遞給Thread
框架,那么你必須遵循該框架的規則,參見Ernest Friedman-Hill的答案,為什么這樣做是一個壞主意。
不過,我有一種預感,你想直接在代碼中調用run
方法,因此你的調用代碼可以處理異常。
這個問題的答案很簡單。 不要使用Thread庫中的Runnable
接口,而是使用修改后的簽名創建自己的接口,該簽名允許拋出已檢查的異常,例如
public interface MyRunnable
{
void myRun ( ) throws MyException;
}
您甚至可以創建一個適配器,將此接口轉換為適合在Thread框架中使用的真實Runnable
(通過處理已檢查的異常)。
是的,有一種方法可以從run()
方法中拋出一個已檢查的異常,但它太可怕了,我不會分享它。
這是你可以做的事情; 它使用與運行時異常相同的機制:
@Override
public void run() {
try {
/* Do your thing. */
...
} catch (Exception ex) {
Thread t = Thread.currentThread();
t.getUncaughtExceptionHandler().uncaughtException(t, ex);
}
}
正如其他人所指出的,如果你的run()
方法確實是Thread
的目標,那么拋出異常是沒有意義的,因為它是不可觀察的; 拋出異常與不拋出異常(無)具有相同的效果。
如果它不是Thread
目標,請不要使用Runnable
。 例如,也許Callable
更適合。
@FunctionalInterface
public interface CheckedRunnable<E extends Exception> extends Runnable {
@Override
default void run() throws RuntimeException {
try {
runThrows();
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
void runThrows() throws E;
}
有些人試圖說服你必須遵守規則。 聽着,但不管你是否服從,你應該根據自己的情況決定自己。 現實是“你應該遵守規則”(而不是“你必須遵守規則”)。 請注意,如果您不遵守規則,可能會產生后果。
這種情況不僅適用於Runnable
的情況,而且在Streams和其他已引入功能接口的地方也非常頻繁地使用Java 8,而無法處理已檢查的異常。 例如, Consumer
, Supplier
, Function
, BiFunction
等都已聲明,沒有設施來處理已檢查的異常。
那么情況和選擇是什么? 在下面的文本中, Runnable
代表沒有聲明異常的任何功能接口,或者聲明對於手頭的用例來說太有限的異常。
Runnable
,並且可以用其他東西替換Runnable
。
Callable<Void>
替換Runnable
。 基本上是一樣的,但允許拋出異常; 並且最后必須return null
,這是一個輕微的煩惱。 @FunctionalInterface
替換Runnable
,它可以准確地拋出您想要的那些異常。 Callable<Void>
而不是Runnable
。 RuntimeException
包裝異常。 您可以嘗試以下方法。 這有點像黑客,但有時黑客是我們需要的。 因為,是否應該檢查或取消選中例外是由其類型定義的,但實際上應該根據情況來定義。
@FunctionalInterface
public interface ThrowingRunnable extends Runnable {
@Override
default void run() {
try {
tryRun();
} catch (final Throwable t) {
throwUnchecekd(t);
}
}
private static <E extends RuntimeException> void throwUnchecked(Throwable t) {
throw (E) t;
}
void tryRun() throws Throwable;
}
我比new RuntimeException(t)
更喜歡它,因為它有一個較短的堆棧跟蹤。
你現在可以這樣做:
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
免責聲明:在Java的未來版本中,當不僅在編譯時處理泛型類型信息,而且在運行時處理泛型類型信息時,實際上可以刪除以這種方式執行未經檢查的強制轉換的能力。
是的,您可以從 run() 方法中拋出已檢查的異常。 可以通過欺騙編譯器使用 generics 來完成。 看看這段代碼:
public static void main(String[] args) {
new Main().throwException();
}
public void throwException() {
Runnable runnable = () -> throwAs(new Exception());
new Thread(runnable).start();
}
private <T extends Throwable> void throwAs(Throwable t) throws T {
throw ( T ) t;
}
如果您想從 Runnable 的 run() 方法中拋出已檢查的異常,這可能會有所幫助
你的要求沒有任何意義。 如果要通知線程調用者發生的異常,可以通過回調機制來實現。 這可以通過處理程序或廣播或您能想到的任何其他內容。
最簡單的方法是定義自己的異常對象,該對象擴展RuntimeException
類而不是Exception
類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.