抱歉,我很确定肯定已经有人问过类似的问题,但我就是找不到答案。
假设有一个服务类
ChessEngineService
,它有一个实例方法:
String getBestMove(Query query);
还有一个服务客户端当前正在对服务进行同步调用,如下所示:
String move = chessEngineService.getBestMove(query);
由于此调用是阻塞的并且可能需要很长时间执行,因此需要使调用异步,例如使用
CompletableFuture
:
CompletableFuture.supplyAsync(chessEngineService::getBestMove).thenAccept(...)
问题是,
Supplier
for supplyAsync()
不接受任何参数,因为它只是一个无参数的get()
。
我尝试为
Query
引入一个实例变量,在 ChessEngineService
中为它引入一个设置器,以及 getBestMove()
的重载版本,没有参数在内部使用上述 Query
变量,但我不喜欢这样一个解决方案主要是因为chessEngineService
应该保持无状态。
如果有更好的想法,我们将不胜感激。
人们喜欢方法引用 (
typeOrInstance::method
),因为它们几乎可以完成普通 lambda 可以做的所有事情,同时(主观上)更干净、更清晰、更易于阅读/理解。
您已经一头扎进了他们不能做的少数事情之一,但是普通的lambda可以做——方法引用不能从其本地范围获取状态(除非您使用实例方法引用形式) ,稍后会详细介绍)。
所以,理解了这一点,让我们回到你的例子。
您有一个方法
getBestMove
,并且您想在实例 chessEngineService
上调用它(其类型与名称相同)。具体来说,您想传入变量query
。
嗯,最简单的方法是使用普通的 lambda 表达式。这是对您的示例的修改。
CompletableFuture.supplyAsync(() -> chessEngineService.getBestMove(query)).thenAccept(...)
现在,因为您正在执行普通的 lambda 形式(特别是 lambda 表达式形式),所以您 CAN 从本地范围中获取状态,并插入到您的
Supplier
中——即使 Supplier
不接受参数。
这是 lambda 的功能之一,也是它们有多种形式的原因。方法引用形式不仅更简洁,而且还传达信息——方法引用形式除了将实例列为方法提供者之外不能包含任何本地状态。澄清一下,如果您有方法引用
String::length
,则您正在使用类名称,因此,这是一个纯粹的无状态 lambda。然而,如果你这样做someString::length
,传入的唯一状态就是实例someString
。
方法引用可让您快速认识到 lambda 中恰好包含 0 或 1 个本地状态,而普通 lambda 可以包含任意数量的本地状态 (
() -> Arrays.asList(local1, local2, local3, local4, etc)
)。