如何将简单的setter解释为Consumer <t>?

时间:2017-05-02 10:44:07

标签: java functional-programming java-8 functional-interface

首先,请耐心等待。大多数时候我在Scala(有时只在JVM端)或其他语言工作,所以我的Java(8)知识有点受限!

我必须重构的代码充满了空检查。我想让一些pojo的属性设置/覆盖更好一些,并且很高兴能够使用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中的一等公民,而User-pojo没有扩展FunctionalInterface。接口也是在类级别提供的,而不是功能级别。

现在我想知道,为什么测试有效,我在这里滥用了什么?天真的我只是想象Java编译器知道setter的T setT(T value)签名与Consumer<T>的签名相同。

编辑:详细说明:如果我将测试更改为失败,例如使用assertThat(user.getUserName()).isEqualTo("Something");时,如果遇到比较失败,则会失败!

1 个答案:

答案 0 :(得分:7)

该评论有几个错误:

    接口功能不需要
  1. FunctionalInterface。当标记有此注释的内容不符合标准(仅具有一个抽象方法的接口)时,它只是一个编译器提示标记错误
      

    如果使用此注释类型注释类型,则编译器是   需要生成错误消息,除非:

         
        
    • 类型是接口类型,而不是注释类型,枚举或   类。
    •   
    • 注释类型满足功能的要求   接口。
    •   
         

    但是,编译器会处理符合的任何接口   将功能接口定义为功能接口   无论FunctionalInterface注释是否是   出现在界面声明中。

  2. 在任何情况下,它都不是User应该是正常的,它是Consumer接口,它是有效的。
  3. 虽然函数确实可能不是一等值(虽然有关详细信息,请参阅here),user::setFoo不是&#34; raw&#34; function,它是一个构造,它创建一个实现Consumer的对象(在本例中),并使用传入的任何参数调用user.setFoo()。该机制表面上类似于匿名内部类声明的方式一个类并立即创建一个实例。 (但其背后的机制存在重大差异。)
  4. 但最强有力的论据是,您的代码只能使用Java的官方和文档API来证明是有效的。所以说&#34;但是Java并不支持这个&#34;是一种奇怪的想法。