我已经了解Java中Runnable
和接口之间的区别。Callable
从 Java 1.5 开始,额外的特性被添加到Runnable
接口并被调用Callable
以保持向后兼容性。
我的问题是现在我们有了Callable
接口,我们应该一直使用它吗?不使用Callable
和使用的用例是Runnable
什么?
(这是一篇关于它们之间有什么区别的好文章)
我已经了解Java中Runnable
和接口之间的区别。Callable
从 Java 1.5 开始,额外的特性被添加到Runnable
接口并被调用Callable
以保持向后兼容性。
我的问题是现在我们有了Callable
接口,我们应该一直使用它吗?不使用Callable
和使用的用例是Runnable
什么?
(这是一篇关于它们之间有什么区别的好文章)
两者都有各自的用途,并且都由 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
”)。
恕我直言,当将函数作为参数时,Runnable 是一种更好的类型
不要忘记Callable.call()
抛出异常。这意味着如果您将 Callable 作为参数,则此 Callable 可以抛出任何类型的异常,并且您必须有一种方法以正确的方式处理它们。如果你不能这样做,最好让 Callable 的实现者按照他的意愿处理异常,并将参数设置为 Runnable 以明确这一点。
不使用的用例Callable
:ScheduledExecutorService.scheduleAtFixedRate
并且scheduleWithFixedDelay
只接受Runnable
。
我更喜欢Callable
s,但在极少数情况下您可能需要 a Callable
to be Runnable
,您可以通过将这样的run()
方法添加到您的Callable
.
public void run(){
try{
call();
} catch (Exception e){
e.printStackTrace(); // or however you log errors
}
}
在 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
}
}
}
然后您只需将任何内容更改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();
}
}
那么任何特殊的异常处理只需要实现自己的handleExceptions(Exception)
方法......但如果你不需要,你不必。我更喜欢这个,因为它允许你有一个使用你的日志框架等的实现。
Callable 和Runnable彼此相似,都可以用于实现线程。在实现Runnable的情况下,您必须实现run()方法,但在 callable 的情况下,您必须实现call()方法,两种方法的工作方式相似,但可调用的call()方法具有更大的灵活性。它们之间存在一些差异。
Runnable和callable之间的区别如下 -
1) runnable的run()方法返回void,这意味着如果您希望线程返回可以进一步使用的东西,那么您别无选择 Runnable run()方法。有一个解决方案'Callable',如果你想以对象的形式返回任何东西,那么你应该使用 Callable 而不是 Runnable。可调用接口具有返回 Object 的方法 'call()'。
方法签名 - Runnable->
public void run(){}
可调用->
public Object call(){}
2) 在Runnable run()方法的情况下,如果出现任何已检查的异常,则必须使用 try catch 块进行处理,但在Callable call()方法的情况下,您可以抛出已检查的异常,如下所示
public Object call() throws Exception {}
3) Runnable来自传统的java 1.0版本,但callable来自带有Executer框架的Java 1.5版本。
如果您熟悉Executers ,那么您应该使用 Callable 而不是 Runnable。
希望你能理解。