Java lambda表达式除了保存代码行之外还有其他用途吗?

Java lambda表达式除了保存代码行之外还有其他用途吗?,java,lambda,java-8,Java,Lambda,Java 8,lambda表达式除了保存代码行之外还有其他用途吗 lambdas是否提供了解决不容易解决的问题的特殊功能?我看到的典型用法是,不写以下内容: Comparator<Developer> byName = new Comparator<Developer>() { @Override public int compare(Developer o1, Developer o2) { return o1.getName().compareTo(o2.getNa

lambda表达式除了保存代码行之外还有其他用途吗

lambdas是否提供了解决不容易解决的问题的特殊功能?我看到的典型用法是,不写以下内容:

Comparator<Developer> byName = new Comparator<Developer>() {
  @Override
  public int compare(Developer o1, Developer o2) {
    return o1.getName().compareTo(o2.getName());
  }
};
比较器byName=新比较器(){ @凌驾 公共整数比较(开发者o1、开发者o2){ 返回o1.getName().compareTo(o2.getName()); } }; 我们可以使用lambda表达式来缩短代码:

Comparator<Developer> byName =
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName());
比较器名称=
(开发者o1,开发者o2)->o1.getName().compareTo(o2.getName());

是的,有很多优点

  • 不需要定义整个类,我们可以将函数的实现传递给它本身作为参考。
    • 类的内部创建将创建.class文件,而如果使用lambda,则编译器将避免创建类,因为在lambda中传递的是函数实现而不是类
  • 代码可重用性比以前更高
  • 正如您所说,代码比正常实现要短

保存代码行可以被视为一项新功能,如果它使您能够以更短、更清晰的方式编写大量逻辑,从而减少其他人阅读和理解的时间

如果没有lambda表达式(和/或方法引用)
Stream
管道的可读性将大大降低

例如,想象一下,如果用匿名类实例替换每个lambda表达式,下面的
管道会是什么样子

List<String> names =
    people.stream()
          .filter(p -> p.getAge() > 21)
          .map(p -> p.getName())
          .sorted((n1,n2) -> n1.compareToIgnoreCase(n2))
          .collect(Collectors.toList());
列出名称=
people.stream()
.filter(p->p.getAge()>21)
.map(p->p.getName())
.已排序((n1,n2)->n1.比较信号案例(n2))
.collect(Collectors.toList());
它将是:

List<String> names =
    people.stream()
          .filter(new Predicate<Person>() {
              @Override
              public boolean test(Person p) {
                  return p.getAge() > 21;
              }
          })
          .map(new Function<Person,String>() {
              @Override
              public String apply(Person p) {
                  return p.getName();
              }
          })
          .sorted(new Comparator<String>() {
              @Override
              public int compare(String n1, String n2) {
                  return n1.compareToIgnoreCase(n2);
              }
          })
          .collect(Collectors.toList());
列出名称=
people.stream()
.filter(新谓词(){
@凌驾
公共布尔测试(p人){
返回p.getAge()>21;
}
})
.map(新函数(){
@凌驾
公共字符串应用(个人p){
返回p.getName();
}
})
.sorted(新的比较器(){
@凌驾
公共整数比较(字符串n1、字符串n2){
返回n1.比较信号案例(n2);
}
})
.collect(Collectors.toList());
这比使用lambda表达式的版本更难编写,而且更容易出错。这也更难理解

这是一条相对较短的管道


要使其在没有lambda表达式和方法引用的情况下可读,您必须定义包含此处使用的各种函数接口实例的变量,这将分割管道的逻辑,使其更难理解。

lambda只是匿名类的语法糖

在lambdas之前,匿名类可以用来实现同样的功能。每个lambda表达式都可以转换为匿名类

如果您使用IntelliJ IDEA,它可以为您进行转换:

  • 将光标放在lambda中
  • 按alt/option+enter

内部迭代 在迭代Java集合时,大多数开发人员倾向于获取一个元素,然后处理它。也就是说,取出该项,然后使用它,或者重新插入它,等等。对于8之前版本的Java,您可以实现一个内部类并执行以下操作:

numbers.forEach(new Consumer<Integer>() {
    public void accept(Integer value) {
        System.out.println(value);
    }
});
或者更好

numbers.forEach(System.out::println);
作为论据的行为 猜猜下面的例子:

public int sumAllEven(List<Integer> numbers) {
    int total = 0;

    for (int number : numbers) {
        if (number % 2 == 0) {
            total += number;
        }
    } 
    return total;
}

来源:

为了回答您的问题,事实上,lambdas不允许您做在java-8之前无法做的事情,相反,它可以让您编写更简洁的代码。这样做的好处是,您的代码将更清晰、更灵活。

Lambda表达式不会改变您通常可以用Java解决的问题集,但肯定会使解决某些问题更容易,这与我们不再使用汇编语言编程的原因相同。从程序员的工作中删除多余的任务会使生活变得更轻松,并允许您做一些您甚至不会去做的事情,只需要您(手动)生成的代码量即可

但是lambda表达式不仅仅是保存代码行。Lambda表达式允许您定义函数,在此之前,您可以使用匿名内部类作为解决方法,这就是为什么在这些情况下可以替换匿名内部类,但通常不能

最值得注意的是,lambda表达式是独立于它们将被转换到的函数接口定义的,因此它们没有可以访问的继承成员,而且,它们不能访问实现函数接口的类型的实例。在lambda表达式中,
this
super
与周围上下文中的含义相同,另请参见。此外,您不能创建新的局部变量来隐藏周围上下文的局部变量。对于定义函数的预期任务,这将删除许多错误源,但也意味着对于其他用例,可能存在无法转换为lambda表达式的匿名内部类,即使实现函数接口也是如此

此外,构造
new Type(){…}
保证生成一个新的不同实例(就像
new
总是做的那样)。如果在非
静态
上下文中创建,匿名内部类实例始终保留对其外部实例的引用。相反,lambda表达式仅在需要时捕获对
的引用,即如果它们访问
或非
静态
成员。它们还生成故意未指定标识的实例,这允许实现决定
public int sumAllEven(List<Integer> numbers) {
    int total = 0;

    for (int number : numbers) {
        if (number % 2 == 0) {
            total += number;
        }
    } 
    return total;
}
public int sumAll(List<Integer> numbers, Predicate<Integer> p) {
    int total = 0;

    for (int number : numbers) {
        if (p.test(number)) {
            total += number;
        }
    }
    return total;
}
sumAll(numbers, n -> n % 2 == 0);
//                 v--- create the lambda locally.
Consumer<Integer> action = (Consumer<Integer> & Serializable) it -> {/*TODO*/};
Function<IntUnaryOperator, IntUnaryOperator> twice = f -> f.andThen(f);
IntUnaryOperator plusThree = i -> i + 3;
var g = twice.apply(plusThree);
System.out.println(g.applyAsInt(7))
Predicate<String> startsWithA = (text) -> text.startsWith("A");
Predicate<String> endsWithX   = (text) -> text.endsWith("x");

Predicate<String> startsWithAAndEndsWithX =
        (text) -> startsWithA.test(text) && endsWithX.test(text);

String  input  = "A hardworking person must relax";
boolean result = startsWithAAndEndsWithX.test(input);
System.out.println(result);