可调用是否优于Runnable?

she*_*aei 37 java concurrency

我已经理解了Java RunnableCallable接口之间的区别.从Java 1.5开始,在Runnable接口中添加了其他功能,并且Callable为了保持向后兼容性而调用了这些功能.

我现在的问题是我们有Callable接口,我们总是会使用它吗?不使用Callable和使用的用例有哪些Runnable

(是关于它们之间有什么区别的好文章)

bar*_*uin 34

两者都有它们的用途,并且都受到java.util.concurrent中的Executor框架的支持.Runnable已经存在了很长时间,但它仍然在使用而不是气馁.

Callables可以抛出异常并返回值,这使得它们成为结果承载任务的更好抽象(例如从网络获取资源,执行昂贵的值计算等)[来自Goetz的Java Concurrency in Practice,布洛赫等.al.,Java并发的标准工作].

因此,如果您正在设计API,我建议尽可能使用Callables.如果您确定任务不会返回值并且不会抛出异常,那么Runnables也是一个有效的选择.这里没有黑色和白色,特别是因为Runnables可以很容易地包含在Callables中,反之亦然.

顺便说一句,请注意您的Callable实现不需要声明throws Exception; Callable本身声明它只是允许实现者抛出任何已检查的异常.但是,仅依赖于Callable接口的Callable的调用者必须编写异常处理代码.
另请注意,Callables不需要返回值; 您可以简单地声明您的Callable返回Void(使用大写' V').


JB *_*zet 8

恕我直言,Runnable是一个更好的类型,用作参数作为参数

  • 没有返回值,但只有副作用
  • 必须处理异常,而不是传播它们

不要忘记Callable.call()抛出异常.这意味着如果你将Callable作为参数,这个Callable可以抛出任何类型的异常,你必须有一种方法以正确的方式处理它们.如果你不能这样做,最好让Callable的实现者按照自己的意愿处理异常,并使参数成为Runnable以使其清晰.


Evg*_*eev 7

使用不使用的情况下Callable:ScheduledExecutorService.scheduleAtFixedRatescheduleWithFixedDelay仅接受Runnable.


Ste*_*e K 6

我更喜欢Callables,但在极少数情况下你可能需要CallableRunnable,你可以通过向你的run()方法添加这样的方法来轻松实现Callable.

public void run(){
    try{
        call();
    } catch (Exception e){
        e.printStackTrace(); // or however you log errors
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java 8中,您还可以创建一个界面来为您执行相同的操作:

public interface CallableRunnable<T> extends Callable<T>, Runnable {
    default void run(){
        try {
            call();
        } catch (Exception e) {
            e.printStackTrace(); // or however you log errors
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

那么你只需要改变什么,implements Callable<T>implements CallableRunnable<T>.那这样,你的工作总是可以通过要求或者任何方法调用.当然,如果需要特定的错误处理,仍然可以覆盖run()方法来处理方法抛出的异常call().你甚至可以实现一个方法:

public interface CallableRunnable<T> extends Callable<T>, Runnable {
    default void run(){
        try {
            call();
        } catch (Exception e) {
            handleCallExceptions(e);
        }
    }

    default void handleCallExceptions(Exception e){
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后任何特殊的异常处理只需要实现自己的handleExceptions(Exception)方法......但如果你不需要,你不必这样做.我更喜欢这个,因为它允许你有一个使用你的日志框架等的实现.