Java 8,Lambda:用 lambda 替换匿名内部类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25270467/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:01:49  来源:igfitidea点击:

Java 8, Lambda : replace Anonymous inner class by lambda

javalambdajava-8

提问by user3934519

I've got a class which contains the following:

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

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

IntelliJ tells me to replace the anonymous inner class with a lambda. So I tried:

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

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

However, I get a compilation error:

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

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

I can't find the solution to this problem. Do you have any ideas?

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

回答by snaikar

Try this (removing extra semi colon)

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

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

回答by Holger

I have the strong feeling that you didn't post the exact code in your question. Like Bart, I cannot reproduce the error with the code as you have posted.

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

However, what strikes me is your use of raw types. If your original code looked like this:

然而,让我印象深刻的是你对raw types的使用。如果您的原始代码如下所示:

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

(note the changed type of the rolesvariable) you would get away with just a raw typewarning as you implemented AttributesMapperwithout type arguments and there will be no check whether the returned Objectwill be valid as an element for a List<String>.

(注意roles变量的更改类型)当你在没有类型参数的情况下实现时,你只会得到一个原始类型警告,AttributesMapper并且不会检查返回的值是否Object作为 a 的元素有效List<String>

When converting that code into a lambda, you cannot get away with it anymore:

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

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

Now, the compiler will infer the type AttributesMapper<String>for you and produce an error because your lambda expression returns Objectinstead of Stringand thus does not fulfill the AttributesMapper<String>interface.

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

You can fix that by either inserting a type cast to fulfill the AttributesMapper<String>interface or by declaring roleswith the raw type Listas you already did in the question. However, using the type cast will be the cleaner way (and should be the only one which does not produce compiler warnings):

您可以通过插入类型转换来实现AttributesMapper<String>接口或通过在问题中已经做的声明roles原始类型List来解决这个问题。但是,使用类型转换将是更简洁的方法(并且应该是唯一一种不会产生编译器警告的方法):

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

(I simplified the expression to compensate for the included type cast, looks much better, doesn't it?)

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

回答by Trilok Singh Devda

A simple azure storage Entity Resolver interface and it's implemented method:

一个简单的 Azure 存储实体解析器接口及其实现方法:

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 of the above method will be :

上述方法的 Lambda 将是:

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

It's clear from above example that lambda's are smart enough to handle the type of method parameters according to their anonymous inner class thus it makes the implementation of overridden method easy. Hope this will be helpful.

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

回答by Harsh

Below code shows get student Comparator using annonymous inner class.

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

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;
            }
          };

Using Java8 amd Sonar suggestion to Anonymous inner classes containing only one method should become lambdas Can be converted as below.

使用 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;
      };

Annonymous inner class which has only one method implementation can be consider as Functional Interface and can be easily treated as Lambda Expression.

只有一种方法实现的匿名内部类可以被认为是函数式接口,并且可以很容易地被视为 Lambda 表达式。