JDK1.8 对函数式接口的描述
/*** An informative annotation type used to indicate that an interface* type declaration is intended to be a <i>functional interface</i> as* defined by the Java Language Specification.** Conceptually, a functional interface has exactly one abstract* method. Since {@linkplain java.lang.reflect.Method#isDefault()* default methods} have an implementation, they are not abstract. If* an interface declares an abstract method overriding one of the* public methods of {@code java.lang.Object}, that also does* <em>not</em> 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.** <p>Note that instances of functional interfaces can be created with* lambda expressions, method references, or constructor references.** <p>If a type is annotated with this annotation type, compilers are* required to generate an error message unless:** <ul>* <li> The type is an interface type and not an annotation type, enum, or class.* <li> The annotated type satisfies the requirements of a functional interface.* </ul>** <p>However, the compiler will treat any interface meeting the* definition of a functional interface as a functional interface* regardless of whether or not a {@code FunctionalInterface}* annotation is present on the interface declaration.** @jls 4.3.2. The Class Object* @jls 9.8 Functional Interfaces* @jls 9.4.3 Interface Method Body* @since 1.8*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
从注释我们可以得出
- 函数式接口的实例可以使用lambda表示,方法引用或者构造函数引用
- 带有这个注解的type表示这是接口,而不是注解,枚举或者类
- 函数式接口可以不带这个注解,但是带上了这个注解却不是函数式接口的话,编译器将会报错
下面自定义一个自己的函数式接口 :
@FunctionalInterface
public interface MyFunction {//只能有一个抽象方法public void handlerMyFunction();//接口默认方法 jdk1.8 新提供default特性default void handlerFunction() {System.out.println("this is my interface method");}//静态方法static void getFunction() {System.out.println("this is static method");}
}
default 是 jdk1.8提出的,思考一下为什么会提供这个功能?
在List接口中,我们可以看到如下方法。
default void replaceAll(UnaryOperator<E> operator) {Objects.requireNonNull(operator);final ListIterator<E> li = this.listIterator();while (li.hasNext()) {li.set(operator.apply(li.next()));} }default void sort(Comparator<? super E> c) {Object[] a = this.toArray();Arrays.sort(a, (Comparator) c);ListIterator<E> i = this.listIterator();for (Object e : a) {i.next();i.set((E) e);} }
你会神奇的发现,List 从jdk1.2版本开始,使用了这么时间的接口,竟然能够通过default方法进行扩展接口的功能。
通过函数式接口接口的简单理解,那我们看下jdk1.8为我们提供了哪些接口
四大核心函数式接口
函数式接口 | 参数类型 | 返回参数 | 使用场景 |
---|---|---|---|
Consumer 消费型接口 | T | void | 对类型为 T 的对象应用操作,接口定义的方法:void accept(T t) |
Supplier 供给型接口 | 无 | T | 返回类型为 T 的对象,接口定义的方法:T get() |
Function<T, R>函数式接口 | T | R | 对类型为 T 的对象应用操作,并 R 类型的返回结果。接口定义的方法:R apply(T t) |
Predicate 断言型接口 | T | boolean | 确定类型为 T 的对象是否满足约束条件,并返回boolean 类型的数据 接口定义的方法:boolean test(T t) |
1: Consumer 接口
Consumer 接口是消费性接口,无返回值
public class ConsumerFunction {public static void main(String[] args) {handlerConsumer(1000, (integer) -> {for (int i = 0; i < integer; i++) {System.out.println("number: " + i);}});}public static void handlerConsumer(Integer number, Consumer<Integer> consumer) {consumer.accept(number);}
}
2: Supplier 接口
Supplier 接口是供给型接口,有返回值
public class SupplierFunction {public static void main(String[] args) {List<Integer> numberList = getNumberList(10, () -> new Random().nextInt(100));System.out.println(numberList);}public static List<Integer> getNumberList(int num, Supplier<Integer> supplier) {List<Integer> list = new ArrayList<>();for (int i = 0; i < num; i++) {list.add(supplier.get());}return list;}
}
3: Function接口
Function 接口是函数型接口,有返回值
public class FunctionFunction {public static void main(String[] args) {String hello = handlerString("hello", s -> s.toUpperCase());System.out.println(hello);}public static String handlerString(String str, Function<String, String> function) {return function.apply(str);}
}
4: Predicate接口
Predicate 接口是断言型接口,返回值类型为 boolean
public class PredicateFunction {public static void main(String[] args) {List<String> stringList = Arrays.asList("hello", "World", "Lambda", "Predicate");List<String> strings = filterString(stringList, str -> str.length() > 5);System.out.println(strings);}public static List<String> filterString(List<String> list, Predicate<String> predicate) {List<String> result = new ArrayList<>();for (String str : list) {if (predicate.test(str)) {result.add(str);}}return result;}
}
通过上面的事例,我的理解函数式接口似乎和匿名内部类,和lambda表达式是一个东西。如果更清晰概括的读者,可以在评论区留下你的理解和概括。
其他函数接口
函数式接口 | 参数类型 | 返回参数 | 使用场景 |
---|---|---|---|
BiFunction(T, U, R) | T, U | R | 对类型为 T,U 的参数应用操作,返回 R 类型的结果。接口定义的方法:R apply(T t, U u) |
UnaryOperator | T | T | 对类型为 T 的对象进行一 元运算, 并返回 T 类型的 结果。 包含方法为 T apply(T t) |
BinaryOperator | T, T | T | 对类型为 T 的对象进行二 元运算, 并返回 T 类型的 结果。 包含方法为T apply(T t1, T t2) |
BiConsumer<T, U> | T, U | void | 对类型为 T, U 参数应用 操作。 包含方法为 void accept(T t, U u) |
ToIntFunction | T | int | 计算 int 值的函数 |
ToLongFunction | T | long | 计算 long 值的函数 |
ToDoubleFunction | T | double | 计算 double 值的函数 |
IntFunction | int | R | 参数为 int 类型的函数 |
LongFunction | long | R | 参数为 long 类型的函数 |
DoubleFunction | double | R | 参数为 double 类型的函数 |
总结
通过使用函数式接口,可以将Lambda表达式作为参数传递给方法,从而简化代码,提高代码的可读性和维护性,当然这种简洁性和可读性是仁者见仁,智者见智的事情。