Functional 为 lambda 方法提供一个接口
函数式接口
Functional 的定义其实很简单:任何接口,如果只包含 唯一一个抽象方法,那么它就是一个 Functional Interface ,
函数式接口?这注解名字好。
为了让编译器帮助我们确保一个接口满足 Functional Interface 的要求(也就是说有且仅有一个抽象方法),Java8提供了@FunctionalInterface
注解。
先学习函数式接,才能理解学习 Lambda
表达式。
有什么用
白话:用来为函数式编程提供接口。
就是一个有且仅有
一个抽象方法,但是可以有多个非抽象方法
的接口。
函数式接口可以被隐式转换为 lambda 表达式。
简单示例
写一个最简单的例子做为入门参考,看不懂不要紧,这个只是一个例子。
声明一个无参的接口
声明一个无参函数式接口,为 lambda 提供一个接口。
在接口上添加@Functional
那么这个接口就是一个函数式接口
@FunctionalInterface
public interfaceMyFunctional {
public abstract void run ();
}
实现接口
自己实现一个Functional
接口,只需要 ()-> System.out.println("test")
进行实现。()->System.out.println("test")
就是一个lambda
实现。
这里主要关注Functional
接口,不需要关注lambda
。
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。
规则
- 函数式接口里允许定义默认方法,因为默认方法不是抽象方法,其有一个默认实现,所以是符合函数式接口的定义的
- 函数式接口里允许定义静态方法,因为静态方法不能是抽象方法,是一个已经实现了的方法,所以是符合函数式接口的定义的
- 函数式接口里允许定义Java.lang.Object里的public方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法);因为任何一个函数式接口的实现,默认都继承了Object类,包含了来自
java.lang.Object
里对这些抽象方法的实现; - 函数式接口里允许子接口继承多个父接口,但每个父接口中都只能存在一个抽象方,且必须的相同的抽象方法。
jdk 中的 lambda 实现示例
使用 Arrays 对数据进行排序。 Arrays 的 sort 方法,可以使用 lambda 的方法,这个方法是怎么实现的呢。 老套路:
- 定义 Functional 接口
- Functional 做为形参
- 有一个地方实现了这个Functional接口
- 调用
// 使用 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
接口的具体实现。
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
接口
@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");
}