【问题标题】:Java 8, Lambda : replace Anonymous inner class by lambdaJava 8,Lambda:用 lambda 替换匿名内部类
【发布时间】:2014-08-12 17:27:03
【问题描述】:

我有一个包含以下内容的类:

List roles = ldapTemplate.search(baseDn, replaceFilter, sc,
            new AttributesMapper() {
                public Object mapFromAttributes(Attributes attrs)
                        throws NamingException {
                    return attrs.get("cn").get();
                }
            });

IntelliJ 告诉我用 lambda 替换匿名内部类。 所以我尝试了:

List roles = ldapTemplate.search(
    baseDn, replaceFilter, sc,
    (Attributes a)  -> { return a.get("cn").get(); };
);

但是,我得到一个编译错误:

Error:(46, 50) java: incompatible types: inference variable T has incompatible bounds
    equality constraints: java.lang.String
    lower bounds: java.lang.Object

我找不到这个问题的解决方案。你有什么想法吗?

【问题讨论】:

  • 看起来需要将 lambda 的返回值转换为 String
  • 是(属性 a)->(字符串)a.get("cn").get() 一切都很好。但是我不明白为什么在我的内部类中我返回一个对象并且一切都很好,而不是在 lambda 中。
  • 我不确定,但它一定与类型推断有关。我刚刚在我的机器上尝试了一个简单的测试,它似乎可以在没有强制转换的情况下工作。使用的Java版本是java version "1.8.0_05" Java(TM) SE Runtime Environment (build 1.8.0_05-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

标签: java lambda java-8


【解决方案1】:

一个简单的天蓝色存储Entity Resolver接口及其实现方法:

EntityResolver<String> orderNumberResolver = new EntityResolver<String>() {
    @Override
    public String resolve(String partitionKey, String rowKey, Date timeStamp,
        HashMap<String, EntityProperty> properties, String etag) {
      return properties.get("SomeColumnName").getValueAsString();
    }
  };

上述方法的 Lambda 将是:

 EntityResolver<String> orderNumberResolver = (
          partitionKey, rowKey, timeStamp, properties, etag
      ) -> properties.get("SomeColumnName").getValueAsString();

从上面的示例中可以清楚地看出,lambda 足够聪明,可以根据其匿名内部类处理方法参数的类型,从而使重写方法的实现变得容易。希望这会有所帮助。

【讨论】:

    【解决方案2】:

    试试这个(去掉多余的分号)

    List roles = ldapTemplate.search(
        baseDn, replaceFilter, sc,
        (Attributes a)  -> { return a.get("cn").get(); }            
    );
    

    【讨论】:

    • 问题中的代码有什么不同?啊,多余的分号。您可以将此添加到您的答案中吗?
    • '列出角色 = ldapTemplate.search(baseDn, replaceFilter, sc,(a) -> a.get("cn").get());'即使这样也应该工作
    【解决方案3】:

    我有强烈的感觉,你没有在你的问题中发布确切的代码。与Bart 一样,我无法使用您发布的代码重现错误。

    但是,让我印象深刻的是您对原始类型的使用。如果您的原始代码如下所示:

    List<String> roles = ldapTemplate.search(baseDn, replaceFilter, sc,
        new AttributesMapper() {
            public Object mapFromAttributes(Attributes attrs)
                    throws NamingException {
                return attrs.get("cn").get();
            }
        });
    

    (请注意 roles 变量的更改类型)当您在没有类型参数的情况下实现 AttributesMapper 时,您将得到一个 原始类型 警告,并且不会检查是否返回Object 将作为 List&lt;String&gt; 的元素有效。

    当将该代码转换为 lambda 时,您再也无法摆脱它:

    List<String> roles = ldapTemplate.search(baseDn, replaceFilter, sc,
      (Attributes a)  -> { return a.get("cn").get(); }            
    );
    

    现在,编译器将为您推断类型 AttributesMapper&lt;String&gt; 并产生错误,因为您的 lambda 表达式返回 Object 而不是 String,因此不满足 AttributesMapper&lt;String&gt; 接口。

    您可以通过插入类型转换来满足 AttributesMapper&lt;String&gt; 接口或使用原始类型 List 声明 roles 来解决此问题,就像您在问题中所做的那样。但是,使用类型转换将是更简洁的方式(并且应该是唯一一种不会产生编译器警告的方式):

    List<String> roles = ldapTemplate.search(baseDn, replaceFilter, sc,
        a -> (String)a.get("cn").get());
    

    (我简化了表达式以补偿包含的类型转换,看起来好多了,不是吗?)

    【讨论】:

      【解决方案4】:

      下面的代码显示了使用匿名内部类获取学生比较器。

      private static final Comparator<StudentDto> studentScoreComparator = new Comparator<StudentDto>() {
                  @Override
                  public int compare(StudentDto s1, StudentDto s2) {
                    if (s2.getScore() < s1.getScore()) {
                      return 1;
                    }
                    return s2.getScore() == s1.getScore() ? 0 : 1;
                  }
                };
      

      使用 Java8 amd Sonar 建议只包含一种方法的匿名内部类应该成为 lambdas 可以如下转换。

      private static final Comparator<StudentDto> studentScoreComparator = (s1, s2) -> {
              if (s2.getScore() < s1.getScore()) {
                return 1;
              }
              return s2.getScore() == s1.getScore() ? 0 : 1;
            };
      

      只有一种方法实现的匿名内部类可以是 考虑为功能接口,可以很容易地被视为 Lambda 表达式。

      【讨论】:

        猜你喜欢
        • 2018-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-09
        • 1970-01-01
        • 2020-03-31
        相关资源
        最近更新 更多