如何将简单的 setter 解释为 Consumer<T>?
How is a simple setter interpreted as Consumer<T>?
首先,请多多包涵。大部分时间我都在使用 Scala(有时只是在 JVM 端)或其他语言,所以我的 Java (8) 知识有点有限!
我必须重构的代码到处都是空检查。我想让一些 pojo 属性的 setting/overriding 更好一点,并且很高兴能够使用 Java 8 来完成这项工作。
所以我创建了这个:
private <T> void setOnlyIfNotNull(final T newValue, Consumer<T> setter) {
if(newValue != null) {
setter.accept(newValue);
}
}
并像这样使用它:
setOnlyIfNotNull(newUserName, user::setName);
junit4-test 看起来像这样:
@Test
public void userName_isOnlyUpdated_ifProvided() {
User user = new User("oldUserName");
UserUpdateRequest request = new UserUpdateRequest().withUserName("newUserName");
service.updateUser(user, request); // This calls setOnlyIfNotNull behind the curtain. And it does invoke the setter ONLY once!
assertThat(user.getUserName()).isEqualTo("newUserName");
}
这行得通。在我请同事进行代码审查之前,我对自己很满意。在解释我所做的事情后,他详细说明他认为这行不通,因为函数仍然不是 Java 中的第一个 class 公民,并且 User-pojo 没有扩展 FunctionalInterface。还在 class 级别而非功能级别提供接口。
现在我想知道,为什么测试有效,我在这里滥用了什么吗?天真的我只是简单地想象 Java 编译器知道 setter 的 T setT(T value)
签名与 Consumer<T>
.
的相同
编辑:详细说明一下:如果我将测试更改为失败,例如使用 assertThat(user.getUserName()).isEqualTo("Something");
它失败并出现预期的 comparisonFailure!
评论在几个方面是错误的:
FunctionalInterface
不是接口正常运行所必需的。当标有此注释的内容不符合标准(作为只有一个抽象方法的接口)时,它只是一个编译器提示来标记错误
If a type is annotated with this annotation type, compilers are
required to generate an error message unless:
- The type is an interface type and not an annotation type, enum, or
class.
- The annotated type satisfies the requirements of a functional
interface.
However, the compiler will treat any interface meeting the
definition of a functional interface as a functional interface
regardless of whether or not a FunctionalInterface annotation is
present on the interface declaration.
- 无论如何,
User
应该是功能性的,Consumer
界面才是功能性的。
- 虽然函数确实可能不是 first-class 值(尽管请参阅 here 了解更多信息),但
user::setFoo
不是 "raw" 函数,它是构造创建一个实现 Consumer
的对象(在本例中),并使用传入的任何参数调用 user.setFoo()
。该机制表面上类似于匿名内部 classes 声明一个 class 并立即创建一个实例。 (但其背后的机制存在重大差异。)
但最有力的论据是您的代码显然有效,仅使用 Java 的官方和记录 API。所以说 "but Java doesn't support this" 有点奇怪。
首先,请多多包涵。大部分时间我都在使用 Scala(有时只是在 JVM 端)或其他语言,所以我的 Java (8) 知识有点有限!
我必须重构的代码到处都是空检查。我想让一些 pojo 属性的 setting/overriding 更好一点,并且很高兴能够使用 Java 8 来完成这项工作。
所以我创建了这个:
private <T> void setOnlyIfNotNull(final T newValue, Consumer<T> setter) {
if(newValue != null) {
setter.accept(newValue);
}
}
并像这样使用它:
setOnlyIfNotNull(newUserName, user::setName);
junit4-test 看起来像这样:
@Test
public void userName_isOnlyUpdated_ifProvided() {
User user = new User("oldUserName");
UserUpdateRequest request = new UserUpdateRequest().withUserName("newUserName");
service.updateUser(user, request); // This calls setOnlyIfNotNull behind the curtain. And it does invoke the setter ONLY once!
assertThat(user.getUserName()).isEqualTo("newUserName");
}
这行得通。在我请同事进行代码审查之前,我对自己很满意。在解释我所做的事情后,他详细说明他认为这行不通,因为函数仍然不是 Java 中的第一个 class 公民,并且 User-pojo 没有扩展 FunctionalInterface。还在 class 级别而非功能级别提供接口。
现在我想知道,为什么测试有效,我在这里滥用了什么吗?天真的我只是简单地想象 Java 编译器知道 setter 的 T setT(T value)
签名与 Consumer<T>
.
编辑:详细说明一下:如果我将测试更改为失败,例如使用 assertThat(user.getUserName()).isEqualTo("Something");
它失败并出现预期的 comparisonFailure!
评论在几个方面是错误的:
FunctionalInterface
不是接口正常运行所必需的。当标有此注释的内容不符合标准(作为只有一个抽象方法的接口)时,它只是一个编译器提示来标记错误If a type is annotated with this annotation type, compilers are required to generate an error message unless:
- The type is an interface type and not an annotation type, enum, or class.
- The annotated type satisfies the requirements of a functional interface.
However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a FunctionalInterface annotation is present on the interface declaration.
- 无论如何,
User
应该是功能性的,Consumer
界面才是功能性的。 - 虽然函数确实可能不是 first-class 值(尽管请参阅 here 了解更多信息),但
user::setFoo
不是 "raw" 函数,它是构造创建一个实现Consumer
的对象(在本例中),并使用传入的任何参数调用user.setFoo()
。该机制表面上类似于匿名内部 classes 声明一个 class 并立即创建一个实例。 (但其背后的机制存在重大差异。)
但最有力的论据是您的代码显然有效,仅使用 Java 的官方和记录 API。所以说 "but Java doesn't support this" 有点奇怪。