一、Lambda

Java 8的最大变化是引入了Lambda(Lambda 是希腊字母 λ 的英文名称)表达式,也可称为闭包。

lambda 表达式的语法格式如下:

(parameters) -> expression

(parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

关于lambda表达式的变量作用域:

  • 局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
  • 不允许声明一个与局部变量同名的参数或者局部变量。

二、函数式接口

函数接口是只有一个抽象方法的接口,可以有多个默认方法以及静态方法,通过Lambda表达式可以创建该接口的对象,另外使用@FunctionalInterface注解修饰,编译器会检测该类是否只有一个抽象方法或接口。Runnable以及Comparator接口就是常见的函数式接口。

以下是一个定义函数式接口的例子:

@FunctionalInterface
public interface FunctionInterfaceDemo {
    String test();

//    String test2();

    default String test3() {
        return "test3";
    }

    static String test4() {
        return "test4";
    }
}

然后可以通过lambda表达式来实现接口:

public class FunctionInterfaceTest {

    public static void main(String[] args) {

        // 创建匿名函数
        FunctionInterfaceDemo functionInterfaceDemo1 = new FunctionInterfaceDemo() {
            @Override
            public String test() {
                return "hello ";
            }
        };
        System.out.println(functionInterfaceDemo1.test());

        // 使用lambda替代上面的写法,效果一样
        FunctionInterfaceDemo functionInterfaceDemo2 = () -> "hello";
        System.out.println(functionInterfaceDemo2.test());
    }
}

三、方法引用

函数式接口的实例可以通过 lambda 表达式、 方法引用、构造方法引用来创建。方法引用是 lambda 表达式的语法糖,任何用方法引用的地方都可由lambda表达式替换,但是并不是所有的lambda表达式都可以用方法引用来替换。

方法引用通过方法的名字来指向一个方法,方法引用使用一对冒号 :: 。

  • instanceName::methodName 对象::方法名

  • ClassName::staticMethodName 类名::静态方法

  • ClassName::MethodName 类名::普通方法

  • ClassName::new 类名::new 调用的构造器

以下是使用的例子:

public class MethodReferenceTest {

    public static void main(String[] args) {
        test1();
        test2();
        test3();
        test4();
        test5();
    }

    /**
     * 对象名::引用成员方法
     */
    static void test1() {
        LocalDateTime localDateTime = LocalDateTime.now();
        Supplier<String> supplier1 = () -> localDateTime.toString();
        System.out.println(supplier1.get());
        Supplier<String> supplier2 = localDateTime::toString;
        System.out.println(supplier2.get());
    }

    /**
     * 类名::引用静态方法
     */
    static void test2() {
        Supplier<LocalDateTime> supplier1 = () -> LocalDateTime.now();
        System.out.println(supplier1.get());
        Supplier<LocalDateTime> supplier2 = LocalDateTime::now;
        System.out.println(supplier2.get());
    }

    /**
     * 类名::引用实例方法
     */
    static void test3() {
        Function<String, Integer> function = (s) -> s.length();
        System.out.println(function.apply("1"));
        Function<String, Integer> function2 = String::length;
        System.out.println(function.apply("1"));
    }

    /**
     * 类名::new  引用类构造器
     */
    static void test4() {
        Function<String, String> function1 = (s) -> new String(s);
        System.out.println(function1.apply("321"));
        Function<String, String> function2 = String::new;
        System.out.println(function2.apply("321"));
    }

    /**
     * 数组::new  引用数组构造器
     */
    static void test5() {
        Function<Integer, String[]> function1 = (len) -> new String[len];
        System.out.println(function1.apply(2).length);
        Function<Integer, String[]> function2 = String[]::new;
        System.out.println(function2.apply(2).length);
    }
}