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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47407180/
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-11-03 09:36:51  来源:igfitidea点击:

Do lambda expressions have any use other than saving lines of code?

javalambdajava-8

提问by Vikash

Do lambda expressions have any use other than saving lines of code?

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

Are there any special features provided by lambdas which solved problems which weren't easy to solve? The typical usage I've seen is that instead of writing this:

lambdas 是否提供了任何特殊功能来解决不容易解决的问题?我见过的典型用法是,而不是这样写:

Comparator<Developer> byName = new Comparator<Developer>() {
  @Override
  public int compare(Developer o1, Developer o2) {
    return o1.getName().compareTo(o2.getName());
  }
};

We can use a lambda expression to shorten the code:

我们可以使用 lambda 表达式来缩短代码:

Comparator<Developer> byName =
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName());

采纳答案by Holger

Lambda expressions do not change the set of problems you can solve with Java in general, but definitely make solving certain problems easier, just for the same reason we're not programming in assembly language anymore. Removing redundant tasks from the programmer's work makes life easier and allows to do things you wouldn't even touch otherwise, just for the amount of code you would have to produce (manually).

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

But lambda expressions are not just saving lines of code. Lambda expressions allow you to define functions, something for which you could use anonymous inner classes as a workaround before, that's why you can replace anonymous inner classes in these cases, but not in general.

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

Most notably, lambda expressions are defined independently to the functional interface they will be converted to, so there are no inherited members they could access, further, they can not access the instance of the type implementing the functional interface. Within a lambda expression, thisand superhave the same meaning as in the surrounding context, see also this answer. Also, you can not create new local variables shadowing local variables of the surrounding context. For the intended task of defining a function, this removes a lot of error sources, but it also implies that for other use cases, there might be anonymous inner classes which can not be converted to a lambda expression, even if implementing a functional interface.

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

Further, the construct new Type() { … }guarantees to produce a new distinct instance (as newalways does). Anonymous inner class instances always keep a reference to their outer instance if created in a non-staticcontext. In contrast, lambda expressions only capture a reference to thiswhen needed, i.e. if they access thisor a non-staticmember. And they produce instances of an intentionally unspecified identity, which allows the implementation to decide at runtime whether to reuse existing instances (see also “Does a lambda expression create an object on the heap every time it's executed?”).

此外,该构造new Type() { … }保证生成一个新的不同实例(new一如既往)。如果在非static上下文中创建,匿名内部类实例始终保留对其外部实例的引用。相比之下,lambda 表达式仅this在需要时捕获对引用,即如果它们访问this或非static成员。并且它们生成有意未指定身份的实例,这允许实现在运行时决定是否重用现有实例(另请参阅“ lambda 表达式每次执行时是否在堆上创建一个对象?”)。

These differences apply to your example. Your anonymous inner class construct will always produce a new instance, also it may capture a reference to the outer instance, whereas your (Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName())is a non-capturing lambda expression that will evaluate to a singleton in typical implementations. Further, it doesn't produce a .classfile on your hard drive.

这些差异适用于您的示例。您的匿名内部类构造将始终生成一个新实例,它也可能捕获对外部实例的引用,而您(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName())的非捕获 lambda 表达式将在典型实现中评估为单例。此外,它不会.class在您的硬盘驱动器上生成文件。

Given the differences regarding both, semantic and performance, lambda expressions may change the way programmers will solve certain problems in the future, of course, also due to the new APIs embracing ideas of functional programming utilizing the new language features. See also Java 8 lambda expression and first-class values.

鉴于语义和性能方面的差异,Lambda 表达式可能会改变程序员在未来解决某些问题的方式,当然,这也是由于新的 API 包含利用新语言特性的函数式编程思想。另请参阅Java 8 lambda 表达式和一等值

回答by Jared Smith

Programming languages are not for machines to execute.

编程语言不是供机器执行的。

They are for programmers to thinkin.

它们是供程序员思考的。

Languages are a conversation with a compiler to turn our thoughts into something a machine can execute. One of the chief complaints about Java from people who come to it from other languages (or leaveit forother languages) used to be that it forcesa certain mental model on the programmer (i.e. everything is a class).

语言是与编译器的对话,将我们的想法变成机器可以执行的东西。一个关于Java从谁走到它与其他语言(或人的主诉离开其他语言)曾经是,它迫使对程序员有一定的心理模型(即一切都是一个类)。

I'm not going to weigh in on whether that's good or bad: everything is trade-offs. But Java 8 lambdas allow programmers to thinkin terms of functions, which is something you previously could not do in Java.

我不会权衡这是好是坏:一切都是权衡。但Java 8 Lambda表达式允许程序员认为在以下方面的功能,这是你以前不能用Java做的。

It's the same thing as a procedural programmer learning to thinkin terms of classes when they come to Java: you see them gradually move from classes that are glorified structs and have 'helper' classes with a bunch of static methods and move on to something that more closely resembles a rational OO design (mea culpa).

这与程序程序员在使用 Java 时学习从类的角度进行思考是一样的:你会看到它们逐渐从光荣的结构类和具有一堆静态方法的“帮助”类转移到一些更接近于理性的面向对象设计(mea culpa)。

If you just think of them as a shorter way to express anonymous inner classes then you are probably not going to find them very impressive in the same way that the procedural programmer above probably didn't think classes were any great improvement.

如果您只是将它们视为表达匿名内部类的一种更短的方式,那么您可能不会像上面的程序程序员可能认为类没有任何重大改进一样,发现它们非常令人印象深刻。

回答by Eran

Saving lines of code can be viewed as a new feature, if it enables you to write a substantial chunk of logic in a shorter and clearer manner, which takes less time for others to read and understand.

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

Without lambda expressions (and/or method references) Streampipelines would have been much less readable.

如果没有 lambda 表达式(和/或方法引用),Stream管道的可读性就会低得多。

Think, for example, how the following Streampipeline would have looked like if you replaced each lambda expression with an anonymous class instance.

例如,想想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());

It would be:

这将是:

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());

This is much harder to write than the version with lambda expressions, and it's much more error prone. It's also harder to understand.

这比使用 lambda 表达式的版本更难编写,而且更容易出错。也比较难理解。

And this is a relatively short pipeline.

这是一个相对较短的管道。

To make this readable without lambda expressions and method references, you would have had to define variables that hold the various functional interface instances being used here, which would have split the logic of the pipeline, making it harder to understand.

为了在没有 lambda 表达式和方法引用的情况下使其可读,您必须定义保存此处使用的各种功能接口实例的变量,这会拆分管道的逻辑,使其更难理解。

回答by alseether

Internal iteration

内部迭代

When iterating Java Collections, most developers tend to getan element and then processit. This is, take that item out and then use it, or reinsert it, etc. With pre-8 versions of Java, you can implement an inner class and do something like:

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

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

Now with Java 8 you can do better and less verbose with:

现在使用 Java 8,你可以做得更好,更简洁:

numbers.forEach((Integer value) -> System.out.println(value));

or better

或更好

numbers.forEach(System.out::println);

Behaviors as arguments

作为参数的行为

Guess the following case:

猜下面的情况:

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

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

With Java 8 Predicate interfaceyou can do better like so:

使用 Java 8 Predicate 接口,您可以像这样做得更好:

public int sumAll(List<Integer> numbers, Predicate<Integer> p) {
    int total = 0;

    for (int number : numbers) {
        if (p.test(number)) {
            total += number;
        }
    }
    return total;
}

Calling it like:

像这样称呼它:

sumAll(numbers, n -> n % 2 == 0);

Source: DZone - Why We Need Lambda Expressions in Java

来源:DZone - 为什么我们需要 Java 中的 Lambda 表达式

回答by holi-java

There are many benefits of using lambdas instead of inner class following as below:

使用 lambdas 而不是内部类有很多好处,如下所示:

  • Make the code more compactly and expressive without introducing more language syntax semantics. you already gave an example in your question.

  • By using lambdas you are happy to programming with functional-style operations on streams of elements, such as map-reduce transformations on collections. see java.util.function& java.util.streampackages documentation.

  • There is no physical classes file generated for lambdas by compiler. Thus, it makes your delivered applications smaller. How Memory assigns to lambda?

  • The compiler will optimize lambda creation if the lambda doesn't access variables out of its scope, which means the lambda instance only create once by the JVM. for more details you can see @Holger's answer of the question Is method reference caching a good idea in Java 8? .

  • Lambdas can implements multi marker interfaces besides the functional interface, but the anonymous inner classes can't implements more interfaces, for example:

    //                 v--- create the lambda locally.
    Consumer<Integer> action = (Consumer<Integer> & Serializable) it -> {/*TODO*/};
    
  • 在不引入更多语言语法语义的情况下,使代码更加紧凑和富有表现力。你已经在你的问题中给出了一个例子。

  • 通过使用 lambda,您很高兴在元素流上使用函数式操作进行编程,例如集合上的 map-reduce 转换。请参阅java.util.functionjava.util.stream包文档。

  • 编译器没有为 lambda 生成物理类文件。因此,它使您交付的应用程序更小。内存如何分配给 lambda?

  • 如果 lambda 不访问其范围之外的变量,编译器将优化 lambda 创建,这意味着 lambda 实例仅由 JVM 创建一次。有关更多详细信息,您可以查看@Holger 对问题的回答Is method reference caching a good idea in Java 8? .

  • Lambdas 可以实现功能接口之外的多标记接口,但是匿名内部类不能实现更多的接口,例如:

    //                 v--- create the lambda locally.
    Consumer<Integer> action = (Consumer<Integer> & Serializable) it -> {/*TODO*/};
    

回答by Carlos

One thing I don't see mentioned yet is that a lambda lets you define functionality where it's used.

我还没有看到提到的一件事是 lambda允许您在使用它的地方定义功能

So if you have some simple selection function you don't need to put it in a separate place with a bunch of boilerplate, you just write a lambda that's concise and locally relevant.

所以如果你有一些简单的选择函数,你不需要把它和一堆样板放在一个单独的地方,你只需编写一个简洁的和本地相关的 lambda。

回答by Ousmane D.

To answer your question, the matter of fact is lambdas don'tlet you do anything that you couldn't do prior to java-8, rather it enables you to write more concisecode. The benefits of this, is that your code will be clearer and more flexible.

为了回答你的问题,事实上 lambdas不允许你做任何你在 java-8 之前不能做的事情,而是它使你能够编写更简洁的代码。这样做的好处是,您的代码将更清晰、更灵活。

回答by Sweeper

Lambdas are just syntactic sugar for anonymous classes.

Lambda 只是匿名类的语法糖。

Before lambdas, anonymous classes can be used to achieve the same thing. Every lambda expression can be converted to an anonymous class.

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

If you are using IntelliJ IDEA, it can do the conversion for you:

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

  • Put the cursor in the lambda
  • Press alt/option + enter
  • 将光标放在 lambda 中
  • 按 alt/option + enter

enter image description here

在此处输入图片说明

回答by Sunil Kanzar

Yes many advantages are there.

是的,有很多优点。

  • No need to define whole class we can pass implementation of function it self as reference.
    • Internally creation of class will create .class file while if you use lambda then class creation is avoided by compiler because in lambda you are passing function implementation instead of class.
  • Code re-usability is higher then before
  • And as you said code is shorter then normal implementation.
  • 无需定义整个类,我们可以将其自身的函数实现作为参考传递。
    • 在内部创建类将创建 .class 文件,而如果您使用 lambda,则编译器会避免创建类,因为在 lambda 中您传递的是函数实现而不是类。
  • 代码重用性比以前更高
  • 正如您所说,代码比正常实现要短。