Java函数式接口
一、函数式接口概念
首先什么是函数式接口?
定义:函数式接口就是一个有且仅有一个抽象方法,但可以有多个非抽象方法的接口
函数式接口是适用于函数式编程的接口,在Java中最直接的体现就是可以使用Lambda表达式
@FunctionalInterface注解
在Java8中引入了@FunctionalInterface
注解来标识函数式接口,而且该注解还可以进行编译错误检查。
加上@FunctionalInterface
注解后,当接口不符合函数式接口定义时,编译器会报错。
几个函数式接口实例:
- 只有一个抽象方法的函数式接口
/**
* 这就是个函数式接口,接口只有一个抽象方法
*/
@FunctionalInterface
public interface Show {
void show();
}
- 有一个抽象方法和多个非抽象方法的函数式接口
/**
* 这是个函数式接口,接口有一个抽象方法和一个非抽象方法
*/
@FunctionalInterface
public interface Show {
void show();
default void printTest() {
System.out.println("Hello CSDN");
}
}
- 有多个抽象方法时不再是函数式接口,编译器报错
/**
* 有两个抽象方法时,不再是函数式接口
*/
@FunctionalInterface
public interface Show {
void show();
void read();
default void printTest() {
System.out.println("Hello CSDN");
}
/**
* 编译器报错
* java: 意外的 @FunctionalInterface 注释
* test.Show 不是函数接口
* 在 接口 test.Show 中找到多个非覆盖抽象方法
*/
}
函数式接口的实现
我们已经知道函数式接口会包含一个抽象方法,当使用接口时要进行实现,实现函数式接口有三种方案:直接实现、匿名内部类、Lambda表达式
public class ShowImpl implements Show{
@Override
public void show() {
System.out.println("Hello 直接继承接口实现");
}
}
public static void main(String[] args) {
Show test01 = new Show() {
@Override
public void show() {
System.out.println("Hello 匿名内部类");
}
};
test01.show();
}
public static void main(String[] args) {
Show test01 = () -> System.out.println("Hello Lambda表达式");
test01.show();
}
对比以上三种实现方法,很明显Lambda表达式是最简便的,Lambda表达式是Java8引入的特性,具有易读、高效、延迟实现的优点,推荐大家使用
二、常见的函数式接口
Java8在java.util.function
包下定义了非常多函数式接口
这里介绍几个常用的
- Supplier接口
- Consumer接口
- Predicate接口
- Function接口
2.1 Supplier
@FunctionalInterface
public interface Supplier<T> {
T get();
}
- T get():抽象函数没有参数,可以获取结构,需要自己实现内部逻辑
- Supplier接口也被称为生产型接口,通过指定泛型的类型,可以生产对应类型的数据供我们使用
案例:
public class Demo {
public static String getString(Supplier<String> supplier) {
return supplier.get();
}
public static void main(String[] args) {
Supplier supplier = () -> "hello world";
String res = getString(supplier);
System.out.println(res);
}
}
2.2 Consumer接口
@FunctionalInterface
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); };
}
}
- void accept(T t):Consumer的抽象函数有参数无返回值
- Consumer andThen(Consumer<? super T> after):包含一个非抽象函数,其参数和返回值都是Consumer
- Consumer接口和Supplier接口是相反的,Consumer接口被称为消费型接口,通过泛型来指定要传入参数的类型,然后进行处理消费,没有任何返回值
案例一:只有accept(T t)函数
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
// 打印最大值
Consumer<List<Integer>> printMax = (numList) -> {
int maxNum = Integer.MIN_VALUE;
for (Integer num : numList) {
maxNum = Integer.max(num, maxNum);
}
System.out.println(maxNum);
};
printMax.accept(nums);
}
案例二:包含andThen
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
// 打印最大值
Consumer<List<Integer>> printMax = (numList) -> {
int maxNum = Integer.MIN_VALUE;
for (Integer num : numList) {
maxNum = Integer.max(num, maxNum);
}
System.out.println(maxNum);
};
// 打印最小值
Consumer<List<Integer>> printMin = (numList) -> {
int minNum = Integer.MAX_VALUE;
for (Integer num : numList) {
minNum = Integer.min(num, minNum);
}
System.out.println(minNum);
};
// 先printMax进行消费,后printMin进行消费
printMax.andThen(printMin).accept(nums);
}
2.3 Predicate接口
@FunctionalInterface
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> 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) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
- boolean test(T t):通过泛型指定传入参数类型,返回true/false,Predicate是测试接口
- Predicate的默认方法实现了组合的复杂逻辑(与、或、非)
案例:
public static void main(String[] args) {
String testString = "hello world";
// 判断s长度是否大于5
Predicate<String> lenPredicate = (s) -> s.length() > 5;
System.out.println(lenPredicate.test(testString));
// 并且判断是否包含字符'a'
Predicate<String> hPredicate = (s) -> s.contains("a");
// and方法,长度既大于5又包含a
System.out.println(lenPredicate.and(hPredicate).test(testString));
// or方法,长度大于5或者包含a
System.out.println(lenPredicate.or(hPredicate).test(testString));
// negate, 长度不大于5
System.out.println(lenPredicate.negate().test(testString));
}
2.4 Function接口
@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;
}
}
- R apply(T t):可以通过泛型来指定参数和返回值的类型
- Function接口通常用于对参数进行处理、转换,然后返回一个新的值
public static void main(String[] args) {
Function<String, Integer> stringIntegerFunction = (str) -> Integer.valueOf(str);
Function<Integer, String> integerStringFunction = (i) -> i.toString();
Integer num = 46;
// 测试apply方法
String t1 = integerStringFunction.apply(num);
// 测试compose,先运行integerStringFunction,再运行stringIntegerFunction
Integer t2 = stringIntegerFunction.compose(integerStringFunction).apply(num);
// 测试andThen,先运行integerStringFunction,再运行stringIntegerFunction
Integer t3 = integerStringFunction.andThen(stringIntegerFunction).apply(num);
}
以上介绍的几种都是jdk8的函数式接口,实际上jdk8之前也有许多函数式接口,如java.lang.Runnable、java.util.Comparator等,这些函数式的接口用法都是相同的,不再赘述了。
三、总结
函数式接口是一种功能性接口,将函数式接口和Lambda表达式结合使用可以让代码更简洁易读,非常方便开发和维护,希望大家今后可以多多实践。