Lambda表达式

Posted huzidashu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lambda表达式相关的知识,希望对你有一定的参考价值。

技术图片

Lambda表达式

Java lambda表达式是Java 8附带的一个非常令人兴奋的新功能。对于我们使用scala之类的高级语言工作的人来说,它们并不陌生。

事实上,如果你回顾一下过去20年的历史,试图找出Java语言的任何改进,你将无法回忆起许多令人兴奋的事情。在过去的十年中,Java中只有少数并发类、泛型以及注释(如果您同意的话)。lambda的表达打破了这场干旱,感觉像是一个愉快的礼物。

技术图片

在这篇文章中,我将分三部分介绍lambda表达式及其相关的概念。下面是我们进行的计划。

目录
1. Java中的lambda表达式是什么?
2. Java 8功能接口 
3. Lambda表达式示例

让我们坚持计划并逐步进行。

1. Java中的lambda表达式是什么?

在编程中,Lambda表达式(或函数)只是一个匿名函数,即不带名称且不受标识符限制的函数

换句话说,lambda表达式是作为常量值给出的无名函数,并精确地写在需要的地方,通常作为其他函数的参数

Lambda表达式最重要的特性是它们在出现的上下文中执行。因此,相似的lambda表达式可以在其他上下文中以不同的方式执行(即逻辑相同,但基于传递给函数的不同参数,结果将有所不同)。

上面的定义充满了关键字,只有当您已经深入了解什么是lambda表达式时才能理解。因此,一旦您对下一部分中的lambda表达式有了更好的了解,我建议您重新阅读以上段落。

因此,很明显lambda是某种没有名称和标识符的函数。好吧,有什么大不了的?为什么每个人都这么兴奋?

答案在于函数式编程相对于面向对象编程(OOP)的好处。大多数OOP语言都是围绕对象和实例发展的,并且只把它们当作自己的第一类公民。另一个重要的实体即功能退居其次。尤其是在java中,函数不能存在于对象之外。在java中,函数本身没有任何意义,除非它与某个对象或实例相关。

但是在函数式编程中,您可以定义函数,为它们提供引用变量,并将它们作为方法参数传递等等。javascript就是一个很好的例子,你可以把回调方法传递给Ajax调用。它是一个非常有用的特性,但是java从一开始就缺乏它。现在有了java 8,我们还可以使用这些lambda表达式。

1.1 Lambda语法

典型的lambda表达式语法如下所示:

(x, y) -> x + y  //This function takes two parameters
                    //and return their sum.

现在基于x和y的类型,可以在多个地方使用方法。参数可以匹配int或Integer或简单地字符串匹配。根据上下文,它将添加两个整数或连接两个字符串。

lambda表达式的其他可能的语法是:

either
 
(parameters) -> expression           //1
 
or
 
(parameters) -> { statements; }  //2
 
or
 
() -> expression                     //3

1.2 Lambda示例

让我们也看一下lambda表达式的一些示例:

(int a, int b) ->    a * b               // takes two integers and returns their multiplication
 
(a, b)          ->   a - b               // takes two numbers and returns their difference
 
() -> 99                                // takes no values and returns 99
 
(String a) -> System.out.println(a)     // takes a string, prints its value to the console, and returns nothing
 
a -> 2 * a                               // takes a number and returns the result of doubling it
 
c -> { //some complex statements }   // takes a collection and do some procesing

1.3 Lambda表达式的功能

让我们确定lambda表达式的一些功能

  1. Lambda表达式可以具有零个,一个或多个参数。
  2. 参数的类型可以显式声明,也可以从上下文中推断出来。
  3. 多个参数用强制括号括起来,并用逗号分隔。空括号用于表示空参数集。
  4. 当有单个参数时,如果推断出其类型,则不强制使用括号。例如a->返回a * a。
  5. Lambda表达式的主体可以包含零个,一个或多个语句。
  6. 如果lambda表达式的主体具有单个语句,则不必使用大括号,并且匿名函数的返回类型与主体表达式的返回类型相同。如果正文中有多个语句,则这些语句必须用大括号括起来。

所以,我们对lambda表达式有了一个简短的概述。如果您感到困惑,不知道如何在java编程语言中使用它,请耐心等待。我们会在30分钟内把所有的东西都准备好。我们开始吧。

在深入研究lambda表达式和java编程之间的关系之前,您还必须了解函数接口。这太重要了。

2. Java 8功能接口

单一抽象方法接口(SAM接口)不是一个新概念。它意味着接口只有一个方法。在java中,我们已经有很多这样的SAM接口的例子。从java 8开始,它们也将被称为功能接口。Java 8,通过用一个新的注释(即@FunctionalInterface)来标记这些接口,从而强化了单一职责规则。

例如,Runnable接口的新定义是这样的:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

如果试图在任何函数接口中添加新方法,编译器将不允许您这样做,并将抛出编译时错误。

到目前为止一切顺利。但是,它们是如何与Lambda表达式相关的呢?让我们找出答案。

我们知道Lambda表达式是匿名函数,没有名称,它们(大多数情况下)作为参数传递给其他函数。在java方法中,参数总是有一个类型,查找这个类型信息是为了确定在方法重载或者简单的方法调用时需要调用哪个方法。因此,基本上每个lambda表达式也必须可转换为某种类型才能被接受为方法参数。在lambda表达式转换的类型中,总是函数接口类型。

让我们用一个例子来理解它。如果我们必须写一个线程将打印“howtodoinjava”在控制台,那么最简单的代码将是:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("howtodoinjava");
    }
}).start();

如果我们使用lambda表达式执行此任务,则代码将为:

new Thread(
            () ->   {
                        System.out.println("My Runnable");
                    }
         ).start();

我们还看到,Runnable是一个具有单个方法run()的函数接口。因此,当您将lambda表达式传递给Thread类的构造函数时,编译器将尝试将该表达式转换为等效的可运行代码,如第一个代码示例所示。如果编译器成功,那么一切运行良好,如果编译器不能将表达式转换为等效的实现代码,它将会报错。在上面的例子中,lambda表达式被转换为Runnable类型。

简单来说,lambda表达式是函数接口的实例。但是lambda表达式本身并不包含它正在实现的功能接口的信息;这些信息是从使用它的环境中推断出来的。

3. Java 8 lambda表达式示例

我列出了一些代码示例,您可以阅读并分析如何在日常编程中使用lambda表达式。

1)遍历一个List并执行一些操作

List<String> pointList = new ArrayList();
pointList.add("1");
pointList.add("2");
 
pointList.forEach(p ->  {
                            System.out.println(p);
                            //Do more work
                        }
                 );

2)创建一个新的可运行对象并将其传递给线程

new Thread(
    () -> System.out.println("My Runnable");
).start();

3)按员工对象的名称对其进行排序

public class LambdaIntroduction {
 
  public static void main (String[] ar){
          Employee[] employees  = {
              new Employee("David"),
              new Employee("Naveen"),
              new Employee("Alex"),
              new Employee("Richard")};
            
          System.out.println("Before Sorting Names: "+Arrays.toString(employees));
          Arrays.sort(employees, Employee::nameCompare);
          System.out.println("After Sorting Names "+Arrays.toString(employees));
      }
}
  
class Employee {
  String name;
  
  Employee(String name) {
    this.name = name;
  }
  
  public static int nameCompare(Employee a1, Employee a2) {
    return a1.name.compareTo(a2.name);
  }
    
  public String toString() {
    return name;
  }
}
 
Output:
 
Before Sorting Names: [David, Naveen, Alex, Richard]
After Sorting Names [Alex, David, Naveen, Richard]

4)将事件侦听器添加到GUI组件

JButton button =  new JButton("Submit");
button.addActionListener((e) -> {
    System.out.println("Click event triggered !!");
});          

上面是Java 8中lambda表达式的非常基本的示例。我将不时提出一些更有用的示例和代码示例。

学习愉快!

以上是关于Lambda表达式的主要内容,如果未能解决你的问题,请参考以下文章

JAVA由一个将JSONArray转成Map的需求引发的lambda语法的学习

函数式编程

C# fun

Lambda表达式

Lambda表达式

Lambda表达式