Java - 任务和未来 - 我需要捕获异常还是可以将它们留给应用程序线程?
Java - Tasks and Futures - Do I need to catch exceptions or can I leave them to the Application Thread?
我正在使用 JavaFX 编写一个转换器程序,并且正在使用推荐的 javafx.concurrent.Task
来完成远离 JavaFX 应用程序线程的繁重工作。我还在其中使用 java.util.concurrent.Future
和 java.util.concurrent.ExecutorService
来完成可以同时完成的额外工作。
然而,很多工作都涉及可能会抛出异常的方法,如果发生这种情况,我需要进程停止运行。我目前正在到处发送 try-catch
块和 return 错误而不是让异常冒出来。
但是因为 call()
在 Future
和 Task
中都有 throws Exception
声明以防万一有任何未捕获的,我可以不捕获吗Futures 中的异常并让它们在 Task
终止时由应用程序线程处理?
由于异常将执行我想要的并终止线程,同时向应用程序线程提供有关线程停止原因的额外信息,以便我可以显示适当的警报。
我想这样做的另一个原因是在 Futures 中我需要从 Task
线程访问值,但我不需要改变它们所以我想使值 final
并在 lambda 中创建 Futures。 try-catch
块使事情变得复杂,因为我不能像我想要的那样制作尽可能多的值 final
(或有效地 final
)。这是因为我正在从初始化它们时可能抛出的方法中分配 return 值。因此,我必须将赋值包围在 try-catch
中,因此需要在将临时变量复制到 final
变量之前继续创建临时变量,这会使过程看起来一团糟并且可能会浪费内存。
在 Task
或 Future
中捕获异常是不是一个好主意?在应用程序线程之前不捕获异常是否存在任何重大陷阱或问题?
这是我目前在我的控制器 class 中处理应该触发此过程的事件的示例:
ExecutorService converterExecutor = Executors.newSingleThreadExecutor();
ConverterTask converterThread = new ConverterTask()
converterExecutor.execute(converterThread);
Boolean success = null;
try
{
success = converterThread.get();
}
catch (InterruptedException | ExecutionException e1)
{
e1.printStackTrace();
return false;
}
if (success == null)
{
return false;
}
并且 ConverterTask
class 在另一个线程
中包含对我 运行 的 long-运行ning 逻辑
public class ConverterTask extends Task< Boolean >
{
public Boolean call() throws Exception
{
//do stuff
ExecutorService executor = Executors.newSingleThreadExecutor();
Future< String > skeletonThread = executor.submit(new Callable< String >()
{
//stuff that can throw exceptions
});
//do more stuff
String temp_sklData = null;
try
{
temp_sklData = skeletonThread.get();
}
catch (InterruptedException | ExecutionException e1)
{
e1.printStackTrace();
return false;
}
if (temp_sklData == null)
{
return false;
}
final String sklData = temp_sklData;
//do more stuff including use sklData in a Lambda Future
}
}
以及我想在 converterTask
中做什么,如果我传播异常是个好主意的话
public class converterTask extends Task< Boolean >
{
public Boolean call() throws Exception
{
//do stuff
ExecutorService executor = Executors.newSingleThreadExecutor();
Future< String > skeletonThread = executor.submit(new Callable< String >()
{
//stuff that can throw exceptions
});
//do more stuff
final String sklData = skeletonThread.get();
//do more stuff including use sklData in a Lambda Future
}
}
由于其他人在评论中指出的原因,我不太了解您的代码结构。但是你的问题的基本答案是,如果你可以优雅地处理异常,你应该使用 try
-catch
(这通常意味着你仍然可以 return 一个有意义的结果),并让他们如果没有传播。
所以一个 ConverterTask
将一个 String
转换成另一个,可能会抛出阻止转换发生的异常,看起来像
public class ConverterTask extends Task<String> {
private final String textToConvert ;
public ConverterTask(String textToConvert) {
this.textToConvert = textToConvert ;
}
@Override
public String call() throws Exception {
String result = doConversion(textToConvert); // may throw exception...
return result ;
}
}
典型的用法是
Executor conversionExec = ... ;
// ...
ConverterTask converterTask = new ConverterTask(someText);
converterTask.setOnSucceeded(e -> {
String result = converterTask.getValue();
// process result...
});
converterTask.setOnFailed(e -> {
// code to execute in case of unhandled exception...
// note you can get the exception with
Throwable thingThatWentWrong = converterTask.getException();
// ...
});
conversionExec.execute(converterTask);
请注意,处理程序(onSucceeded
或 onFailed
)中的代码是在 FX 应用程序线程上为您执行的,因此您不应阻塞这些方法,但您可以访问 UI个元素。
如果您有可以从中恢复的异常,您将按照
的方式做一些事情
@Override
public String call() {
try {
String result = doConversion(textToConvert);
return result ;
} catch (Exception e) {
// fallback computation that doesn't throw exception...
String result = doSafeConversion(textToConvert);
return result ;
}
}
然后你不需要 onFailed
处理程序。
显然,如果你有一些可恢复的异常和一些不可恢复的异常,你可以结合这两种技术:
@Override
public String call() throws Exception {
String partialResult ;
// recoverable:
try {
partialResult = doSomeProcessing(textToConvert);
} catch (Exception e) {
partialResult = computeFallbackValue(textToConvert);
}
// non-recoverable: may throw exception which is propagated out
String result = completeComputation(partialResult);
return result ;
}
(现在您又需要 onFailed
处理程序)。
我正在使用 JavaFX 编写一个转换器程序,并且正在使用推荐的 javafx.concurrent.Task
来完成远离 JavaFX 应用程序线程的繁重工作。我还在其中使用 java.util.concurrent.Future
和 java.util.concurrent.ExecutorService
来完成可以同时完成的额外工作。
然而,很多工作都涉及可能会抛出异常的方法,如果发生这种情况,我需要进程停止运行。我目前正在到处发送 try-catch
块和 return 错误而不是让异常冒出来。
但是因为 call()
在 Future
和 Task
中都有 throws Exception
声明以防万一有任何未捕获的,我可以不捕获吗Futures 中的异常并让它们在 Task
终止时由应用程序线程处理?
由于异常将执行我想要的并终止线程,同时向应用程序线程提供有关线程停止原因的额外信息,以便我可以显示适当的警报。
我想这样做的另一个原因是在 Futures 中我需要从 Task
线程访问值,但我不需要改变它们所以我想使值 final
并在 lambda 中创建 Futures。 try-catch
块使事情变得复杂,因为我不能像我想要的那样制作尽可能多的值 final
(或有效地 final
)。这是因为我正在从初始化它们时可能抛出的方法中分配 return 值。因此,我必须将赋值包围在 try-catch
中,因此需要在将临时变量复制到 final
变量之前继续创建临时变量,这会使过程看起来一团糟并且可能会浪费内存。
在 Task
或 Future
中捕获异常是不是一个好主意?在应用程序线程之前不捕获异常是否存在任何重大陷阱或问题?
这是我目前在我的控制器 class 中处理应该触发此过程的事件的示例:
ExecutorService converterExecutor = Executors.newSingleThreadExecutor();
ConverterTask converterThread = new ConverterTask()
converterExecutor.execute(converterThread);
Boolean success = null;
try
{
success = converterThread.get();
}
catch (InterruptedException | ExecutionException e1)
{
e1.printStackTrace();
return false;
}
if (success == null)
{
return false;
}
并且 ConverterTask
class 在另一个线程
public class ConverterTask extends Task< Boolean >
{
public Boolean call() throws Exception
{
//do stuff
ExecutorService executor = Executors.newSingleThreadExecutor();
Future< String > skeletonThread = executor.submit(new Callable< String >()
{
//stuff that can throw exceptions
});
//do more stuff
String temp_sklData = null;
try
{
temp_sklData = skeletonThread.get();
}
catch (InterruptedException | ExecutionException e1)
{
e1.printStackTrace();
return false;
}
if (temp_sklData == null)
{
return false;
}
final String sklData = temp_sklData;
//do more stuff including use sklData in a Lambda Future
}
}
以及我想在 converterTask
中做什么,如果我传播异常是个好主意的话
public class converterTask extends Task< Boolean >
{
public Boolean call() throws Exception
{
//do stuff
ExecutorService executor = Executors.newSingleThreadExecutor();
Future< String > skeletonThread = executor.submit(new Callable< String >()
{
//stuff that can throw exceptions
});
//do more stuff
final String sklData = skeletonThread.get();
//do more stuff including use sklData in a Lambda Future
}
}
由于其他人在评论中指出的原因,我不太了解您的代码结构。但是你的问题的基本答案是,如果你可以优雅地处理异常,你应该使用 try
-catch
(这通常意味着你仍然可以 return 一个有意义的结果),并让他们如果没有传播。
所以一个 ConverterTask
将一个 String
转换成另一个,可能会抛出阻止转换发生的异常,看起来像
public class ConverterTask extends Task<String> {
private final String textToConvert ;
public ConverterTask(String textToConvert) {
this.textToConvert = textToConvert ;
}
@Override
public String call() throws Exception {
String result = doConversion(textToConvert); // may throw exception...
return result ;
}
}
典型的用法是
Executor conversionExec = ... ;
// ...
ConverterTask converterTask = new ConverterTask(someText);
converterTask.setOnSucceeded(e -> {
String result = converterTask.getValue();
// process result...
});
converterTask.setOnFailed(e -> {
// code to execute in case of unhandled exception...
// note you can get the exception with
Throwable thingThatWentWrong = converterTask.getException();
// ...
});
conversionExec.execute(converterTask);
请注意,处理程序(onSucceeded
或 onFailed
)中的代码是在 FX 应用程序线程上为您执行的,因此您不应阻塞这些方法,但您可以访问 UI个元素。
如果您有可以从中恢复的异常,您将按照
的方式做一些事情@Override
public String call() {
try {
String result = doConversion(textToConvert);
return result ;
} catch (Exception e) {
// fallback computation that doesn't throw exception...
String result = doSafeConversion(textToConvert);
return result ;
}
}
然后你不需要 onFailed
处理程序。
显然,如果你有一些可恢复的异常和一些不可恢复的异常,你可以结合这两种技术:
@Override
public String call() throws Exception {
String partialResult ;
// recoverable:
try {
partialResult = doSomeProcessing(textToConvert);
} catch (Exception e) {
partialResult = computeFallbackValue(textToConvert);
}
// non-recoverable: may throw exception which is propagated out
String result = completeComputation(partialResult);
return result ;
}
(现在您又需要 onFailed
处理程序)。