阅读 78

Function源码解析与实践

作者:陈昌浩

1 导读

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

2 Function接口

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

@FunctionalInterface interface 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 源码
@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

测试代码:

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调用具体的实现。执行结果:

2)compose

测试代码:

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); } 复制代码

执行结果

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

3)andThen

测试代码:

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); } 复制代码

执行结果:

如结果所示:

andThen先执行function1 后执行function2。

  • identity

测试代码:

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); } 复制代码

执行结果:

3.2 Supplier

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

3.2.1 源码
@FunctionalInterface public interface Supplier<T> {     /**      * 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<SupplierTest> sup = SupplierTest::new;         System.out.println("调用一次");         sup.get();         System.out.println("调用二次");         sup.get(); } 复制代码

执行结果:

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

3.3 Consumer

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

3.3.1 源码
@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 方法举例
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"); } 复制代码

执行结果:

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

3.4 Runnable

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

3.4.1 源码
@FunctionalInterface public 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 差异处理

原代码:

@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("未成年!");         } } 复制代码

执行结果:

使用Function接口后的代码:

@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("未成年!"); } 复制代码

执行结果:

使用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);         }     }); } @FunctionalInterface public 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<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();         }     }); } 复制代码

执行结果:

5 总结

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


作者:京东云开发者
链接:https://juejin.cn/post/7171276495661301796
来源:https://www.77cxw.com/


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐