函数式接口
概述
函数式接口在Java中是指:有且仅有一个抽象方法的接口。
函数式接口的实现可以由Lambda表达式、方法引用、构造器引用等方式实现。
前言
其实在1.8版本之前就已经出现了函数式接口了,例如:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.security.PrivilegedAction
- java.util.Comparator
- java.io.FileFilter
- java.nio.file.PathMatcher
- java.lang.reflect.InvocationHandler
- java.beans.PropertyChangeListener
- java.awt.event.ActionListener
- javax.swing.event.ChangeListener
@FunctionalInterface注解
为了对我们所编写的函数式接口进行校验,在Java8版本中引入了@FunctionalInterface,用来检验我们所编写的接口是否有且只有一个抽象方法,我们来看一个小栗子:
@FunctionalInterface
public interface MyFunctionalInterface(){
void method();
}
我们写好了我们的接口那么下面我们来使用它吧
public class TestMyFunctionalInterface {
public static void main(String[] args) {
doSomething(()-> System.out.println("我被执行啦"));
}
private static void doSomething(MyFunctionalInterface inter){
inter.method();
}
}
如果我们在其中在增加一个抽象方法,那么我们的idea就会友善的给你进行飘红,当容你也不能没有抽象方法,必须是要有一个的。
那么就可能有小伙伴们有疑问了,Comparator<T>
接口里面就有两个抽象方法呀,不信你看
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
让我们来看看官方文档怎么说的:
\qquad
If an interface declares an abstract method overriding one of the public methods of {@code java.lang.Object}, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation from {@code java.lang.Object} or elsewhere.
翻译过来就是:
如果接口中声明的抽象方法覆盖了java.lang.Object的公共方法,则该方法不会计入接口的抽象方法计数,因为该接口的任何实现都将具有java.lang.Object或其他地方的实现。
接口分类
在java.util.function包下面增加了很多函数式接口,一共有43种大体上可以被分为4种供给型、消费型、功能型、判断型
供给型接口
特点
无参,有返回值
接口
接口名 | 抽象方法 | 描述 |
---|---|---|
Supplier | T get() | 返回一个对象 |
BooleanSupplier | boolean getAsBoolean() | 返回一个boolean值 |
DoubleSupplier | double getAsDouble() | 返回一个double值 |
IntSupplier | int getAsInt() | 返回一个int值 |
LongSupplier | long getAsLong() | 返回一个long值 |
代表 - Supplier接口
java.util.function.Supplier<T>
对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据, 我们来看一个小栗子:
public class TestSupplier {
public static void main(String[] args) {
String strA = "Hello ";
String strB = "World";
String result = getString(() -> strA + strB);
System.out.println(result);
}
static String getString(Supplier<String> supplier) {
return supplier.get();
}
}
消费型接口
特点
有参、无返回值
接口
接口名 | 抽象方法 | 描述 |
---|---|---|
Consumer | void accept(T t) | 接收一个对象用于完成功能 |
BiConsumer<T,U> | void accept(T t, U u) | 接收两个对象用于完成功能 |
DoubleConsumer | void accept(double value) | 接收一个double值 |
IntConsumer | void accept(int value) | 接收一个int值 |
LongConsumer | void accept(long value) | 接收一个long值 |
ObjDoubleConsumer | void accept(T t, double value) | 接收一个对象和一个double值 |
ObjIntConsumer | void accept(T t, int value) | 接收一个对象和一个int值 |
ObjLongConsumer | void accept(T t, long value) | 接收一个对象和一个long值 |
代表 - Consumer接口
java.util.function.Consumer<T>
接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定。我们来看个小栗子
public class TestConsumer {
public static void main(String[] args) {
consume(System.out::println);
}
public static void consume(Consumer<String> function){
function.accept("Hello");
}
}
默认方法 - andThen
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作, 然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 。下面是JDK的源代码:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
我们来看一个小栗子
public class TestConsumer2 {
public static void main(String[] args) {
consume(c1 -> System.out.println(c1.toLowerCase()),
c2 -> System.out.println(c2.toUpperCase()));
}
public static void consume(Consumer<String> c1, Consumer<String> c2){
c1.andThen(c2).accept("Hello");
}
}
判断型接口
特点
有参、返回值类型是boolean
接口
接口名 | 抽象方法 | 描述 |
---|---|---|
Predicate | boolean test(T t) | 接收一个对象 |
BiPredicate<T,U> | boolean test(T t, U u) | 接收两个对象 |
DoublePredicate | boolean test(double value) | 接收一个double值 |
IntPredicate | boolean test(int value) | 接收一个int值 |
LongPredicate | boolean test(long value) | 接收一个long值 |
代表 - Predicate
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用 java.util.function.Predicate<T>
接口,我们看一个简单的小栗子
public class TestPredicate {
public static void main(String[] args) {
Boolean predicate = predicate(String::isEmpty);
System.out.println("字符串是否为空:" + predicate);
}
private static Boolean predicate(Predicate<String> p){
return p.test("");
}
}
默认方法 - and
其中将两个 Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法 and 。其JDK源码为:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
默认方法 - negate
实现“非”(取反)非常简单。默认方法 negate 的JDK源代码为:
default Predicate<T> negate() {
return (t) -> !test(t);
}
默认方法 - or
与 and 的“与”类似,默认方法 or 实现逻辑关系中的“或”。JDK源码为:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
功能型接口
特点
有参数、有返回值
接口
接口名 | 抽象方法 | 描述 |
---|---|---|
Function<T,R> | R apply(T t) | 接收一个T类型对象,返回一个R类型对象结果 |
UnaryOperator | T apply(T t) | 接收一个T类型对象,返回一个T类型对象结果 |
DoubleFunction | R apply(double value) | 接收一个double值,返回一个R类型对象 |
IntFunction | R apply(int value) | 接收一个int值,返回一个R类型对象 |
LongFunction | R apply(long value) | 接收一个long值,返回一个R类型对象 |
ToDoubleFunction | double applyAsDouble(T value) | 接收一个T类型对象,返回一个double |
ToIntFunction | int applyAsInt(T value) | 接收一个T类型对象,返回一个int值 |
ToLongFunction | long applyAsLong(T value) | 接收一个T类型对象,返回一个long值 |
DoubleToIntFunction | int applyAsInt(double value) | 接收一个double值,返回一个int值 |
DoubleToLongFunction | long applyAsLong(double value) | 接收一个double值,返回一个long值 |
IntToDoubleFunction | double applyAsDouble(int value) | 接收一个int值,返回一个double值 |
IntToLongFunction | long applyAsLong(int value) | 接收一个int值,返回一个long值 |
LongToDoubleFunction | double applyAsDouble(long value) | 接收一个long值,返回一个double值 |
LongToIntFunction | int applyAsInt(long value) | 接收一个long值,返回一个int值 |
DoubleUnaryOperator | double applyAsDouble(double operand) | 接收一个double值,返回一个double值 |
IntUnaryOperator | int applyAsInt(int operand) | 接收一个int值,返回一个int值 |
LongUnaryOperator | long applyAsLong(long operand) | 接收一个long值,返回一个long值 |
BiFunction<T,U,R> | R apply(T t, U u) | 接收一个T类型和一个U类型对象,返回一个R类型对象 |
BinaryOperator | T apply(T t, T u) | 接收两个T类型对象,返回一个T类型对象 |
ToDoubleBiFunction<T,U> | double applyAsDouble(T t, U u) | 接收一个T类型和一个U类型对象,返回一个double值 |
ToIntBiFunction<T,U> | int applyAsInt(T t, U u) | 接收一个T类型和一个U类型对象,返回一个int值 |
ToLongBiFunction<T,U> | long applyAsLong(T t, U u) | 接收一个T类型和一个U类型对象,返回一个long值 |
DoubleBinaryOperator | double applyAsDouble(double left, double right) | 接收两个double值,返回一个double值 |
IntBinaryOperator | int applyAsInt(int left, int right) | 接收两个int值,返回一个int值 |
LongBinaryOperator | long applyAsLong(long left, long right) | 接收两个long值,返回一个long值 |
代表 - Function
java.util.function.Function<T,R>
接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件, 后者称为后置条件。我们来看一个小栗子:
public class TestFunction {
public static void main(String[] args) {
Integer function = function(Integer::valueOf);
System.out.println(function + 3);
}
public static Integer function(Function<String, Integer> f){
return f.apply("123");
}
}
默认方法 - compose
compose方法接收一个Function类型的参数,先用传入的Function对象执行对应的apply方法,然后使用当前的Function对象的执行对应的apply方法
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
默认方法 - andThen
Function 接口中有一个默认的 andThen 方法,用来进行组合操作。JDK源代码如:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}