首页 Java 基础 - 函数式编程详解
文章
取消

Java 基础 - 函数式编程详解

1. 概述

1.1背景

在日常Java编码中,函数式编程使用的频率是非常高的,但是回想一下,自己虽然能很好的使用,但是却没能系统的了解过函数式编程,所以以下为最近学习的一个总结。

1.2 概念

函数式接口在Java中是指:有且仅有一个抽象方法的接口函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。

2. 函数式接口介绍&基本使用

2.1 格式

1
2
3
4
5
6
7
8
9
修饰符 interface 接口名称 {
    public abstract 返回值 方法名称(参数列表)
    // 其他方式 
}
// public abstract 可以不写 编译器自动加上
修饰符 interface 接口名称 {
       返回值 方法名称(参数列表)
    // 其他方式 
}

以最常用的Function为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

2.2 @FunctionalInterface注解

1
2
3
4
5
6
// 标明为函数式接口
@FunctionalInterface
public interface MyFunction {
    // 抽象方法
    void method();
}

一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。(该接口是一个标记接口)

2.3 自定义函数式接口使用

1
2
3
4
5
6
7
    public static void executeMyFunction(MyFunction function) {
        function.method();
    }

    public static void main(String[] args) {
        executeMyFunction(()-> System.out.println("Hello World"));
    }

2.4 Java自带函数式接口


常用函数式接口

  1. Supplier 你要作为一个供应者,自己生产数据
  2. Consumer 你要作为一个消费者,利用已经准备数据
  3. Function 输入一个或者两个不同或者相同的值转为另一个值
  4. Predicate 输入一个或者两个不同或者相同的值总是输出boolean
  5. UnaryOperator 输入一个值转换为相同值输出
  6. BinaryOperator 输入两个相同类型的值 转为相同类型的值输出

2.4 主要语法

  1. () -> 代表了 lambda的一个表达式
  2. 单行代码无需写return (无论函数式接口有没有返回值),花括号
  3. 多行代码必须写花括号,有返回值的一定要写返回值
  4. 单行代码且有参数的情况下可以不写 () 如 s->System.out.println(s)
  5. (T t)中的参数类型可写可不写

3. 常用函数式接口

3.1 Supplier接口(供应接口)

  • 接口名:java.util.function.Supplier
  • 抽象方法:接口仅包含一个无参的方法: T get()
  • 作用:用来获取一个泛型参数指定类型的对象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
  • 使用
    1
    2
    3
    4
    5
    6
    7
    
      private static String supplierFunction(Supplier<String> stringSupplier){
          return stringSupplier.get();
      }
    
      public static void main(String[] args) {
          System.out.println(supplierFunction(()->"Hello World"));
      }
    

    3.2 Consumer接口

  • 接口名:java.util.function.Consumer
  • 抽象方法:void accept(T t)
  • 作用:接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定

  • 默认方法:andThen
  • 作用:如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作,然后再做一个操作,实现组合
    1
    2
    3
    4
    5
    6
    7
    
      default Consumer<T> andThen(Consumer<? super T> after) {
          //1:  返回值为Consumer 那么需要 ()-> 表示函数式接口
      	//2:  accept(t);为生产一个数据供应给 (T t)中的t
      	//3:  after.accept(t);为利用这个t再次生成新的函数式接口 实现类始于builder的设计模式
          Objects.requireNonNull(after);
          return (T t) -> { accept(t); after.accept(t); };
      }
    

    3.3 Predicate接口

  • 接口名:java.util.function.Predicate
  • 抽象方法:_boolean _test(T t)
  • 作用:需要对某种类型的数据进行判断,从而得到一个boolean值结果

  • 默认方法:
    • Predicate and(Predicate<? _super _T> other)
    • _default _Predicate or(Predicate<? _super _T> other)
    • _default _Predicate negate() (取反)
  • 作用:既然是条件判断,就会存在与、或、非三种常见的逻辑关系。

  • 静态方法:_static _ Predicate isEqual(Object targetRef)
  • 作用:返回值为Predicate,返回一个是否与targetRef相等的函数表达式

3.4 Function接口

  • 接口名:java.util.function.Function<T, R>
  • 抽象方法:R apply(T t)
  • 作用:根据一个类型的数据得到另一个类型的数据

  • 默认方法:
    • _default _ Function<V, R> compose(Function<? _super _V, ? _extends _T> before)
    • _default _ Function<T, V> andThen(Function<? _super _R, ? _extends _V> after)
  • 作用:与另一个Function进行结合,一个方法为before,另一个为after
    1
    2
    3
    4
    5
    6
    7
    8
    
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
      Objects.requireNonNull(before);
      return (V v) -> apply(before.apply(v));
    }    
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
      Objects.requireNonNull(after);
      return (T t) -> after.apply(apply(t));
    }
    

参考

本文由作者按照 CC BY 4.0 进行授权