Java -任务和未来-我是否需要捕获异常,或者我可以把它们留给应用程序线程



我正在使用JavaFX编写一个转换器程序,并且使用推荐的javafx.concurrent.Task来完成远离JavaFX应用程序线程的繁重工作。我还在其中使用java.util.concurrent.Futurejava.util.concurrent.ExecutorService来完成可以并发完成的额外工作。

然而,许多工作涉及可能抛出的方法,如果发生这种情况,我需要进程停止。我目前到处乱扔try-catch块,并返回false,而不是让异常冒泡。

但是,由于FutureTask中的call()都有throws Exception声明,以防有任何未捕获的声明,我是否可以不捕获期货中的异常,并让它们在Task终止时由应用程序线程处理?因为异常会做我想要的并终止线程,同时提供额外的信息,关于为什么线程停止到应用程序线程,所以我可以显示一个适当的警报。

我想这样做的另一个原因是在未来我需要访问Task线程的值,但我不需要改变它们,所以我想使值final并在lambda中创建未来。try-catch块使问题复杂化,因为我不能像我想的那样制作尽可能多的final(或有效的final)值。这是因为我分配了方法的返回值,这些方法在初始化时可能会抛出。因此,我必须在try-catch中包围赋值,因此需要在将它们复制到final变量之前不断创建临时变量,这使得过程看起来很混乱,并且可能浪费内存。

TaskFuture中不捕获异常是否是个好主意?是否有任何主要的陷阱或问题不捕捉异常,直到应用程序线程?

这里有一个例子,我目前有什么在我的控制器类来处理事件,应该触发这个过程:

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
    }
}

我真的不明白你代码的结构,原因是其他人在评论中指出的。但是你的问题的基本答案是,如果你能优雅地处理异常,你应该使用try - catch(这通常意味着你仍然可以返回一个有意义的结果),如果不能,让它们传播。

因此,将一个String转换为另一个ConverterTask,可能会抛出异常,阻止转换发生,看起来像

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);

请注意,处理程序(onSucceededonFailed)中的代码都是在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处理程序)。

相关内容

最新更新