简短的回答
不,这不是更自然的CompletableFuture.supplyAsync
使用Callable
,而不是Supplier
。这个论点几乎完全是关于语义的,所以如果你之后仍然不确定,那就没关系。
龙答案
的Callable
和Supplier
功能接口/ SAM类型在功能上几乎相等(原谅双关语),但其来源和用途不同。
Callable
被创建为java.util.concurrent
包的一部分。这个包来自Java 8中关于lambda表达式的巨大变化,最初集中在帮助您编写并发代码的一系列工具上,而不会偏离经典的动态多线程模型。
Callable
的主要用途是抽象可以在不同线程中执行并返回结果的动作。从Callable
的Javadoc中:
的Callable
接口类似于Runnable
,在两者都 设计用于一个其实例可能受 另一个线程执行。
Supplier
被作为java.util.function
包的一部分创建的。该包作为Java 8上述更改的组成部分。它提供了可以由lambda表达式和方法引用定位的常用函数类型。
一种这样的类型是没有参数返回结果的函数(即提供某种类型函数或函数)。
那么为什么Supplier
而不是Callable
?
CompletableFuture
是添加到由在Java中8的上述变化的启发,允许显影剂以构建在功能,隐含并行方式他的代码java.util.concurrent
包的一部分,而不是在它明确地处理并发。
它的supplyAsync
方法需要一种方法来提供特定类型的结果,并且对结果更感兴趣,而不是为了达到这个结果而采取的行动。它也不一定关心异常完成(另请参阅下面的...段落)。
但是,如果Runnable
用于无参数,无结果功能接口,不应使用Callable
用于无参数,单结果功能接口?
不一定。
对于没有参数且不返回结果(因此完全通过外部上下文中的副作用操作)的函数的抽象不包括在java.util.function
中。这意味着(有些恼人地)Runnable
被用在任何需要这种功能接口的地方。
那么Callable.call()
可以抛出的支票Exception
怎么办?
这是Callable
和Supplier
之间预期语义差异的一个小符号。
A Callable
是一个动作,可以在另一个线程中执行,并允许您检查其副作用的执行结果。如果一切顺利,您会得到特定类型的结果,但由于在执行某些操作时(特别是在多线程环境中)可能会出现异常情况,因此您可能还需要定义和处理这些异常情况。
另一方面,A Supplier
是您依赖于提供某种类型的对象的函数。作为Supplier
的直接消费者,例外情况不一定是您的责任。这是因为:
- ...功能接口通常用于在创建或变异数据,以及处理
Exception
可以均是一个独立的阶段,多阶段过程定义一个特定的阶段,如果你不在乎
- ...明确处理
Exception
小号显著减少的功能接口,Lambda表达式和方法表达能力引用
因为他们刚刚从C#,这通常命名为'行动<>'和'不同Func <>'接口,它们完成相同的工作,但不会让程序员感到困惑。所以他们扩大了具有相同签名但不同名称的方法的功能接口。他们可能认为这会帮助程序员提供一个合作的心理模型,但它不会:这只是一个小小的PITA。 – davidbak