首先什么是函数式接口?
定义:函数式接口就是一个有且仅有一个抽象方法,但可以有多个非抽象方法的接口
函数式接口是适用于函数式编程的接口,在Java中最直接的体现就是可以使用Lambda表达式
在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
包下定义了非常多函数式接口
@FunctionalInterface
public interface Supplier<T> {
T get();
}
案例:
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);
}
}
@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); };
}
}
案例一:只有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);
}
@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);
}
}
案例:
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));
}
@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;
}
}
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表达式结合使用可以让代码更简洁易读,非常方便开发和维护,希望大家今后可以多多实践。