您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Function源码解析与实践
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Function源码解析与实践
自猿其说Tech
2022-10-12
IP归属:未知
78960浏览
计算机编程
### 1 导读 if...else...在代码中经常使用,听说可以通过Java 8的Function接口来消灭if...else...!Function接口是什么?如果通过Function接口接口消灭if...else...呢?让我们一起来探索一下吧。 ### 2 Function接口 Function接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Function接口可以被隐式转换为 lambda 表达式。可以通过FunctionalInterface注解来校验Function接口的正确性。Java 8允许在接口中加入具体方法。接口中的具体方法有两种,default方法和static方法。 ```java @FunctionalInterface interface TestFunctionService { void addHttp(String url); } ``` 那么就可以使用Lambda表达式来表示该接口的一个实现。 ```java TestFunctionService testFunctionService = url -> System.out.println("http:" + url); ``` #### 2.1 FunctionalInterface ##### 2.1.1 源码 ```java @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface {} ``` ##### 2.1.2 说明 ![](//img1.jcloudcs.com/developer.jdcloud.com/36931974-156d-4b5b-9133-a004b37342fa20221012180223.png) 上图是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 源码 ```java @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; } } ``` ##### 3.1.2 方法说明 - apply:抽象方法。将此函数应用于给定的参数。参数t通过具体的实现返回R。 - compose:default方法。返回一个复合函数,首先执行fefore函数应用于输入,然后将该函数应用于结果。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。 - andThen:default方法。返回一个复合函数,该复合函数首先对其应用此函数它的输入,然后对结果应用after函数。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。 - identity:static方法。返回一个始终返回其输入参数的函数。 ##### 3.1.3 方法举例 1)apply 测试代码: ```java public String upString(String str){ Function<String, String> function1 = s -> s.toUpperCase(); return function1.apply(str); } public static void main(String[] args) { System.out.println(upString("hello!")); } ``` 通过apply调用具体的实现。 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/5cd0d080-825b-47fe-a2db-950cb842d9c620221012180435.png) 2)compose 测试代码: ```java public static void main(String[] args) { Function<String, String> function1 = s -> s.toUpperCase(); Function<String, String> function2 = s -> "my name is "+s; String result = function1.compose(function2).apply("zhangSan"); System.out.println(result); } ``` 执行结果 ![](//img1.jcloudcs.com/developer.jdcloud.com/8c050b0a-5d91-41f8-a55e-2475618bdf4520221012180517.png) 如结果所示: compose 先执行function2 后执行function1。 3)andThen 测试代码: ```java public static void main(String[] args) { Function<String, String> function1 = s -> s.toUpperCase(); Function<String, String> function2 = s -> "my name is "+s; String result = function1.andThen(function2).apply("zhangSan"); System.out.println(result); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/69228c45-e075-44b1-b044-1b2285cdc12c20221012180546.png) 如结果所示: andThen先执行function1 后执行function2。 - identity 测试代码: ```java public static void main(String[] args) { Stream<String> stream = Stream.of("order", "good", "lab", "warehouse"); Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), String::length)); System.out.println(map); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/2ee8c6d6-0cf3-4af2-a618-dfc15e935cbe20221012180626.png) #### 3.2 Supplier Supplier的表现形式为不接受参数、只返回数据。 ##### 3.2.1 源码 ```java @FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); } ``` ##### 3.2.2 方法说明 get:抽象方法。通过实现返回T。 ##### 3.2.3 方法举例 ```java public class SupplierTest { SupplierTest(){ System.out.println(Math.random()); System.out.println(this.toString()); } } public static void main(String[] args) { Supplier<SupplierTest> sup = SupplierTest::new; System.out.println("调用一次"); sup.get(); System.out.println("调用二次"); sup.get(); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/b62af52e-67de-4165-848c-48b3f22848db20221012180711.png) 如结果所示: Supplier建立时并没有创建新类,每次调用get返回的值不是同一个。 #### 3.3 Consumer Consumer接收一个参数,没有返回值。 ##### 3.3.1 源码 ```java @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); }; } } ``` ##### 3.3.2 方法说明 - accept:对给定参数T执行一些操作。 - andThen:按顺序执行Consumer -> after ,如果执行操作引发异常,该异常被传递给调用者。 ##### 3.3.3 方法举例 ```java public static void main(String[] args) { Consumer<String> consumer = s -> System.out.println("consumer_"+s); Consumer<String> after = s -> System.out.println("after_"+s); consumer.accept("isReady"); System.out.println("========================"); consumer.andThen(after).accept("is coming"); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/0a625c9a-7688-4199-a9ae-3873f19b394620221012180812.png) 如结果所示: 对同一个参数T,通过andThen 方法,先执行consumer,再执行fater。 #### 3.4 Runnable Runnable:Runnable的表现形式为即没有参数也没有返回值。 ##### 3.4.1 源码 ```java @FunctionalInterface public interface Runnable { public abstract void run(); } ``` ##### 3.4.2 方法说明 run:抽象方法。run方法实现具体的内容,需要将Runnale放入到Thread中,通过Thread类中的start()方法启动线程,执行run中的内容。 ##### 3.4.3 方法举例 ```java 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(); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/41d0da65-c3e7-491b-88cf-f7a409320da820221012181059.png) 如结果所示: 当线程实行start方法时,执行Runnable 的run方法中的内容。 ### 4 Function接口用法 Function的主要用途是可以通过lambda 表达式实现方法的内容。 #### 4.1 差异处理 原代码: ```java @Data public class User { /** * 姓名 */ private String name; /** * 年龄 */ private int age; /** * 组员 */ private List<User> parters; } public static void main(String[] args) { User user =new User(); if(user ==null ||user.getAge() <18 ){ throw new RuntimeException("未成年!"); } } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/264bf868-f7bf-44ca-aa61-27c09f707ae620221012181144.png) 使用Function接口后的代码: ```java @FunctionalInterface public 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("未成年!"); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/2aa3dd47-0434-4a4f-8880-00000e27f48520221012181216.png) 使用function接口前后都抛出了指定的异常信息。 #### 4.2 处理if...else... 原代码: ```java public static void main(String[] args) { User user =new User(); if(user==null){ System.out.println("新增用户"); }else { System.out.println("更新用户"); } } ``` 使用Function接口后的代码: ```java 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); } }); } @FunctionalInterface public interface testFunctionInfe { /** * 不同分处理不同的事情 * @param trueConsumer * @param falseConsumer */ void showExceptionMessage(Consumer trueConsumer,Consumer falseConsumer); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/6a6ef345-f651-42b1-aa03-b8977172278820221012181311.png) #### 4.3 处理多个if 原代码: ```java 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接口后的代码: ```java public static void main(String[] args) { String flag="B"; Map<String, Runnable> map =initFunctionMap(); trueOrFalseMethdo(map.get(flag)==null).showExceptionMessage(()->{ System.out.println("没有相应指令"); },map.get(flag)); } public static Map<String, Runnable> initFunctionMap(){ Map<String,Runnable> 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(); } }); } ``` 执行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/52f537d9-af33-4e1d-9a85-58839e9aa6b620221012181354.png) ### 5 总结 Function函数式接口是java 8新加入的特性,可以和lambda表达式完美结合,是 非常重要的特性,可以极大的简化代码。 ------------ ###### 自猿其说Tech-JDL京东物流技术与数据智能部 ###### 作者:陈昌浩
原创文章,需联系作者,授权转载
上一篇:测试进阶之路—新手关于测试碎碎念篇
下一篇:深入跨域 - 从初识到入门
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号