关于function:Function源码解析与实践

28次阅读

共计 6785 个字符,预计需要花费 17 分钟才能阅读完成。

作者:陈昌浩

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 表达式完满联合,是十分重要的个性, 能够极大的简化代码。

正文完
 0