Function 源码解析与实践
创始人
2024-02-28 08:34:56
0

作者:陈昌浩

1 导读

if…else…在代码中经常使用,听说可以通过 Java 8 的 Function 接口来消灭 if…else…!Function 接口是什么?如果通过 Function 接口接口消灭 if…else…呢?让我们一起来探索一下吧。

2 Function 接口

Function 接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Function 接口可以被隐式转换为 lambda 表达式。可以通过 FunctionalInterface 注解来校验 Function 接口的正确性。Java 8 允许在接口中加入具体方法。接口中的具体方法有两种,default 方法和 static 方法。

@FunctionalInterfaceinterface TestFunctionService{    void addHttp(String url);}

复制代码

那么就可以使用 Lambda 表达式来表示该接口的一个实现。

TestFunctionService testFunctionService = url -> System.out.println("http:" + url);

复制代码

2.1 FunctionalInterface

2.1.1 源码

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface FunctionalInterface {}

复制代码

2.1.2 说明

上图是 FunctionalInterface 的注解说明。通过上面的注解说明,可以知道 FunctionalInterface 是一个注解,用来说明一个接口是函数式接口。 函数式接口只有一个抽象方法。 可以有默认方法,因为默认方法有一个实现,所以不是抽象的。函数接口的实例可以用 lambda 表达式、方法引用或构造函数引用创建。

FunctionalInterface 会校验接口是否满足函数式接口:

  • 类型必须是接口类型,不能是注释类型、枚举或类。

  • 只能有一个抽象方法。

  • 可以有多个默认方法和静态方法。

  • 可以显示覆盖 java.lang.Object 中的抽象方法。

编译器会将满足函数式接口定义的任何接口视为函数式接口,而不管该接口声明中是否使用 FunctionalInterface 注解。

3 Function 接口主要分类

Function 接口主要分类:

  • Function:Function 函数的表现形式为接收一个参数,并返回一个值。

  • Supplier:Supplier 的表现形式为不接受参数、只返回数据。

  • Consumer:Consumer 接收一个参数,没有返回值。

  • Runnable:Runnable 的表现形式为即没有参数也没有返回值。

3.1 Function

Function 函数的表现形式为接收一个参数,并返回一个值。

3.1.1 源码

@FunctionalInterfacepublic interface Function {    R apply(T t);    default  Function compose(Function before) {        Objects.requireNonNull(before);        return (V v) -> apply(before.apply(v));    }    default  Function andThen(Function after) {        Objects.requireNonNull(after);        return (T t) -> after.apply(apply(t));    }    static  Function identity() {        return t -> t;    }}

复制代码

3.1.2 方法说明

  • apply:抽象方法。将此函数应用于给定的参数。参数 t 通过具体的实现返回 R。

  • compose:default 方法。返回一个复合函数,首先执行 fefore 函数应用于输入,然后将该函数应用于结果。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。

  • andThen:default 方法。返回一个复合函数,该复合函数首先对其应用此函数它的输入,然后对结果应用 after 函数。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。

  • identity:static 方法。返回一个始终返回其输入参数的函数。

3.1.3 方法举例

1)apply

测试代码:

public  String upString(String str){    Function function1 = s -> s.toUpperCase();    return function1.apply(str);} public static void main(String[] args) {     System.out.println(upString("hello!")); }

复制代码

通过 apply 调用具体的实现。执行结果:

2)compose

测试代码:

public static void main(String[] args) {    Function function1 = s -> s.toUpperCase();    Function function2 = s -> "my name is "+s;    String result = function1.compose(function2).apply("zhangSan");    System.out.println(result);}

复制代码

执行结果

如结果所示:compose 先执行 function2 后执行 function1。

3)andThen

测试代码:

public static void main(String[] args) {    Function function1 = s -> s.toUpperCase();    Function function2 = s -> "my name is "+s;    String result = function1.andThen(function2).apply("zhangSan");    System.out.println(result);}

复制代码

执行结果:

如结果所示:

andThen 先执行 function1 后执行 function2。

  • identity

测试代码:

public static void main(String[] args) {    Stream stream = Stream.of("order", "good", "lab", "warehouse");    Map map = stream.collect(Collectors.toMap(Function.identity(), String::length));    System.out.println(map);}

复制代码

执行结果:

3.2 Supplier

Supplier 的表现形式为不接受参数、只返回数据。

3.2.1 源码

@FunctionalInterfacepublic interface Supplier {    /**     * Gets a result.     *     * @return a result     */    T get();}

复制代码

3.2.2 方法说明

get:抽象方法。通过实现返回 T。

3.2.3 方法举例

public class SupplierTest {    SupplierTest(){        System.out.println(Math.random());        System.out.println(this.toString());    }}    public static void main(String[] args) {        Supplier sup = SupplierTest::new;        System.out.println("调用一次");        sup.get();        System.out.println("调用二次");        sup.get();}

复制代码

执行结果:

如结果所示:Supplier 建立时并没有创建新类,每次调用 get 返回的值不是同一个。

3.3 Consumer

Consumer 接收一个参数,没有返回值。

3.3.1 源码

@FunctionalInterfacepublic interface Consumer {    void accept(T t);    default Consumer andThen(Consumer after) {        Objects.requireNonNull(after);        return (T t) -> { accept(t); after.accept(t); };    }}

复制代码

3.3.2 方法说明

  • accept:对给定参数 T 执行一些操作。

  • andThen:按顺序执行 Consumer -> after ,如果执行操作引发异常,该异常被传递给调用者。

3.3.3 方法举例

public static void main(String[] args) {    Consumer consumer = s -> System.out.println("consumer_"+s);    Consumer after = s -> System.out.println("after_"+s);    consumer.accept("isReady");    System.out.println("========================");    consumer.andThen(after).accept("is coming");}

复制代码

执行结果:

如结果所示:对同一个参数 T,通过 andThen 方法,先执行 consumer,再执行 fater。

3.4 Runnable

Runnable:Runnable 的表现形式为即没有参数也没有返回值。

3.4.1 源码

@FunctionalInterfacepublic interface Runnable {    public abstract void run();}

复制代码

3.4.2 方法说明

run:抽象方法。run 方法实现具体的内容,需要将 Runnale 放入到 Thread 中,通过 Thread 类中的 start()方法启动线程,执行 run 中的内容。

3.4.3 方法举例

public class TestRun implements Runnable {    @Override    public void run() {        System.out.println("TestRun is running!");    }}    public static void main(String[] args) {        Thread thread = new Thread(new TestRun());        thread.start();    }

复制代码

执行结果:

如结果所示:当线程实行 start 方法时,执行 Runnable 的 run 方法中的内容。

4 Function 接口用法

Function 的主要用途是可以通过 lambda 表达式实现方法的内容。

4.1 差异处理

原代码:

@Datapublic class User {    /**     * 姓名     */    private String name;    /**     * 年龄     */    private int age;    /**     * 组员     */    private List parters;}    public static void main(String[] args) {        User user =new User();        if(user ==null ||user.getAge() <18 ){            throw new RuntimeException("未成年!");        }}

复制代码

执行结果:

使用 Function 接口后的代码:

@FunctionalInterfacepublic interface testFunctionInfe {    /**     * 输入异常信息     * @param message     */    void showExceptionMessage(String message);}    public static testFunctionInfe doException(boolean flag){        return (message -> {            if (flag){                throw new RuntimeException(message);            }        });    }    public static void main(String[] args) {        User user =new User();        doException(user ==null ||user.getAge() <18).showExceptionMessage("未成年!");}

复制代码

执行结果:

使用 function 接口前后都抛出了指定的异常信息。

4.2 处理 if…else…

原代码:

public static void main(String[] args) {    User user =new User();    if(user==null){        System.out.println("新增用户");    }else {        System.out.println("更新用户");    }}

复制代码

使用 Function 接口后的代码:

public static void main(String[] args) {    User user =new User();    Consumer trueConsumer = o -> {        System.out.println("新增用户");    };    Consumer falseConsumer= o -> {        System.out.println("更新用户");    };    trueOrFalseMethdo(user).showExceptionMessage(trueConsumer,falseConsumer);}public static testFunctionInfe trueOrFalseMethdo(User user){    return ((trueConsumer, falseConsumer) -> {        if(user==null){            trueConsumer.accept(user);        }else {            falseConsumer.accept(user);        }    });}@FunctionalInterfacepublic interface testFunctionInfe {    /**     * 不同分处理不同的事情     * @param trueConsumer     * @param falseConsumer     */    void showExceptionMessage(Consumer trueConsumer,Consumer falseConsumer);}

复制代码

执行结果:

4.3 处理多个 if

原代码:

public static void main(String[] args) {    String flag="";    if("A".equals(flag)){        System.out.println("我是A");    }else if ("B".equals(flag)) {        System.out.println("我是B");    }else if ("C".equals(flag)) {        System.out.println("我是C");    }else {        System.out.println("没有对应的指令");    }}

复制代码

使用 Function 接口后的代码:

public static void main(String[] args) {    String flag="B";    Map map =initFunctionMap();    trueOrFalseMethdo(map.get(flag)==null).showExceptionMessage(()->{        System.out.println("没有相应指令");    },map.get(flag));}public static   Map initFunctionMap(){    Map result  = Maps.newHashMap();    result.put("A",()->{System.out.println("我是A");});    result.put("B",()->{System.out.println("我是B");});    result.put("C",()->{System.out.println("我是C");});    return result;}public static testFunctionInfe trueOrFalseMethdo(boolean flag){    return ((runnable, falseConsumer) -> {        if(flag){            runnable.run();        }else {            falseConsumer.run();        }    });}

复制代码

执行结果:

5 总结

Function 函数式接口是 java 8 新加入的特性,可以和 lambda 表达式完美结合,是非常重要的特性,可以极大的简化代码。

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...