一、原理概要
lambda 表示式,可以作为某些匿名内部类的替代。主要目的是调用该内部类中的方法,而该方法的实现(重写)由 lambda表示式决定。
通常,我们可能不关心匿名内部类中的具体方法(被重写的方法),而只关心该方法是怎么被重写的(方法的实现)。因此,我们可以构造一个中间对象(通常是接口,比如 Funtion),该接口拥有一个需要该重写的方法(比如 Function 对应的方法是 apply)。
二、如何使用
在实际书写时,可以只写出(传递的参数)与{方法的实现},或者只标出实现过程的 调用者的和其方法名(使用冒号分隔)。
Function<Person, Integer> getAge = Person::getAge; // 传参数调用 getAge 方法 Integer age = getAge.apply(p);
注释:
1. 比如 Function<T,R>
,T
表示传入类型,R
表示返回类型。比如,表达式 person -> person.getAge();
,传入参数是 person
,返回值是 person.getAge()
,那么方法引用 Person::getAge
就对应着 Function<Person,Integer>
类型。
2. 使用双冒号的方式会返回这个对象,当你调用该对象中的 apply 方法时,就会调用你之前传进去的方法。
3. 这个过程类似一个函数的闭包。当你使用双冒号的方式,会把你的类和方法传入并生成一个 Function对象。该对象会在之后某个时间被调用,此时它会调用之前你传入这个对象中的方法。
4. 三种方式对比
// old way List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7); for (Integer n : list) { System.out.println(n); } // 使用 -> 的 Lambda 表达式 list.forEach(n -> System.out.println(n)); // 使用 :: 的 Lambda 表达式 list.forEach(System.out::println);
三、关于函数式接口
1. Java 8中允许接口实现方法, 而不是简单的声明。需要使用关键字 default
2. Java8 中的 函数式接口中除了定义抽象方法外还可以包含静态方法。
@FunctionalInterface interface FunctionalInterfaceWithStaticMethod { static int sum(int[] array) { return Arrays.stream(array).reduce((a, b) -> a+b).getAsInt(); } void apply(); }
注. @FunctionalInterface注解,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。
3.一般情况下函数式接口只会定义一个抽象方法,但是接口最终有确定的类实现, 而类的最终父类是Object。 因此函数式接口可以定义Object 中的public方法,protected 方法不行。
@FunctionalInterface public interface ObjectMethodFunctionalInterface { void count(int i); String toString(); //same to Object.toString int hashCode(); //same to Object.hashCode boolean equals(Object obj); //same to Object.equals }
4. util 包中的函数式接口
java.util.function
中定义了几组类型的函数式接口以及针对基本数据类型的子接口。
- Predicate -- 传入一个参数,返回一个bool结果, 方法为
boolean test(T t)
- Consumer -- 传入一个参数,无返回值,纯消费。 方法为
void accept(T t)
- Function<t,r> -- 传入一个参数,返回一个结果,方法为
R apply(T t)
- Supplier -- 无参数传入,返回一个结果,方法为
T get()
- UnaryOperator -- 一元操作符, 继承Function<t,t>,传入参数的类型和返回类型相同。
- BinaryOperator -- 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction
原文地址:https://www.cnblogs.com/lemos/p/9244651.html