函数式接口,lambda表达式,方法引用

文章目录

    • 函数式接口
      • 常见函数式接口对比
      • Function
        • 方法说明
        • 使用示例
      • Consumer
        • 方法说明
        • 使用示例
      • Supplier
        • 方法说明
        • 使用示例
      • Predicate
        • 方法说明
        • 使用示例
    • lambda
        • 常见的lambda表达式
    • 方法引用
      • 使用示例

函数式接口是指只拥有一个抽象函数。带有@FunctionalInterface标注的接口,编译时就需要完全符合函数式接口的定义。与函数式接口密切相连的便是lambda表达式。

函数式接口

1.只拥有一个抽象方法。
2.接口可以含有default-method。即使用default修饰的方法,该方法是具有方法体的。
3.接口还可以含有static方法。

在jdk里面的function包中,就含有许多函数式接口,接下来就介绍一些常用的接口。

常见函数式接口对比

接口 说明 常用方法
Function 传入一个参数,返回一个值 apply,andThen,compose,identity
Consumer< T > 消费一个参数 accept,andThen
Supplier< T> 返回一个值 get
Predicate 传入一个参数,返回一个布尔值 test,negate,and,or,isEqual
BiFunction 传入两个参数,返回一个值 apply,andThen
BiConsumer 消费两个参数 accept,andThen
BiPredicate 断言两个参数,返回一个布尔值 test,negate,and,or
BinaryOperator< T> 对相同类型的参数进行比较,继承于BiFunction apply,andThen,minBy,maxBy
UnaryOperator< T> 返回输入值,继承于Function identity
BooleanSupplier 返回布尔值 getAsBoolean

Function

方法说明

方法名 说明
R apply(T t) 传入具体参数,执行方法体,返回结果
Function andThen(Function after) 传入function,执行完方法体后再执行传入的function
Function compose(Function before) 传入function,先执行传入的function,再执行方法体
Function identity() 【静态方法】返回一个 返回值和传入参数一致的函数

使用示例

Function<Integer, Integer> function1 = (input) -> input * 2;
Function<Integer, Integer> function2 = (input) -> input + 10;
Function<Integer, Integer> function3 = Function.identity();

// 2
System.out.println(function1.apply(1));
// 11
System.out.println(function2.apply(1));
// 1
System.out.println(function3.apply(1));

// 12
System.out.println(function1.andThen(function2).apply(1));
// 2
System.out.println(function1.andThen(function3).apply(1));

// 22
System.out.println(function1.compose(function2).apply(1));
// 2
System.out.println(function1.compose(function3).apply(1));

Consumer

方法说明

注意:consumer是可以对接具有返回值的方法。

方法名 说明
apply 传入具体参数,执行方法体,返回结果
andThen 传入function,执行完方法体后再执行传入的function
compose 传入function,先执行传入的function,再执行方法体
identity 【静态方法】返回一个 返回值和传入参数一致的函数

使用示例

Consumer<Integer> consumer1 = (input) -> System.out.println("Comsumer1:" + input);
Consumer<Integer> consumer2 = (input) -> System.out.println("Comsumer2:" + input);

// Comsumer1:1
consumer1.accept(1);
// Comsumer1:1
// Comsumer2:1
consumer1.andThen(consumer2).accept(1);

Supplier

方法说明

方法名 说明
T get() 执行方法体,获取返回结果

使用示例

Supplier<Integer> supplier1 = () -> 100;
Supplier<Integer> supplier2 = () -> 2 * 10 + 40;

// 100
System.out.println(supplier1.get());
// 60
System.out.println(supplier2.get());

Predicate

方法说明

方法名 说明
boolean test(T t) 断言t,返回一个布尔值
Predicate and(Predicate other) 与逻辑
Predicate negate() 返回test相反值
Predicate or(Predicate other) 或逻辑
Predicate isEqual(Object targetRef) 【静态方法】判断是否equal

使用示例

Predicate<Integer> predicate1 = (input) -> input > 0;
Predicate<Integer> predicate2 = (input) -> input < 0;

// true
System.out.println(predicate1.test(1));
// false
System.out.println(predicate1.negate().test(1));
// false
System.out.println(predicate1.and(predicate2).test(1));
// true
System.out.println(predicate1.or(predicate2).test(1));
// true
System.out.println(Predicate.isEqual(1).test(1));

在function包内部出了上述介绍的接口,还有针对int,long,double的相应接口,用法都大致相仿,就不在此赘述。

lambda

大家都知道匿名类一定意义上简化了代码,而lambda表达式其实在一定程度上起到了再次简化代码的作用。在上节函数式接口的使用示例中,我都是直接使用最简单的lambda表达式来演示,可见一个方法体只需要用一行代码即可描述的简便性。

常见的lambda表达式

// 无参数
()-> {
     1};
// 无参数,一行代码的方法体可直接省略花括号
()-> 1;
// 明确一个参数类型,且返回其二倍数
(int nput)-> input*2;
// 可以不明确参数类型
(input)-> input;
// 输入两个参数
(input1, input2) -> input1 + input2;
// 输入两个参数
(int input1, int input2) -> input1 + input2;

看见上面常见的lambda表达式,我们可以发现有些时候lambda表达式需要定义参数类型,而有些时候却不需要,这是为啥?
因为编译器会根据上下文环境对lambda表达式进行参数推导,所以有时候我们直接写一个lambda表达式时,可以根据该表达式所在环境适当省略类型声明,比如我们上节函数式接口的使用示例中,前方明确了参数类型,返回值类型就可以省略后续lambda表达式的类型声明。

方法引用

当我们想再对lambda表达式进行简化时,或者说,只要方法体是调用一个已经存在的方法,不对现有方法进行改写,就可以使用方法引用了。

类型 使用说明
静态方法 类名::方法名
构造方法 类名::new
实例方法 类名::方法名 或者 实例::方法名

使用示例

// 静态方法引用
List<String> list = Arrays.asList("aa", "bb", "cc");
List<String> valueList = list.stream().map(String::valueOf).collect(Collectors.toList());

// 含参构造方法引用
Function<String, String> function = String::new;

// 实例方法引用
valueList.forEach(System.out::println);

注意:
针对下面这种方法,我们有两种方法引用的写法

default void follow(final Car another) {
     
        System.out.println("Following the " + another.toString());
    }
final Car car = new Car() {
     
};
// 第一种 
Consumer<Car> c3 = car::follow;
c3.accept(car);
// 第二种
BiConsumer<Car,Car> c4 = Car::follow;
c4.accept(car,car);

因为follow是实例方法,所以使用第一种方式时,会默认调用car的follow方法,传入的参数默认是调用的实例;使用第二种时,由于是要通过类名引用,则需要传入实例,并且要指明参数是谁,所以要传入两个值。

你可能感兴趣的:(java,lambda,java,接口)