函数式编程之lambda表达式

什么是Lambda 表达式

// 不包含参数,用()表示没有参数
// 表达式主体只有一个语句,可以省略{}
        Runnable helloWord = () -> System.out.println("Hello World");

        // 表达式主体由多个语句组成,不能省略{}
        Runnable helloWords = () -> {
            System.out.println("Hello");
            System.out.println("Word");
            System.out.println("Word");
        };

        // 表达式中只有一个参数,可以省略()
        Consumer<String> infoConsumer = msg -> System.out.println("Hello " + msg);

        // 表达式由多个参数组成,不可省略()
        BinaryOperator<Integer> add1 = (Integer i ,Integer j) -> i + j;

        // 编译器会进行类型推断,在没有歧义情况下可以省略类型声明,但是不可省略()
        BinaryOperator<Integer> add2 = (i, j) -> i + j;

综上可见,一个 Lambda 表达式主要由三部分组成:

  1. 参数列表
  2. 箭头分隔符(->)
  3. 主体,单个表达式或语句块

我们在使用匿名内部类时有一些限制:引用方法中的变量时,需要将变量声明为 final,不能为其进行重新赋值,如下:

final String msg = "World";
        Runnable print = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello"  + msg);
            }
        };

在 Java8 中放松了这个限制,可以引用非 final 变量,但是该变量在既成事实上必须是 final 的,虽然无需将变量声明为 final,在 Lambda 表达式中,也无法用作非最终态变量,及只能给该变量赋值一次(与用 final 声明变量效果相同)。

Lambda之方法引用

Lambda 表达式一种常用方法便是直接调用其他方法,针对这种情况,Java8 提供了一个简写语法,及方法引用,用于重用已有方法。

凡是可以使用 Lambda 表达式的地方,都可以使用方法引用。

方法应用的标准语法为 ClassName::methodName,虽然这是一个方法,但不需要再后面加括号,因为这里并不直接调用该方法。

Function<User, String> f1 = user->user.getName();
    Function<User, String> f2 = User::getName;

    Supplier<User> s1 = ()->new User();
    Supplier<User> s2 = User::new;

    Function<Integer, User[]> sa1 = count -> new User[count];
    Function<Integer, User[]> sa2 = User[]::new;

方法引用主要分为如下几种类型:

  • 静态方法引用:className::methodName
  • 实例方法引用:instanceName::methodName
  • 超类实体方法引用:supper::mehtodName
  • 构造函数方法引用:className::new
  • 数组构造方法引用:ClassName[]::new

说白了Lambda 就是匿名内部类的简化写法