Java8 新特性:Lambda表达式
2023-05-28

Lambda表达式

Lamdba表达式时Java 1.8 的新特性。

是一个匿名函数,作为函数式接口的实例。

举例

// 原来接口的匿名实现类写法
Comparator<Integer> comparator = new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o1.compareTo(o2);
			}
		};
//Lambda表达式写法
Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);

语法

(形参列表) -> 单条语句
或
(形参列表) ->{ 方法体; };

-> Lambda操作符

->左边 Lambda形参列表,使用圆括号包裹(接口中抽象方法的形参)

  • 可选类型声明: 参数类型可以省略(类型推断)

    (Integer o1,Integer o2) -> { return o1.compareTo(o2); }; 
    // 参数类型时可选的 (o1,o2)
    Comparator<Integer> com2 = (o1,o2) -> { return o1.compareTo(o2); }; 
    
  • 可选的参数圆括号: 只有一个参数是可以不写圆括号,零个或多个时必须写

    // 1.一个参数不省略大括号
    (s) -> System.out.println(s);
    // 2.只有一个参数可以省略圆括号
    s -> System.out.println(s);
    // 3.没有参数或多个时不可以省略
    () -> System.out.println("hello");
    

->右边 Lambda体 ,大括号包裹,最后需要分号(重写的抽象方法的方法体)

  • 可选的大括号: 如果只有一条语句,可以省略大括号

    // 1. 一条语句时不省略大括号
    s -> { System.out.println(s); };
    // 2. 只有一条语句时可以省略大括号
    s -> System.out.println(s);
    //3. 有多条语句时不可以省略
    s -> {
        System.out.println("hello");
        System.out.println(s);
    };
    
  • 可选的返回关键字: 如果省略了大括号,则需要去掉 return关键字

    // 1. 不省略大括号
    (a,b) -> { return a+b; };
    // 2. 省略大括号,需要去掉return 否则会报错
    (a,b) -> a+b;
    

==本质上Lambda作为函数式接口的实例==

只包含一个抽象方法的接口叫函数式接口

可以在接口上使用FunctionalInterface注解,来检查它是否是一个函数式接口

所以可以将lambda表达式作为参数给方法

Arrays.sort(list, (String s1, String s2) -> (s1.compareTo(s2))); // 相当于
Comparator<String> sortByName = (String s1, String s2) -> (s1.compareTo(s2));  
Arrays.sort(list, sortByName);  

变量作用域

1)可以在lambda表达式中访问外层的局部变量

只能访问 声明为final 的变量,但是可以不用显式声明,会隐性的具有 final 的语义

// num
int num = 1;
Converter<Integer, String> s =
        (param) -> String.valueOf(param + num);

不过这里的局部变量 num必须不可被后面的代码修改(即隐性的具有final的语义)。

int num = 1;  
Converter<Integer, String> s = (param) -> String.valueOf(param + num));
s.convert(2);
num = 5;  
//报错信息:Local variable num defined in an enclosing scope must be final or effectively 

==在Lambda表达式中试图修改局部变量是不允许的==

2) Lambda 表达式当中不允许声明一个与外部局部变量同名的参数或者局部变量。

// 局部变量
int a;
Comparator<Integer> com3 = (o1,o2) -> {
			int a = 9;
			return a;
		};
java: 已在方法 test2()中定义了变量 a
    
// 参数
int a;
Comparator<Integer> com3 = (a,o2) -> o2;
java: 已在方法 test2()中定义了变量 a    

this的区别

在lambda中 this 表示外部类

我们分别使用匿名内部类和lambda的方式,输出一下他的this

// lambda 表达式
Comparator<Integer> com1 = (o1,o2) -> {
		System.out.println("lambda:"+thisgetClass());
		return o1.compareTo(o2);
		};
// 匿名内部类
Comparator<Integer> com2 = new Comparator<Integer>() {
    @Override
   public int compare(Integer o1, Integer o2) {
        System.out.println("匿名内部类:"+thisgetClass());
        return o1.compareTo(o2);
    }
};
// 调用
com1.compare(1,2);
com2.compare(1,2);

结果:

lambda:class com.xxxx.LambdaDemo
匿名内部类:class com.xxxx.LambdaDemo$1

可以看到 lambda 表达式的输出的是 LambdaDemo,匿名内部类的输出中 有一个 $1 这个表示LambdaDemo类中的匿名类