• 深入了解Java 8 新特性:lambda表达式进阶


    阅读建议

    嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议:

    1. 本篇文章大概7000多字,预计阅读时间长需要10分钟。
    2. 本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章,建议收藏起来,方便时常学习与回顾,温故而知新。
    3. 创作不易,免费的点赞、关注,请走上一走,算是对博主一些鼓励,让我更有动力输出更多的干货内容。

    前言

            Java 8中的Lambda表达式是一种匿名函数,它允许你将函数作为方法参数进行传递,或者把代码更简洁地定义在你的应用程序里。另外Java的函数式编程就是Lambda表达式,java的函数式接口的有一个明显特征:有且仅有一个抽象方法的接口。下面是一些常见的Java内置的函数式接口梳理,掌握这些内置的函数式接口是相当有必要的,因为作为一种更简洁、更灵活和更易于维护的编程方式,这在很多的java相关的框架技术中有大量的应用,相信有喜欢钻研源码小伙伴应该深有体会。

    Java内置的函数式接口

    Function

            Function接口是Java 8中引入的一个函数式接口,它位于java.util.function包中。这个接口表示一个输入参数能够产生一个结果的函数。Function接口只有一个抽象方法,即apply(T t),它接受一个参数并返回一个结果。

    1. @FunctionalInterface
    2. public interface Function {
    3. R apply(T t);
    4. default Function compose(Functionsuper V, ? extends T> before) {
    5. Objects.requireNonNull(before);
    6. return (V v) -> apply(before.apply(v));
    7. }
    8. default Function andThen(Functionsuper R, ? extends V> after) {
    9. Objects.requireNonNull(after);
    10. return (T t) -> after.apply(apply(t));
    11. }
    12. static Function identity() {
    13. return t -> t;
    14. }
    15. }

            下面是一个使用Function接口的简单示例:

    1. @Test
    2. public void test5() {
    3. Function function = str -> new Student(str);
    4. Student student = function.apply("张三");
    5. log.info(student.getName());
    6. }

            在Java中,Function接口的默认实现包括以下几种:

    • Function.andThen(Function after):这个方法返回一个新函数,它首先应用原始函数,然后应用另一个函数。也就是说,这个新函数首先将输入映射到某个结果,然后将结果映射到另一个结果。假设我们有一个Function,它接受一个整数作为输入,并返回一个整数作为输出。现在,我们想在这个函数的基础上添加一个新的函数,将得到的整数加倍。
    1. @Test
    2. public void test7() {
    3. Function originalFunction = x -> x * 2;
    4. Function newFunction = x -> x * 2;
    5. Function composedFunction = originalFunction.andThen(newFunction);
    6. int input = 5;
    7. int result = composedFunction.apply(input);
    8. System.out.println(result); // 输出:20
    9. }

    在上面的示例中,我们定义了一个原始函数originalFunction,它接受一个整数作为输入,并将其乘以2。然后,我们定义了一个新的函数newFunction,它也接受一个整数作为输入,并将其乘以2。接下来,我们使用andThen方法将这两个函数组合成一个新的函数composedFunction。最后,我们将输入整数5传递给composedFunction,并打印结果。在这个例子中,首先将输入整数5乘以2得到10,然后将10乘以2得到20,最终输出结果为20。

    • Function. compose(Function before):这个方法返回一个新函数,它首先应用另一个函数,然后将结果映射到原始函数的输入。也就是说,这个新函数首先将输入映射到另一个输入,然后将这个输入映射到结果。假设我们有两个函数,一个将字符串转换为大写,另一个将字符串长度截断为5个字符。这两个函数可以组合成一个新函数,首先将字符串转换为大写,然后将其长度截断为5个字符。
    1. @Test
    2. public void test6(){
    3. Function toUpperCase = str -> str.toUpperCase();
    4. Function truncate = str -> str.substring(0, 6);
    5. Function composedFunction = toUpperCase.compose(truncate);
    6. String input = "hello world!";
    7. String result = composedFunction.apply(input);
    8. System.out.println(result); // 输出:"HEL"
    9. }

    在上面的示例中,我们首先定义了两个函数:toUpperCase和truncate。然后,我们使用compose方法将它们组合成一个新函数composedFunction。最后,我们调用composedFunction对输入字符串进行操作,并打印结果。

    BiFunction

            BiFunction接口是Java 8中引入的一个函数式接口,它位于java.util.function包中。BiFunction接口表示一个接受两个输入参数并返回一个结果的函数。它与Function接口类似,但多了一个输入参数。

            BiFunction接口的定义如下:

    1. @FunctionalInterface
    2. public interface BiFunction {
    3. R apply(T t, U u);
    4. default BiFunction andThen(Functionsuper R, ? extends V> after) {
    5. Objects.requireNonNull(after);
    6. return (T t, U u) -> after.apply(apply(t, u));
    7. }
    8. }

            其中,T和U是输入参数的类型,R是返回结果的类型。apply()方法是抽象的,需要具体的实现来提供具体的逻辑。

            下面是一个使用BiFunction接口的示例:

    1. @Test
    2. public void test8() {
    3. BiFunction add = (x, y) -> x + y;
    4. int result = add.apply(2, 3);
    5. System.out.println(result); // 输出:5
    6. }

    在上面的示例中,我们定义了一个add函数,它接受两个整数作为输入,并将它们相加得到一个整数作为结果。我们使用apply()方法调用该函数并传递两个参数2和3,然后打印结果5。

            BiFunction接口包含一个默认实现,即andThen方法,用于将两个函数组合在一起。它接受一个BiFunction作为参数,并返回一个新的函数,该函数将先应用原始函数,然后应用给定的函数。

    1. @Test
    2. public void test9() {
    3. BiFunction addAndToString = (x, y) -> Integer.toString(x + y);
    4. Function toUpperCase = str -> str.toUpperCase();
    5. BiFunction composedFunction = addAndToString.andThen(toUpperCase);
    6. int input1 = 2;
    7. int input2 = 3;
    8. String result = composedFunction.apply(input1, input2);
    9. System.out.println(result); // 输出:"5"
    10. }

    在上面的示例中,我们定义了一个addAndToString函数,它接受两个整数作为输入,并将它们的和转换为字符串。然后,我们定义了一个toUpperCase函数,它接受一个字符串作为输入,并将其转换为大写。接下来,我们使用andThen方法将两个函数组合成一个新的函数composedFunction。最后,我们调用composedFunction对输入整数2和3进行操作,并打印结果"5"。首先将输入整数2和3相加得到5,然后将5转换为字符串"5",最后将字符串"5"转换为大写"5",最终输出结果为"5"。

    Predicate

            Predicate 是 Java 中的一个函数式接口,它位于 java.util.function 包中。这个接口用于表示一个参数的谓词(即,条件判断),接收一个参数并返回一个布尔值,通常用于判断参数是否满足指定的条件

    1. @FunctionalInterface
    2. public interface Predicate {
    3. boolean test(T t);
    4. default Predicate and(Predicatesuper T> other) {
    5. Objects.requireNonNull(other);
    6. return (t) -> test(t) && other.test(t);
    7. }
    8. default Predicate negate() {
    9. return (t) -> !test(t);
    10. }
    11. default Predicate or(Predicatesuper T> other) {
    12. Objects.requireNonNull(other);
    13. return (t) -> test(t) || other.test(t);
    14. }
    15. static Predicate isEqual(Object targetRef) {
    16. return (null == targetRef)
    17. ? Objects::isNull
    18. : object -> targetRef.equals(object);
    19. }
    20. @SuppressWarnings("unchecked")
    21. static Predicate not(Predicatesuper T> target) {
    22. Objects.requireNonNull(target);
    23. return (Predicate)target.negate();
    24. }
    25. }

            Predicate接口的主要方法是 test(),它接收一个参数并返回一个布尔值。下面是一个简单的例子:

    1. @Test
    2. public void test3(){
    3. Student student = new Student("张三");
    4. Predicate predicate= obj -> "张三".equals(obj.getName());
    5. boolean flag = predicate.test(student);
    6. Assert.isTrue(flag,"test fail");
    7. boolean flag2 = predicate.test(new Student("李四"));
    8. Assert.isTrue(flag2,"test fail");
    9. }

    Predicate:常用的四个方法:

    • boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值。
    • default Predicate negate():返回一个逻辑的否定,对应逻辑非。
    • default Predicate and(Predicate other):返回一个组合判断,对应短路与。
    • default Predicate or(Predicate other):返回一个组合判断,对应短路或。
    1. @Test
    2. public void test4(){
    3. Student student = new Student("张三");
    4. Predicate predicate= obj -> "张三".equals(obj.getName());
    5. Predicate predicate2= obj-> "李四".equals(obj.getName());
    6. Predicate or = predicate2.or(predicate);
    7. boolean flag = or.test(student);
    8. Assert.isTrue(flag,"test fail");
    9. student.setName("李四");
    10. boolean flag2 = or.test(student);
    11. Assert.isTrue(flag2,"test fail");
    12. Predicate predicate3=obj->18==obj.getAge();
    13. student.setAge(18);
    14. Predicate and = predicate3.and(predicate2);
    15. boolean flag3 = and.test(student);
    16. Assert.isTrue(flag3,"test fail");
    17. student.setName("铁蛋");
    18. boolean test = and.test(student);
    19. Assert.isTrue(test,"学生姓名不等于张三或者李四");
    20. }

    Consumer

            Consumer接口代表了一个接受输入参数并返回void的函数。它的主要作用是消费输入数据,也就是说,对输入进行某种操作,但不返回任何结果。

    1. @FunctionalInterface
    2. public interface Consumer {
    3. void accept(T t);
    4. default Consumer andThen(Consumersuper T> after) {
    5. Objects.requireNonNull(after);
    6. return (T t) -> { accept(t); after.accept(t); };
    7. }
    8. }

            Consumer接口的主要方法是void accept(T t):对给定的参数执行此操作。

    1. @Test
    2. public void test2() {
    3. Student student = new Student("zhangsan");
    4. Consumer nameConsumer = str -> student.setName(str);
    5. nameConsumer.accept("lisi");//设置学生的姓名为拼音-小写
    6. log.info(student.getName());
    7. Assert.isTrue("lisi".equals(student.getName()), "test fail!");
    8. }

            Consumer接口的默认实现,andThen方法,用于将两个Consumer合并在一起。它允许你将一个操作(即第二个Consumer)附加到另一个操作(即第一个Consumer)的后面,以便在原始操作完成之后执行附加操作。

            下面是一个简单的示例,演示如何使用andThen方法:

    1. @Test
    2. public void test2() {
    3. Student student = new Student("zhangsan");
    4. Consumer nameConsumer = str -> student.setName(str);
    5. Consumer nameConsumer2 = name -> student.setName(name.toUpperCase());
    6. Consumer nameConsumer3 = nameConsumer.andThen(nameConsumer2);//设置学生的姓名为拼音-大写
    7. nameConsumer3.accept("lisi");
    8. log.info(student.getName());
    9. Assert.isTrue("LISI".equals(student.getName()), "test fail!");
    10. }

    Supplier

            这个接口表示一个不接受任何参数但返回结果的函数

    1. @FunctionalInterface
    2. public interface Supplier {
    3. T get();
    4. }

            特点:

    • 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据。
    • Supplier接口也称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。

            使用示例:        

    1. private String getStuName(Supplier supplier) {
    2. String name = supplier.get().getName();
    3. return name;
    4. }
    5. @Test
    6. public void test() {
    7. String name = this.getStuName(() -> new Student("zhangsan"));
    8. log.info(name);
    9. Assert.isTrue(name.equals("zhangsan"), "test fail");
    10. }

  • 相关阅读:
    使用微信小程序编写会议OA项目-首页
    051:mapboxGL改变bearing和pitch,变换查看视角
    初始Cpp之 五、函数
    Windows10源码编译安装RDKit
    Redis环境配置
    向openssl中添加一个最简单的算法
    国内首款研发领域 AI 项目管理工具发布:PingCode AI
    Selective Search学习笔记
    状态机动态规划之股票问题总结
    线上接口处理突然超时
  • 原文地址:https://blog.csdn.net/fox9916/article/details/134481164