• 面试题精讲:你所不知道的Lambda表达式和常用的函数式接口


    一. 什么Lambda表达式

    Lambda表达式是JDK1.8中新增的一种方式,用于替代匿名内部类,该表达式可以让开发人员更加关注于具体需要传递的方法,而不是因为需要传递一个方法而创建一个对象。

    二. Lambda表达式

    1.基本语法

    Lambda省去⾯向对象的条条框框,格式由3个部分组成:

    参数部分

    箭头

    代码块

    比如:(参数类型 参数名称) -> { 代码语句 }

    2.格式说明

    ⼩括号内的语法与传统⽅法参数列表⼀致:⽆参数则留空;多个参数则⽤逗号分隔;

    -> 是新引⼊的语法格式,代表指向动作;

    ⼤括号内的语法与传统⽅法体要求基本⼀致。

    3.Lambda的省略格式

    所谓的Lambda表达式的省略原则是:可推导即可省略。

    Lambda强调的是“做什么”⽽不是“怎么做”,所以凡是可以根据上下⽂推导得知的信息,都可以省略。

    3.1 省略规则

    在Lambda标准格式的基础上,使⽤省略写法的规则为:

    • ⼩括号内参数的类型可以省略;

    • 如果⼩括号内有且仅有⼀个参,则⼩括号可以省略;

    • 如果⼤括号内有且仅有⼀个语句,则⽆论是否有返回值,都可以省略⼤括号、return关键字及语句、分号。

    4.Lambda的使用前提

    Lambda的语法⾮常简洁,完全没有⾯向对象复杂的束缚,但是使⽤时有⼏个问题需要特别注意:

    • 使⽤Lambda必须具有接⼝,且要求接口中有且仅有⼀个抽象方法。⽆论是JDK内置的Runnable 、 Comparator 接⼝还是⾃定义的接⼝,只有当接⼝中的抽象⽅法存在且唯⼀时,才可以使⽤Lambda。

    • 使⽤Lambda必须具有上下推断。也就是⽅法的参数或局部变量类型必须为Lambda对应的接⼝类型,才能使⽤Lambda作为该接⼝的实例。

    5.常用函数式接口

    JDK提供了⼤量常⽤的函数式接⼝以丰富Lambda的典型使⽤场景,它们主要在 java.util.function

    包中被提供. 常用的函数式接口包括以下四个。

    5.1 Supplier接口

    java.util.function.Supplier 接⼝仅包含⼀个⽆参的⽅法:T get() 。⽤来获取⼀个泛型参数,可以指定类型的对象数据。由于这是⼀个函数式接⼝,这也就意味着对应的Lambda表达式需要“对外提供”⼀个符合泛型类型的对象数据。

    5.1.1 基本使用方式如下

    1. public class SupplierDemo {
    2. //    为了获取一个int类型的数据
    3.     private static int getNum(Supplier<Integer> supplier) {
    4. //        get方法 -- 返回一个指定数据类型 T 的数据
    5.         return supplier.get();
    6.     }
    7.     public static void main(String[] args) {
    8. //        int num = getNum(new Supplier<Integer>() {
    9. //            @Override
    10. //            public Integer get() {
    11. //                return 50;
    12. //            }
    13. //        });
    14.         System.out.println(getNum(() -> 50));
    15. //        1. 获取30  60 两个数字中的最大值
    16. //        getNum(new Supplier<Integer>() {
    17. //            @Override
    18. //            public Integer get() {
    19. //                return Math.max(30,  60);
    20. //            }
    21. //        });
    22.         getNum(()->Math.max(3060));
    23. //        有一个数组
    24.         int[] nums = {1,5,4,8,4,51,2,1,6,8};
    25. //        通过getNum方法获取数组的最大值
    26. //        getNum(new Supplier<Integer>() {
    27. //            @Override
    28. //            public Integer get() {
    29. //                Arrays.sort(nums);
    30. //                return nums[nums.length - 1];
    31. //            }
    32. //        });
    33.         int num = getNum(() -> {
    34.             Arrays.sort(nums);
    35.             return nums[nums.length - 1];
    36.         });
    37.         System.out.println(num);
    38.     }
    39. }

    5.2 Consumer接口

    java.util.function.Consumer 接⼝则正好与Supplier接⼝相反,它不是⽣产⼀个数据,⽽是消费⼀个数据,其数据类型由泛型决定。

    • Consumer接口中包含抽象⽅法 void accept(T t) ,意思是说消费⼀个执⾏泛型的数据

    • Consumer 接⼝中包含默认⽅法:andThen

    如果⼀个⽅法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,⾸先做⼀个操作, 然后再做另⼀个操作,实现组合。⽽这个⽅法就是 Consumer 接⼝中的default⽅法 andThen。

    5.2.1 下⾯是JDK的源代码:

    1. default Consumer<T> andThen(Consumer<super T> after) {
    2.  Objects.requireNonNull(after);
    3.  return (T t) -> { accept(t); after.accept(t); };
    4.  }
    5. 基本使用方式如下:
    6. public class ConsumerDemo {
    7. //    使用一个指定的String类型的数据
    8.     private static void useString(Consumer<String> consumer, String string){
    9.         consumer.accept(string);
    10.     }
    11.     private static void useString(Consumer<String> consumer, Supplier<String> supplier) {
    12.         consumer.accept(supplier.get());
    13.     }
    14. //    返回的Consumer对象的目的 -- 使用accept方法接收参数,传递给first和second使用
    15.     private static Consumer<String> andThen(Consumer<String> first, Consumer<String> second){
    16.         return new Consumer<String>() {
    17.             @Override
    18.             public void accept(String s) {
    19.                 first.accept(s);
    20.                 second.accept(s);
    21.             }
    22.         };
    23.     }
    24.     private static void andThenTest(Consumer<String> first, Consumer<String> second, String string){
    25. //        Consumer<String> then = first.andThen(second);
    26. //        then.accept(string);
    27. //        前后两个接口对象之间,没有数据上的联系
    28. //        两个接口 分别处理的都是原本的数据
    29.         first.andThen(second).accept(string);
    30.         System.out.println("---------");
    31.         Consumer<String> consumer = andThen(first, second);
    32.         consumer.accept(string);
    33.     }
    34.     public static void main(String[] args) {
    35. //        useString(new Consumer<String>() {
    36. //            @Override
    37. //            public void accept(String s) {
    38. //                System.out.println(s.length());
    39. //            }
    40. //        }, "lambda");
    41. //        useString((String s)->{
    42. //            System.out.println(s.length());
    43. //        }, "lambda");
    44.         useString(s->System.out.println(s.length()), "lambda");
    45. //        useString(s-> System.out.println(s), "lambda");
    46. //        useString(System.out::println, "lambda");
    47.         useString(s-> {
    48.             System.out.println(s.concat(Integer.valueOf(s.length()).toString()));
    49.             System.out.println(s + s.length());
    50.         }, "lambda");
    51.         useString(s->{
    52.             System.out.println(s.length());
    53.         },()->{
    54.             return "123456oiuytr";
    55.         });
    56.         andThenTest(s -> System.out.println(s.toUpperCase()),
    57.                 s->System.out.println(s.substring(03)), "lambda Exp");
    58.     }
    59. }

    5.3 Predicate接口

    有时候我们需要对某种类型的数据进⾏判断,从⽽得到⼀个boolean值结果。这时可以使

    • ⽤java.util.function.Predicate接⼝。

    • Predicate 接⼝中包含⼀个抽象⽅法:boolean test(T t)

    • 该接口也存在三个默认的方法,分别是and 、 or 和negate, 分别表示与 、或 、非三种逻辑处理。

    5.3.1 接口代码示例

    1. public class PredicateDemo {
    2.     private static boolean testMethod(Predicate<String> predicate, String s){
    3. //        test方法返回一个boolean类型的数据
    4.         return predicate.test(s);
    5.     }
    6.     private static boolean andMethod(Predicate<String> first, Predicate<String> second, String s){
    7.         return first.and(second).test(s);
    8.     }
    9.     private static boolean orMethod(Predicate<String> first, Predicate<String> second, String s) {
    10.         return first.or(second).test(s);
    11.     }
    12.     private static boolean negateMethod(Predicate<String> predicate, String s) {
    13.         return predicate.negate().test(s);
    14.     }
    15.     public static void main(String[] args) {
    16. //        1. 判断一个字符串是否是由txt结尾的
    17. //        boolean result = testMethod(new Predicate<String>() {
    18. //            @Override
    19. //            public boolean test(String s) {
    20. //                return s.endsWith("txt");
    21. //            }
    22. //        }, "newFile");
    23. //        boolean result = testMethod((String s)->{
    24. //                return s.endsWith("txt");
    25. //        }, "newFile");
    26.         boolean result = testMethod(s->s.endsWith("txt"), "newFile");
    27.         System.out.println(result);
    28.         boolean r1 = andMethod(s -> s.length() > 6,
    29.                 s -> s.startsWith("a"), "asijhgvbnm");
    30.         boolean r2 = orMethod(s -> s.length() > 6,
    31.                 s -> s.equals("abcd"), "asdfghjkl");
    32.         boolean r3 = negateMethod(s -> s.endsWith("a"), "asdfghjkl");
    33.         System.out.println(r1 + " - " + r2 + " - " + r3);
    34.     }
    35. }

    5.4 Function接口

    java.util.function.Function接⼝⽤来根据⼀个类型的数据得到另⼀个类型的数据,前者称为前置条件,后者称为后置条件。

    • Function 接⼝中最主要的抽象⽅法是:R apply(T t) ,根据类型T的参数获取类型R的结果。

    • Function接⼝中有⼀个默认的andThen⽅法,⽤来进⾏组合操作。

    5.4.1 基本使用方式如下

    1. public class FunctionDemo {
    2.     private static void applyMethod(Function<String, Integer> functionString s){
    3.         Integer apply = function.apply(s);
    4.         System.out.println("从字符串" + s + "中获取的integer类型数据是:" + apply);
    5.     }
    6.     private static Function<StringBoolean> andThen(Function<String, Integer> firstFunction<Integer, Boolean> second){
    7. //        T = String; R = Integer; V=Boolean
    8. //        String --> Boolean
    9.         return new Function<StringBoolean>() {
    10.             @Override
    11.             public Boolean apply(String s) {
    12. //                String --> Integer
    13.                 Integer apply = first.apply(s);
    14. //                Integer --> Boolean
    15.                 Boolean apply1 = second.apply(apply);
    16.                 return apply1;
    17.             }
    18.         };
    19.     }
    20.     private static void andThenMethod(Function<String, Integer> firstFunction<Integer, Boolean> second, String s){
    21.         Function<StringBoolean> then = first.andThen(second);
    22. //        因为andThen方法在实现的时候  前面一个的结果给后面一个处理
    23. //        前者T R --> 后者 R V   ==> T  --> V
    24.         Boolean apply = then.apply(s);
    25.         System.out.println(apply);
    26.         System.out.println("------");
    27.         Function<StringBoolean> function = andThen(first, second);
    28.         Boolean b = function.apply(s);
    29.         System.out.println(b);
    30.     }
    31.     public static void main(String[] args) {
    32. //        applyMethod(new Function<String, Integer>() {
    33. //            @Override
    34. //            public Integer apply(String s) {
    35. //                return s.indexOf("a");
    36. //            }
    37. //        }, "fashjkl");
    38. //        applyMethod((String s)->{
    39. //            return s.indexOf("a");
    40. //        }, "fashjkl");
    41.         applyMethod(s->s.indexOf("a"), "fashjkl");
    42.         andThenMethod(s-> s.length(),
    43.                 i -> i > 20"sadfghjkl;");
    44. //        andThenMethod(String::length,
    45. //                i -> i > 20"sadfghjkl;");
    46.     }
    47. }

  • 相关阅读:
    低代码:让软件开发不再遥不可及
    毕业设计选题Java+springboot校园新闻资讯系统源码 开题 lw 调试
    MONGO常用操作指令
    基于BP神经网络识别手写字体MINST字符集
    Spring 中BeanFactory和FactoryBean有什么不同之处呢?
    吃透Chisel语言.30.Chisel进阶之通信状态机(二)——FSMD:以Popcount为例
    第23篇 基于Qt实现PID温度加热控制系统
    SAP ABAP教程之 02 创建您的第一份 ABAP 报告 (教程含源码)
    数据结构学习——第一章了解数据结构
    postman-pre-request-scripts使用
  • 原文地址:https://blog.csdn.net/finally_vince/article/details/126991933