函数式接口是指只包含一个抽象方法的接口,除了这一个抽象方法外,它还可以有default方法和static方法。
下面这一个就是函数式接口的例子:
public interface A {
void say(String str);
}
可以使用匿名内部类实现该接口:
A a = new A() {
@Override
public void say(String str) {
System.out.println(str);
}
};
a.say("hello");
也可以使用lambda实现该接口,可以看到lambda的写法更简洁:
A a = (String str)-> System.out.println(str);
// A a = System.out::println; //还可以简写成方法引用的形式
a.say("hello");
上面的示例是先声明一个函数式接口,然后再实现它,那有没有更简单的方式呢?答案是有的,java内置了一些通用的函数式接口(在java.util.function
包下),常用的有Consumer、Function、Predicate、Supplier,比如上面的例子可以写成:
Consumer<String> a = System.out.println(str);
a.accept("hello");
下面来一一介绍这几个内置的函数式接口:
Consumer
Consumer代表接收一个参数、且没有返回值的操作,下面是Consumer接口的定义:
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
可以看到,Consumer接口有一个accept抽象方法需要我们实现。下面的示例就是接收一个String类型的参数,然后在控制台打印该字符串(无返回值)
Consumer<String> a = (String str)-> System.out.println(str);
a.accept("hello");
那还有一个andThen默认函数是干啥用的呢?其实它是用来组合函数的,可以将两个函数组合成一个新函数使用,举个例子:
Consumer<String> a = (String str)-> System.out.println(str.toLowerCase());
Consumer<String> b = (String str)-> System.out.println(str.toUpperCase());
Consumer<String> c = a.andThen(b); //先执行a,然后用同一个参数再执行b
c.accept("hello");
/**
* 打印结果为:
* hello
* HELLO
*/
Function
Function代表接收一个参数、且有返回值的操作,下面是Function接口的定义:
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));
}
//...
}
Function接口有一个apply抽象方法需要我们实现。下面的示例就是接收一个String类型的参数,然后返回拼接后的字符串
Function<String, String> a = (String str) -> "hello," + str;
String result = a.apply("world");
//result的值为"hello,world"
接口定义中的默认方法compose和andThen都是用来组合函数的,两者的区别就是组合的函数执行顺序不同,看个例子就懂了:
Function<String, String> a = (String str) -> "hello," + str;
Function<String, String> b = (String str) -> str.toUpperCase();
//组合函数c是先执行b,然后拿着b的返回值做为参数再执行a
Function<String, String> c = a.compose(b);
String result1 = c.apply("world"); //result1的值为"hello,WORLD"
//组合函数d是先执行a,然后拿着a的返回值做为参数再执行b
Function<String, String> d = a.andThen(b);
String result2 = d.apply("world"); //result2的值为"HELLO,WORLD"
Predicate
Predicate代表接收一个参数、且返回一个boolean值的操作,下面是Predicate接口的定义:
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
//...
}
Predicate接口有一个test抽象方法需要我们实现。下面是判断一个数是否小于3的例子:
Predicate<Integer> lessThanThree = (Integer x)->x<3;
lessThanThree.test(5); //false
接口定义中的默认方法and和or都是用来组合函数的,分别表示逻辑与、逻辑或,看个例子:
Predicate<Integer> lessThanThree = (Integer x)->x<3;
Predicate<Integer> lessThanTen = (Integer x)->x<10;
Predicate<Integer> andPredicate = lessThanThree.and(lessThanTen);
andPredicate.test(5); //false
Predicate<Integer> orPredicate = lessThanThree.or(lessThanTen);
orPredicate.test(5); //true
Supplier
Supplier代表无参、且有返回值的操作,下面是Supplier接口的定义:
public interface Supplier<T> {
T get();
}
Supplier接口有一个get抽象方法需要我们实现。下面是每次调用生成一个随机数的例子:
Supplier<Integer> randomNum = ()-> (int) (Math.random() * 100);
randomNum.get(); //随机一个大于等于0且小于100的数