什么是lambda表达式?lambda表达式详解

定义

lambda表达式是一个可以传递的代码块,可以在以后一次或多次执行,也就是它会延迟执行,等待某个时刻或者某个事件发生在执行。它类似于一个方法的实现。

语法

(String f, String s) -> f.length()-s.length();

以上就是一个lambda表达式,类似与方法,圆括号中定义参数,箭头后面的就是方法的具体实现。

  1. 如果lambda表达式的体(可以理解成方法体)包含多条语句则用{}括起来。
  2. lambda表达式中也可以使用return,但是如果表达式中有多个分支语句那么每个分支语句都必须要有return,否则不合法。
  3. 如果可以根据上下文推导出lambda表达式参数的类型,那么不需要指定参数类型。如下:可以推导出参数类型为String。
	Comparator<String> comp = (f,s) -> f.length()-s.length();
  1. 如果只有一个参数并且能推导出参数类型,则可以省略圆括号,如下。
	Comparator<String> comp = s -> System.out.println(s);
  1. lambda表达式不需要指定返回类型,因为其总是会有上下文推导得出。

函数式接口

  在真正了解lambda表达式前,我们需要先了解另外一个概念,它叫函数式接口。什么是函数接口呢?只有一个抽象方法的接口就是函数式接口,需要这种接口的对象时我们就可以给他提供一lambda表达式。
  这里需要注意一个点,接口类型的变量可以引用实现了该接口的类的对象,类似于父类类型的变量可以引用子类类型的对象(多态),接口类似于父类。那么当把lambda表达式赋给一个函数式接口的变量时,这个lambda表达式就会转化成为实现了该接口的对象,并且这个lambda表达式就是对这个函数式接口中唯一的抽象方法的实现。当我们用这个函数式接口的变量去调用这个唯一的抽象方法时(这时抽象方法已经被lambda表达式实现),执行的就是lambda表达式代码块。简单来讲lambda表达式就是对一个类实现了一个接口,然后把这个类的对象赋给接口变量,接口变量就可调用被实现的方法的这过程的简化,只是这里的接口必须是函数式接口。
  函数式接口类型的变量会接受一个实现了该接口的对象,而lambda表达式就可以转化为这样的一个对象,在这个对象上调用函数式接口中的唯一抽象方法执行的就是lambda表达式的体。
  lambda表达式能做的也只是转换为函数式接口。不能把lambda表达式赋给其他类型的变量,Object的变量也不可以,因为Object不是函数式接口。

  当我们使用lambda表达式时,要谨记表达式的用途,并给他建立一个特定的函数式接口,java.util.function包中包含了很多Java自带的通用的函数式接口,从这也可以理解函数式接口是用来传递lambda表达式的。

变量作用域

public void repeat(String s){
        ActionListener actionListener = e -> {
            System.out.println(s);
        };
 }

  可以看到上面的lambda表达式访问repeat方法中的局部变量(参数)s,但是有个问题我们需要考虑就是lambda表达式不是立即执行的,是在今后某个时刻或者某个事件发生后执行一次或多次,那就有可能repeat方法执行完了,lambda表达式还没有执行,当lambda表达式要执行了,这个时候局部变量s已经不再内存中了,这就会出错。所以在这里Java中对这种变量的访问增加一些限制。

  首先来了解下lambda表达式的构成,由三部分构成:

  1. 一个参数列表
  2. 一个代码块
  3. 自由变量的值,这是指不在参数以及代码块中定义的变量。

  以上的例子中变量s就是一个自由变量,lambda表达式的数据结构会存储这个自由变量的值,这个过程也称为捕获。lambda表达式在赋给一个函数式接口的变量时会被转化为包含一个方法的对象,该方法就是函数式接口中的唯一抽象方法,方法体就是lambda表达式代码块,那么这个自由变量就是这个对象的实例字段。

  有了lambda表达式对自由变量值的捕获后,就算这个变量在他自己的作用域中已经消失了,但是lambda表达式自己存储了一份,就不会出错。

注意

  lambda表达式中只能访问不在发生改变的变量,也就是事实最终变量,不一定要把这个变量声明为final,只要自己能确认不会再去改变它。这里的改变是既不能在lambda表达式中对其进行改变,也不能在lambda表达式外进行改变。

  lambda表达式与嵌套块有相同的作用域,同样适用命名冲突和遮蔽的规则。比如在lambda表达式中声明与局部变量同名的变量是不合法的。

你可能感兴趣的:(lambda,java)