我正在使用JavaFX编写转换程序,并使用推荐的javafx.concurrent.Task
来完成远离JavaFX应用程序线程的繁重工作。我还在其中使用java.util.concurrent.Future
和java.util.concurrent.ExecutorService
来完成可以同时完成的额外工作。
然而,很多工作都涉及可能抛出的方法,如果发生这种情况,我需要进程停止。我目前在所有地方发送try-catch
个版块的垃圾邮件并返回错误,而不是让异常冒出来。
但由于call()
和Future
中的Task
都有throws Exception
声明,以防有任何未被删除的声明,我是否可以抓住异常在期货中,当Task
终止时,让它们由应用程序线程处理?
因为异常将执行我想要的操作并终止线程,同时提供有关线程停止到应用程序线程的原因的额外信息,以便我可以显示适当的警报。
我想要这样做的另一个原因是在期货中我需要访问Task
线程中的值,但我不需要改变它们所以我想制作价值观final
并在lambdas中创建Futures。 try-catch
区块使问题变得复杂,因为我无法像我一样制作尽可能多的值final
(或有效final
)。这是因为我在初始化时可能会抛出可能抛出的方法的返回值。因此,我必须在try-catch
中包围赋值,因此需要在将临时变量复制到final
变量之前继续创建临时变量,这会使进程看起来很乱并且可能会浪费内存。
是不是在Task
或Future
内捕捉异常是不是一个好主意?在应用程序线程之前是否存在任何未捕获异常的重大缺陷或问题?
以下是我目前在控制器类中处理应触发此过程的事件的示例:
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
类在另一个线程中运行
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
}
}
答案 0 :(得分:0)
由于其他人在评论中指出的原因,我并不真正理解您的代码结构。但是你的问题的基本答案是你应该使用try
- catch
,如果你可以优雅地处理异常(这通常意味着你仍然可以返回一个有意义的结果),如果没有,就让它们传播。
因此,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
或@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 ;
}
}
)中的代码都是在FX Application Thread上执行的,因此您不应该阻止这些方法,但是您可以访问UI元素。 / p>
如果您有可以恢复的例外情况,那么您可以采取行动
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
(现在你需要再次使用Compensation
处理程序。)