Java8新特性—四大内置函数式接口

Java8新特性——四大内置函数式接口预备知识背景Lambda 的设计者们为了让现有的功能与 Lambda 表达式良好兼容,考虑了很多方法,于是产生了函数接口这个概念 。
什么是函数式接口?函数式接口指的是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,这样的接口可以隐式转换为 Lambda 表达式 。
但是在实践中,函数式接口非常脆弱,只要某个开发者在该接口中添加一个函数 , 则该接口就不再是函数式接口进而导致编译失败 。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface,举个简单的函数式接口的定义:
@FunctionalInterface public interface GreetingService {     void sayMessage(String message); } Java7 只能通过匿名内部类进行编程,例如:
GreetingService greetService = new GreetingService() {      @Override     public void sayMessage(String message) {         System.out.println("Hello " + message);     } }; greetService.sayMessage("world"); Java8 可以采用 Lambda 表达方进行编程,例如:
GreetingService greetService = message -> System.out.println("Hello " + message); greetService.sayMessage("world"); 目前 Java 库中的所有相关接口都已经带有这个注解了,实践上java.lang.Runnable和java.util.concurrent.Callable是函数式接口的最佳例子!
@FunctionalInterface注解Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错 。
正确例子 , 没有报错:
/** * @Description FunctionalInterface * @Author vchicken * @Date 2022/9/24 14:46 */@FunctionalInterfacepublic interface TestFunctionalInterface {void sayMessage(String message);}错误例子,接口中包含了两个抽象方法,违反了函数式接口的定义,Eclipse报错提示其不是函数式接口 。

Java8新特性—四大内置函数式接口

文章插图
提醒:加不加@FunctionalInterface对于接口是不是函数式接口没有影响,该注解知识提醒编译器去检查该接口是否仅包含一个抽象方法 。
四大函数式接口1.Function接口什么是Function接口?
Java8新特性—四大内置函数式接口

文章插图
从Function接口的源代码,我们可以看出,JDK1.8之后才加入这个接口 。Functional接口类中只有一个抽象方法待实现,符合函数式接口(指的是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口) , 因此Function接口可以用Lambda表达式——这个方法就是apply 。
从源码可以看出 , 入参和出参类型,用泛型动态指定 。apply的具体逻辑就相当于是入参转化为出参的具体逻辑 。也就相当于是y = f(x)这个里面的,映射法则f 。具体逻辑需要我们用匿名内部类或者Lambda,写方法体来实现 。因此这个接口又叫函数型接口
下面我们来用代码举栗如何使用Function接口:
public class FunctionTest {public static void main(String[] args) {// 如果入参为null,则回参为0 , 否则返回入参的值作为出参Function<Integer, Integer> function1 = s -> s == null ? 0 : s;// 将入参的值+1后作为回参返回Function<Integer, Integer> function2 = s -> s + 1;// 如果入参为null,则回参为"",否则返回入参的值作为出参Function<String, String> function3 = s -> s == null ? "空的" : s;System.out.println(function1.apply(null));System.out.println(function1.apply(100));System.out.println(function2.apply(10));System.out.println(function3.apply(null));System.out.println(function3.apply("hello world!"));// andThen是先执行前面的操作,然后执行andThen之后的操作Function<Integer, Integer> first = x -> x * x;Function<Integer, Integer> after = y -> y * 2;System.out.println(first.apply(3));System.out.println(after.apply(3));int res = first.andThen(after).apply(4);System.out.println(res);}}执行结果
010011空的hello world!9632从上面的栗子我们可以看出:
Java把这些映射规则,也就是y = f(x)中的【f】抽象成了这个Function接口的apply逻辑 。然后x和y,自变量和因变量,也就是入参出参,Java使用了扩展性更强的泛型参数类型,而不是固定Object入参出参 。因为固定Object的话还要涉及到类型转换,还有可能报ClassCast异常,很麻烦

推荐阅读