Lambda01-Functional 函数式接口

2023-10-20 12:36:23 浏览数 (1)

Functional 为 lambda 方法提供一个接口

函数式接口

Functional 的定义其实很简单:任何接口,如果只包含 唯一一个抽象方法,那么它就是一个 Functional Interface , 函数式接口?这注解名字好。 为了让编译器帮助我们确保一个接口满足 Functional Interface 的要求(也就是说有且仅有一个抽象方法),Java8提供了@FunctionalInterface注解。

先学习函数式接,才能理解学习 Lambda 表达式。

有什么用

白话:用来为函数式编程提供接口。 就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 函数式接口可以被隐式转换为 lambda 表达式。

简单示例

写一个最简单的例子做为入门参考,看不懂不要紧,这个只是一个例子。

声明一个无参的接口

声明一个无参函数式接口,为 lambda 提供一个接口。 在接口上添加@Functional那么这个接口就是一个函数式接口

代码语言:javascript复制
@FunctionalInterface
public interfaceMyFunctional {
    public abstract void run ();
}

实现接口

自己实现一个Functional接口,只需要 ()-> System.out.println("test") 进行实现。()->System.out.println("test") 就是一个lambda实现。 这里主要关注Functional接口,不需要关注lambda

代码语言:javascript复制
public class Test {
  public static void main(String[] args) {
    //实现 lambda
    MyFunctional myFunctional = () -> System.out.println("test");
    //调用 Functional 接口来执行 lambda 实现
    System.out.println(myFunctional.run());
  }
}

使用规则

首先它是一个接口。然后这个接口里面只能有一个抽象方法。 这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。

规则

  1. 函数式接口里允许定义默认方法,因为默认方法不是抽象方法,其有一个默认实现,所以是符合函数式接口的定义的
  2. 函数式接口里允许定义静态方法,因为静态方法不能是抽象方法,是一个已经实现了的方法,所以是符合函数式接口的定义的
  3. 函数式接口里允许定义Java.lang.Object里的public方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法);因为任何一个函数式接口的实现,默认都继承了Object类,包含了来自java.lang.Object里对这些抽象方法的实现;
  4. 函数式接口里允许子接口继承多个父接口,但每个父接口中都只能存在一个抽象方,且必须的相同的抽象方法。

jdk 中的 lambda 实现示例

使用 Arrays 对数据进行排序。 Arrays 的 sort 方法,可以使用 lambda 的方法,这个方法是怎么实现的呢。 老套路:

  1. 定义 Functional 接口
  2. Functional 做为形参
  3. 有一个地方实现了这个Functional接口
  4. 调用
代码语言:javascript复制
// 使用 lambda expression 排序 players
Comparator<String> sortByName = (s1, s2) -> (s1.compareTo(s2));
Arrays.sort(players, sortByName);

//等价形式
Arrays.sort(players, (s1, s2)-> (s1.compareTo(s2)));

看看 sort 的具体实现,sort 是对 Comparator 接口的具体实现。

代码语言:javascript复制
public static <T> void sort(T[] a, Comparator<? super T> c) {
    if (c == null) {
        sort(a);
    } else {
        if (LegacyMergeSort.userRequested)
    legacyMergeSort(a, c);
        else
        TimSort.sort(a, 0, a.length, c, null, 0, 0);
    }
}

Comparator 接口

代码语言:javascript复制
@FunctionalInterface
public interface Comparator<T> {
...
}

默认方法 和 静态方法

默认方法是可以直接被 类名.方法名使用的。 lambda 的默认实现方法,可以直接写在接口当中,然后具体使用的时候引用即可。 封装的时候也可以直接引用。

代码语言:javascript复制
import java.util.Objects;
import java.util.function.Predicate;

@FunctionalInterface
public interface MyFunctional<T> {
    //只允许存在一个 public abstract 方法
     boolean test(T t);
    // 这个方法就是对上面  boolean test(T t);  的一个默认实现
    static <T> boolean getBoolean (T b) {
        System.out.println(b.toString());
        return true;
    }
    //由于使用了范形,入参就变得灵活
    default String testPrintString (String message) {
        System.out.println(message);        return message;
    }
    //使用范形方法
     default <T> boolean testPrint (T message) {
        System.out.println(message);        return true;
    }
        //允许存在默认方法
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }    //允许存在静态方法
    static <T> Predicate<T> isEqual(Object targetRef) {
       System.out.println("使用静态方法");
       return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);
    }
}
代码语言:javascript复制
public static void testStaticMethod() {
  //直接使用默认实现
  static <T > boolean getBoolean (T b)
  MyFunctional myFunctional = MyFunctional::getBoolean;
  myFunctional.test(new Date());
  myFunctional.testPrintString("test....");
  //使用具体类型,默认方法
  myFunctional.testPrint(new Date());
  //使用范形默认方法
  // 直接传入默认实现即可
  testDefault(MyFunctional::getBoolean);
  //使用静态方法
  MyFunctional.isEqual(new Date());
}

//封装 lambda 表达式
public static String testDefault(MyFunctional myFunctional) {
  return myFunctional.testPrintString("just test lambda");
}

0 人点赞