java 8 个消费者什么时候比一个可运行的界面更受欢迎?

When are java 8 consumers preferable over a runnable interface?

我的问题是在什么情况下或在什么情况下使用可调用接口比简单的单方法功能接口更好。

假设我们有一个带有基于任务的事件处理系统的游戏。它每秒循环一次事件队列。每个事件涉及一名球员。在什么情况下最好做

Consumer<Player> c1 = (player) -> player.sendMessage("hey"); 

超过

Runnable r1 = () -> player.sendMessage("hey");

刚刚发现这个问题:The difference between the Runnable and Callable interfaces in Java。它解释了有关多线程环境的一些要点,但我正在说明的情况涉及单线程环境。那还有关系吗?

我想您可能误解了 'functional interface' 的意思。在Java中,'functional interface'有一个非常具体的含义:一个interface只有一个抽象方法。 Java 上下文中功能接口的价值在于它们在 lambda 表达式中的使用。添加了注释以指示明确设计为功能性的接口。但它没有任何 run-time 语义:任何满足标准的接口都是功能性的。

所以,实际上,Runnable是一个函数式接口,只有一个抽象方法run。这使您的短语 "use a functional interface over for example a runnable interface" 毫无意义。

Java 在 java.util.function 包中提供了一整套 pre-defined 通用功能接口。这些纯粹是为了实用:让您不必创建多个本质上做同样事情的接口。

我个人的看法是这些应该谨慎使用。在你的情况下,事件处理系统大概是你系统的一个关键组件,让它持有实现 Event 接口的对象将使你的意图比持有 ObjLongConsumer<Player> 或类似的东西更清晰,即使你的事件发生了out 是一个具有相同签名的接口。

更新:

在您的评论中,您询问是否有理由让您的 Task 接口在所有情况下都通用。不,没有理由。使接口或 class 通用的唯一原因是它是否将在具有不同类型的多个上下文中使用。在您的情况下,如果任务将始终涉及 Player,则将其作为接口方法签名的具体部分,而不是参数化类型。

根据 Oracle 文档:

Functional interfaces often represent abstract concepts like functions, actions, or predicates. In documenting functional interfaces, or referring to variables typed as functional interfaces, it is common to refer directly to those abstract concepts, for example using "this function" instead of "the function represented by this object". When an API method is said to accept or return a functional interface in this manner, such as "applies the provided function to...", this is understood to mean a non-null reference to an object implementing the appropriate functional interface, unless potential nullity is explicitly specified. Functional interface are the interfaces that have only one functionality to implement. So basically, if you will see at runnable interface as well, it is again kind of function interface with only one functionality "run".

因此,您可以将函数式接口视为一种只有一个非默认函数的接口类别,各种接口如 Runnable 接口和 Comparable 接口都属于这一类。

另外,在JAVA8中你也可以直接使用lambda表达式匿名实现函数式接口:

Runnable r1 = () -> System.out.println("Hello World!");

使用lambda 表达式,使代码非常整洁和可读,也减少了行数。此外,lambda 表达式可以帮助使用 Streams 进行顺序和并行执行。

在使用函数式接口的同时,您还可以通过实现@FunctionalInterface 确保只有一个非默认函数,这样它就不会在以后的修改中中断。

更多关于功能接口的详细信息,您可以访问here