|
| 1 | +--- |
| 2 | +sitemap: |
| 3 | + exclude: false |
| 4 | + changefreq: hourly |
| 5 | +title: '@FunctionalInterface、Lambda表达式' |
| 6 | +date: 2024-8-8 |
| 7 | +tags: |
| 8 | +- java |
| 9 | +--- |
| 10 | + |
| 11 | +Java语言从JDK1.8开始引入了函数式编程。 |
| 12 | + |
| 13 | +函数式编程的核心特点是,函数作为一段功能代码,可以像变量一样进行引用和传递,以便在有需要的时候进行调用。 |
| 14 | + |
| 15 | + |
| 16 | +## @FunctionalInterface与“函数类型” |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | +Java对函数式编程的支持,本质是通过接口机制来实现的。 |
| 21 | + |
| 22 | +函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 |
| 23 | + |
| 24 | + |
| 25 | +首先定义一个仅声明一个方法的接口,然后对接口冠以@FunctionalInterface注解,那么这个接口就可以作为“函数类型”,可以接收一段以Lambda表达式,或者方法引用予以承载的逻辑代码。例如: |
| 26 | + |
| 27 | +```java |
| 28 | +@FunctionalInterface |
| 29 | +interface IntAdder { |
| 30 | + int add(int x, int y); |
| 31 | +} |
| 32 | + |
| 33 | +IntAdder adder = (x, y) -> x + y; |
| 34 | +``` |
| 35 | + |
| 36 | +@FunctionalInterface下只能声明一个方法,覆写Object中toString/equals的方法不受此个数限制。 |
| 37 | + |
| 38 | +```java |
| 39 | +// Comparator.java |
| 40 | +@FunctionalInterface |
| 41 | +public interface Comparator<T> { |
| 42 | + int compare(T o1, T o2); |
| 43 | + boolean equals(Object obj); |
| 44 | + //... |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +@FunctionalInterface注解不是必须的,不加这个注解的接口(前提是只包含一个方法)一样可以作为函数类型。不过,显而易见的是,加了这个注解表意更明确、更直观,是更被推荐的做法 |
| 49 | + |
| 50 | + |
| 51 | +## JDK提供的“函数类型”: |
| 52 | + |
| 53 | +```java |
| 54 | +@FunctionalInterface |
| 55 | +public interface Consumer<T> { |
| 56 | + void accept(T t); //接收一个类型为T(泛型)的参数,无返回值;所以叫消费者 |
| 57 | +} |
| 58 | +@FunctionalInterface |
| 59 | +public interface BiConsumer<T, U> { |
| 60 | + void accept(T t, U u);//接收2个参数,无返回值 |
| 61 | +} |
| 62 | +@FunctionalInterface |
| 63 | +public interface Supplier<T> { |
| 64 | + T get();//无参数,有返回值(所以叫提供者) |
| 65 | +} |
| 66 | +//注意没有BiSupplier,因为返回值只能有1个,不会有2个 |
| 67 | +@FunctionalInterface |
| 68 | +public interface Function<T, R> { |
| 69 | + R apply(T t);//一个输入(参数),一个输出(返回值) |
| 70 | +} |
| 71 | +@FunctionalInterface |
| 72 | +public interface BiFunction<T, U, R> { |
| 73 | + R apply(T t, U u);//两个输入T和U,一个输出R |
| 74 | +} |
| 75 | +@FunctionalInterface |
| 76 | +public interface UnaryOperator<T> extends Function<T, T> { |
| 77 | + static <T> UnaryOperator<T> identity() {//一元操作,输入原样返回给输出 |
| 78 | + return t -> t; |
| 79 | + } |
| 80 | +} |
| 81 | +@FunctionalInterface |
| 82 | +public interface BinaryOperator<T> extends BiFunction<T,T,T> {//二元操作,输入输出类型相同 |
| 83 | + public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) { |
| 84 | + Objects.requireNonNull(comparator); |
| 85 | + return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;//传入比较器,返回较小者 |
| 86 | + } |
| 87 | + public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) { |
| 88 | + Objects.requireNonNull(comparator); |
| 89 | + return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;//传入比较器,返回较大者 |
| 90 | + } |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +## Lambda表达式 |
| 95 | + |
| 96 | +Lambda表达式用来定义函数实现体。 |
| 97 | + |
| 98 | +```java |
| 99 | +//无返回值的时候 |
| 100 | +(int x)->{System.out.println(x);} |
| 101 | +(x)->{System.out.println(x);}//参数类型自动推断 |
| 102 | +x->{System.out.println(x);}//只有一个参数的时候,可以省略小括号 |
| 103 | +x->System.out.println(x);//实现体只有一个表达式可以省略大括号,System.out.println本身无返回值 |
| 104 | +//有返回值的情况 |
| 105 | +(int x)->{return x*x;} |
| 106 | +(x)->{return x*x;} |
| 107 | +//x->return x*x; //错误,不能这么写!! |
| 108 | +x->x*x; |
| 109 | +``` |
| 110 | + |
| 111 | +## 方法引用 |
| 112 | + |
| 113 | +函数类型可以接收一段Lambda表达式,或者对方法的引用。 |
| 114 | + |
| 115 | +方法引用就是对一个类中已经存在的方法加以引用,分4中类型:(以Test类为例): |
| 116 | + |
| 117 | +1. 对类构造方法的引用,如Test::new。 |
| 118 | +2. 对类静态方法的引用,如Test::staticMethodName |
| 119 | +3. 对对象实例方法的引用,如:new Test()::instanceMethod |
| 120 | +4. 是2和3的结合,如Test::instanceMethod2,但要求函数类型声明和函数调用的时候,其第一个参数必须是Test类的实例。 |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | + |
| 125 | + |
0 commit comments