简介

Lambda 表达式是 Java 1.8 跟 Stream 机制一起推出的。Lambda 表达式极大地缩小了代码量,减少了代码的可读性。
引入 Lambda 表达式之后,Java 开始反对把函数作为参数传递

前置条件

应用 Lambda 表达式的前置条件,作为参数的接口必须是函数式接口

  1. 首先类型必须是接口 interface,不能是类 class。比方,抽象类就不能够。
  2. 函数式接口有且仅有一个未被覆写的形象办法

举例:

  • Object 中办法不算
// MyRunnable 依然算是一个“函数式接口”public interface MyRunnable extends Runnable {    String toString();    boolean equals(Object obj);    int hashCode();} 
  • 接口中的 default 办法不算
// MyRunnable2 依然算是一个“函数式接口”public interface MyRunnable2 extends Runnable {    default void run2() {}} 

FunctionalInterface 注解

@FunctionalInterface 能够帮忙咱们在编译期辨认出一个接口是否是“函数式接口”:

参数的传递

如果咱们有一个如下含意的“函数式接口”:

@FunctionalInterfacepublic interface Formatter {    void format(String name, int age);} 

咱们能够结构一个测试:

public class LambdaTest {    public static void main(String[] args) {        print((String name, int age)-> System.out.println(String.format("name:%s age:%d", name, age)), "ziyu", 18);    }    public static void print(Formatter formatter, String name, int age) {        formatter.format(name, age);    }} 

多个参数

当有多个参数时,能够抉择省略所有参数类型申明:

留神:
不能省略一部分保留一部分。(String name, age) -> System.out.println(name); 这是不非法的!

单个参数


当只有一个参数时,除了能够省略参数类型,还能够进一步省略掉括号。

编写形式

没有返回值

Runnable 就是一个罕用的“函数式接口”,它的形象办法 run() “没有返回值”, 刚好适宜用于此处的演示。测试例子如下:

public class LambdaTest2 {    public static void main(String[] args) {        runIt(()->{            System.out.println("123");        });    }    static void runIt(Runnable runnable) {        new Thread(runnable).start();    }} 

  • 如果写成多行表达式,那么须要 {} 来示意代码块,且每一行代码完结时须要书写 ; 示意语句的完结。
  • 如果代码块中只有一条语句,那么能够通过省略 {}; 来简写为单行表达式

有返回值

咱们定义一个 IdFactory 接口来做演示:

public interface IdFactory {    String generateId();} 

咱们的示例代码如下:

import java.util.UUID;public class LambdaTest3 {    public static void main(String[] args) {        String name = getId(()-> UUID.randomUUID() + "");        System.out.println(name);    }    static String getId(IdFactory factory) {        return factory.generateId();    }} 

  • 如果写成多行表达式,除了须要 {} 来示意代码块,和每一行代码完结时须要书写 ; 示意语句的完结以外,还应该在须要返回值的办法用 return 来返回值。
  • 如果代码块中只有一条语句,那么能够通过省略 {}; 以及 return 来简写为单行表达式

办法援用

比方咱们要写一段代码,用来打印出残缺的加法表达式 a + b = c,并且要求依据 a 和 b 求出 c 作为函数返回值。
首先咱们定一个“计算器”接口:

public interface Calculator {    int compute(int a, int b);} 

接着咱们写一个测试用例:

public class LambdaTest3 {    public static void main(String[] args) {        int a = 10;        int b = 20;        // 这里不能用 (a, b), 那样的话会产生歧义,使得编译器报错        runIt((x, y)->{            System.out.print(x);            System.out.print(" + ");            System.out.print(y);            System.out.print(" = ");            System.out.println(x + y);            return x + y;        }, a, b);    }    static void runIt(Calculator calculator, int a, int b) {        calculator.compute(a, b);    }} 

静态方法援用

  • 在 LambdaTest2 中定一个静态方法 sum
  • 应用静态方法援用 LambdaTest2::sum
  • 这样在运行静态方法 runIt 中的第一行 calculator.compute(a, b) 时,ab 会通过静态方法援用传递给静态方法 sum

通过这种形式,即简化了参数的传递,也把“多行表达式”简化为了“单行表达式”

成员办法援用

  • new LambdaTest2()::sum: 先新建对象 LambdaTest2,并且通过该对象来应用成员变量援用
    小贴士:
    如果先申明变量 obj,再应用 obj::sum 也是非法的。
public static void main(String[] args) {    int a = 10;    int b = 20;    LambdaTest2 obj = new LambdaTest2();    runIt(obj::sum, a, b);} 

总结

  • Lambda表达式的前置条件:必须是“函数式接口”
  • 单个参数传递时,能够省略参数两端的括号。参数的类型能够一起省略。
  • 编写的形式次要包含单行表达式和多行表达式
  • 能够应用办法援用来把多行表达式写成单行表达式。办法援用又包含了静态方法援用和动静办法援用。