A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

day13 Stream 方法引用今日内容    函数式编程:

            Stream流式思想:
                    先编写所有处理方案, 最后再统一执行方案
                    应用场景: 简化对集合/数组复杂操作的代码
                    API
            方法引用:
                    简化Lambda表达式, 直接引用一个已经存在的方法(成员方法, 静态方法, 构造方法)Stream流传统方式遍历集合进行过滤知识点:    传统方式过滤集合中的元素, 有哪些代码显得重复冗余总结:     传统方式过滤集合中的元素, 要写很多次for循环, 代码重复冗余补充:    public class Demo01List {
        public static void main(String[] args) {
            //创建一个List集合,存储姓名
            List<String> list = new ArrayList<>();
            list.add("张无忌");
            list.add("周芷若");
            list.add("赵敏");
            list.add("张强");
            list.add("张三丰");

            // 第一次过滤: 只要以张开头的元素, 存储到一个新的集合中
            List<String> listA = new ArrayList<>();
            for(String s : list){  // 外部迭代
                if(s.startsWith("张")){  // boolean startsWith("字符串")    endsWith()
                    listA.add(s);
                }
            }

            // 第二次过滤: 只要姓名长度为3的人, 存储到一个新集合中
            List<String> listB = new ArrayList<>();
            for (String s : listA) {
                if(s.length()==3){
                    listB.add(s);
                }
            }

            // 遍历查看结果
            for (String s : listB) {
                System.out.println(s);
            }
        }
    }使用Stream流式思想遍历集合进行过滤知识点:    感受函数式编程中提供的Stream流式思想对集合过滤操作的简化总结:     Stream流式思想:
            JDK 8 出现, 是函数式编程中的一大特性
            关注做什么, 而不是怎么做补充:    public class Demo02Stream {
        public static void main(String[] args) {
            //创建一个List集合,存储姓名
            List<String> list = new ArrayList<>();
            list.add("张无忌");
            list.add("周芷若");
            list.add("赵敏");
            list.add("张强");
            list.add("张三丰");

            // 使用Stream流式操作
            list.stream()
                            .filter(name -> name.startsWith("张"))       // 第一次过滤: 只要以张开头的元素
                            .filter(name -> name.length()==3)           // 第二次过滤: 只要姓名长度为3的人
                            .forEach(name -> System.out.println(name)); // 遍历查看结果
            }
    }流式思想概述知识点:    Stream流式思想是如何处理数据的
    流相比于集合有什么优点
    使用Stream流的步骤是什么
    流的数据源可以是什么总结:     Stream流式思想处理数据的方式:
            让代码的执行像流水线一样, 先设计好处理方案, 然后一按开关开始执行
            
    流相比于集合的2个优点:
            1. Pipelining(管道特性): "可以链式调用"
                    Stream流对象的 延迟方法 调用后, 会返回新的Stream流对象, 可以链式调用
                    每个方法类似于一条一条的管道, 衔接了不同的处理方案
            2. 内部迭代特性: "不用写for循环"
                    集合遍历通过 Iterator 或者 增强for, 显式的在集合外部进行迭代, 这叫做外部迭代
                    Stream提供了内部迭代的方法 forEach(Consumer c), 可以直接调用遍历方法

    使用Stream流的3个步骤:
            1. 获取数据源 (从"集合"或"数组"转换为"Stream"对象)
            2. 数据处理 (调用延迟方法, 编写处理方案)
            3. 获得结果 (调用终结方法, 启动开关)补充:    2种获取Stream流的方式知识点:    怎样将"集合"转换为Stream流对象
    怎样将"数组"转换为Stream流对象总结:     获取Stream流对象的2种方式:
            1. 利用"Collection接口"中的默认方法 default Stream<E> stream() 方法: 集合转Stream对象
            2. 利用"Stream接口"中的静态方法 static <T> Stream<T> of(T... values): 数组转Stream对象
            
    java.util.Collection<E>接口:
            // 默认方法
            default Stream<E> stream(): 将"集合"转换为Stream对象
            
    java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型
            // 静态方法
            static<T> Stream<T> of(T... values): 将"数组"转换为Stream对象补充:    // 集合转换为Stream流对象
    List<String> list = new ArrayList<>();
    Stream<String> listStream = list.stream();                          // List集合的Stream

    Set<String> set = new HashSet<>();
    Stream<String> setStream = set.stream();                            // Set集合的Stream

    Map<String,String> map = new HashMap<>();
    Stream<String> keyStream = map.keySet().stream();                   // 键的集合的Stream
    Stream<String> valueStream = map.values().stream();                 // 值的集合的Stream
    Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();// 键值对Stream


    // 数组转换为Stream流对象
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);            

    String[] array = {"a", "b", "c"};
    Stream<String> arrayStream = Stream.of(array);Stream API: 方法分类, forEach()遍历知识点:    什么样的方法属于"延迟方法", 返回值类型有什么特点
    什么样的方法属于"终结方法", 返回值类型有什么特点
    void?forEach(Consumer<??super?T>?action) 方法属于哪种, 有什么作用, 传什么参数总结:     延迟方法: (具有延迟执行的特性)
            返回值类型"是Stream"类型的方法, 支持链式调用
                    Stream filter(): 过滤
                    Stream map(): 映射/转换
                    Stream limit(): 截取
                    Stream skip(): 跳过
    终结方法:
            返回值类型"不是Stream"类型的方法, 不支持链式调用
            void forEach(): 遍历
            long count(): 统计
            
    注意:
            除了终结方法外, 其余方法均为延迟方法

               -------------------------------------------------
    创建数据源-> filter()过滤 | map()映射 | limit()截取 | skip()跳过 -> forEach() | count()结果
               -------------------------------------------------  
      获取流                            转换                                  聚合
                                     (延迟方法)                            (终结方法)
    new ArrayList().stream().filter(...).map(...).limit(...).skip(...).forEach(...);
    Stream.of(1,2,3).filter(...).map(...).limit(...).skip(...).count();


    java.util.stream.Stream<T>接口: 管道接口
            // 抽象方法
            void?forEach(Consumer<??super?T>?action): 遍历流中的元素进行逐一消费. 并不保证元素的逐一消费动作在流中是被有序执行的补充:    public class Demo02Stream_forEach {
        public static void main(String[] args) {
            //获取一个Stream流
            Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六", "田七");

            //使用Stream流中的方法forEach对Stream流中的数据进行遍历
            stream.forEach((String name)->{
                System.out.println(name);
            });

            stream.forEach(name->System.out.println(name));
        }
    }Stream API: filter()过滤知识点:    Stream<T>?filter(Predicate<??super?T>?predicate) 方法有什么作用, 如何使用总结:     java.lang.String类:
            boolean startsWith(String prefix): 判断当前字符串是否以参数字符串开头

    java.util.stream.Stream<T>接口: 管道接口
            // 抽象方法
            
    }Stream流的特点: 只能使用一次知识点:    每次调用延迟方法返回的Stream流对象, 是同一个流对象吗总结:     每次调用延迟方法返回的Stream流对象, 都是经过处理后返回的"新的Stream流对象"
    之前的Stream流在调用方法后, 已经使用过并关闭了, 不能再次使用, 否则会抛出异常:
            java.lang.IllegalStateException: stream has already been operated upon or closed补充:    Stream API: map()映射转换知识点:    <R>?Stream<R>?map(Function<T,?R>?mapper) 方法有什么作用, 如何使用总结:     java.util.stream.Stream<T>接口: 管道接口
            // 抽象方法
            <R>?Stream<R>?map(Function<T,?R>?mapper): 将当前流中的T类型的元素, 转换R类型元素, 放入新流并返回补充:    5分钟练习: 使用map()转换数组元素    需求:
    定义字符串数组: {"1", "2", "3", "4"}
    将数组转换为Stream流, 使用 map() 方法将流中的字符串都转换为int, 遍历输出转换后的结果示例:    public class Test {
        public static void main(String[] args) {
            String[] arr = {"1", "2", "3", "4"};
            Stream<String> stream1 = Stream.of(arr);
            Stream<Integer> stream2 = stream1.map((String num) -> {  // 元素从String 转换为 Integer. 返回流的泛型也要变化
                return Integer.parseInt(num);
            });
            stream2.forEach((Integer i) -> {
                System.out.println(i);
            });

            System.out.println("-----------------");

            // 使用链式调用, 更加方便
            Stream.of("1", "2", "3", "4")
                    .map(num -> Integer.parseInt(num))
                    .forEach(i -> System.out.println(i));
        }
    }Stream API: count()统计流中元素个数知识点:    long count() 方法有什么作用, 如何使用总结:     java.util.stream.Stream<T>接口: 管道接口
            // 抽象方法
            long count(): 获取流中的元素个数 (终结方法)补充:    5分钟练习: 使用count()统计个数    需求:
    创建一个ArrayList集合, 存储整数: 1,2,3,4,5,6,7

    }Stream API: limit()获取前n个(只要前n个)知识点:    Stream<T> limit(long maxSize) 方法有什么作用, 如何使用总结:     java.util.stream.Stream<T>接口: 管道接口
            // 抽象方法
            Stream<T> limit(long maxSize): 从流中获取前maxSize个. 如果maxSize大于等于元素个数, 则返回所有元素的流补充:    5分钟练习: 使用limit()获取数组中前3个元素    需求:
    创建字符串数组: {"美羊羊", "喜羊羊", "懒羊羊", "灰太狼", "红太狼"}
    将数组转换为Stream流, 从流中获取前3个元素, 将截取后的流遍历打印输出到控制台代码:    public class Test {
        public static void main(String[] args) {
            Stream.of("美羊羊", "喜羊羊", "懒羊羊", "灰太狼", "红太狼")
                    .limit(3)    // 只要前3个
    //                .limit(0)    // 只要前0个 = 全都不要
    //                .limit(30)    // 只要前30个, 比流中的元素个数多, 所以全都返回
    //                .limit(-2)    // 负数抛出异常 java.lang.IllegalArgumentException: -2
                    .forEach(s -> System.out.println(s));
        }
    }Stream API: skip()跳过前n个(不要前n个)知识点:    Stream<T>?skip(long?n) 方法有什么作用, 如何使用总结:     java.util.stream.Stream<T>接口: 管道接口
            // 抽象方法
            Stream<T>?skip(long?n): 从流中跳过n个元素, 获取后面的元素. 如果n大于等于元素个数, 则全都跳过补充:    5分钟练习: 使用skip()跳过数组中的元素    需求:
    创建字符串数组: {"美羊羊", "喜羊羊", "懒羊羊", "灰太狼", "红太狼"}
    将数组转换为Stream流, 从流中跳过前3个元素, 遍历打印输出到控制台代码:    public class Test {
        public static void main(String[] args) {
            Stream.of("美羊羊", "喜羊羊", "懒羊羊", "灰太狼", "红太狼")
    //                .skip(3)    // 不要前3个
    //                .skip(10)    // 不要前10个, 总共就5个, 相当于全都不要
    //                .skip(0)    // 不要前0个, 相当于全要
                    .skip(-1)    // 负数抛异常 java.lang.IllegalArgumentException: -1
                    .forEach(s -> System.out.println(s));
        }
    }Stream API: 静态方法concat()合并两个流知识点:    如何通过concat()方法快速合并2个流总结:     java.util.stream.Stream<T>接口: 管道接口
            // 静态方法
            static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流的元素, 变成一个新的流. 两个流中的元素类型必须相同, 或有共同的父类补充:    5分钟练习: 使用concat()方法合并两个流, 并遍历输出    需求:
    创建2个字符串数组:
            {"张三丰", "张翠山", "赵敏", "周芷若", "张无忌"}
            {"美羊羊", "喜羊羊", "懒羊羊", "灰太狼", "红太狼"}
    将2个数组分别转换为Stream流对象, 并使用Stream的静态方法concat()将2个流拼接为新的流, 遍历打印新流的元素代码:    public class Test {
        public static void main(String[] args) {
            // 将数组1转换为流
            Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
            // 将数组2转换为流
            Stream<String> stream2 = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "灰太狼", "红太狼");
            // 将2个流合并为1个流
            Stream<String> stream3 = Stream.concat(stream1, stream2);
            stream3.forEach(s -> System.out.println(s));

            System.out.println("---------------");

            // 以上代码也可以合并, 将参数变成调用的方法即可, 但是要注意阅读性
            Stream.concat(
                    Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌"),
                    Stream.of("美羊羊", "喜羊羊", "懒羊羊", "灰太狼", "红太狼")
            ).forEach(s -> System.out.println(s));
        }
    }
    }

    java.util.stream.Stream<T>接口: 流
            Object[] toArray(): 将当前Stream流对象转换为Object[]数组
            <R,A> R collect(Collector<? super T,A,R> collector): 将当前Stream流对象根据传入的Collector转换为集合或数组

    java.util.stream.Collectors类: 收集器静态工具类, 提供不同转换方式的Collector
            static <T> Collector<T,?,List<T>> toList(): Stream转List集合  
            static <T> Collector<T,?,Set<T>> toSet(): Stream转Set集合
            static <...> Collector<...> toMap(Function<? super T,? extends K> keyMapper,
                                          Function<? super T,? extends U> valueMapper)
                Stream转Map集合.
                Function keyMapper: 生成key的转换方式
                Function valueMapper: 生成value的转换方式代码示例:    /*
    收集器:
        演示将Stream转换回 List, Set, Map集合, 以及数组
     */
    public class Demo {
        public static void main(String[] args) {
            streamToArray();
    //        streamToList();
    //        streamToSet();
    //        streamToMap();
        }

        // 演示Stream转数组
        private static void streamToArray() {
            Stream<String> stream4 = Stream.of("a", "b", "c", "d", "e");
            Object[] arr = stream4.toArray();
            System.out.println(Arrays.toString(arr));
        }

        // 演示Stream转List
        private static void streamToList() {
            Stream<String> stream1 = Stream.of("a", "b", "c", "d", "e");
            List<String> list = stream1.collect(Collectors.toList());
            System.out.println(list);
        }

        // 演示Stream转Set
        private static void streamToSet() {
            Stream<String> stream2 = Stream.of("a", "b", "c", "d", "e");
            Set<String> set = stream2.collect(Collectors.toSet());
            System.out.println(set);
        }

        // 演示Stream转Map
        private static void streamToMap() {
            Stream<String> stream3 = Stream.of("a", "b", "c", "d", "e");
            Map<String, String> map = stream3.collect(Collectors.toMap(
                    new Function<String, String>() {
                        @Override
                        public String apply(String s) {
                            return s;                // 使用原本的字符串作为key
                        }
                    },
                    new Function<String, String>() {
                        @Override
                        public String apply(String s) {
                            return s.toUpperCase();  // 将字符串转为大写作为value
                        }
                    }
            ));
            // Lambda简化
            /*Map<String, String> map = stream3.collect(
                    Collectors.toMap(s -> s, s -> s.toUpperCase())
            );*/
            System.out.println(map);
        }
    }方法引用方法引用基本介绍知识点:    什么是方法引用
    方法引用用于简化什么
    方法引用的格式是怎样的
    总结:     方法引用: Method Reference
            如果Lambda表达式仅仅是调用一个已经存在的方法, 那就可以通过方法引用来替代Lambda表达式
            作用: 简化Lambda表达式
            :: 方法引用运算符, 它所在的表达式被称为方法引用

    Lambda表达式写法:
            (String s) -> System.out.println(s)   
        参数传递给System.out.println()方法去打印
    方法引用写法:     
            System.out::println
            引用System.out.println()方法中代码, 来作为Lambda中重写方法的实现方式

    注意:
            Lambda中, 重写方法的"参数", 必须是方法引用的方法"要接收的类型", 否则会抛出异常
            (String s) -> System.out.println(s)  方法有个参数String s
        System.out::println                  引用的println方法必须能接收String类型的s

    方法引用能简化以下场景: (方法名后不要写小括号)
                    场景                                                格式                          简化之前的Lambda                        方法引用简化后
            1. 通过对象名引用成员方法     对象名::成员方法名   ()->person.eat()          person::eat
            2. 通过类名引用静态方法       类名::静态方法名     i -> Math.abs(i)          Math::abs
            3. 通过super引用父类成员方法  super::父类方法名   ()->super.eat();          super::eat
            4. 通过this引用本类成员方法   this::本类方法名    ()->this.eat();           this::eat
            5. 引用某个类的构造方法       类名::new          name->new Person(name)    Person::new
            6. 引用创建数组的方法         数据类型[]::new    length->new int[length];  int[]::new补充:    @FunctionalInterface
    public interface Printable {
        //定义字符串的抽象方法
        void print(String s);
    }

    public class Demo01Printable {

        //定义一个方法,参数传递Printable接口,对字符串进行打印
        public static void printString(Printable p){
            p.print("HelloWorld");
        }

        public static void main(String[] args) {
            // 匿名内部类方式
            printString(new Printable(){
                @Override
                public void print(String s){
                    System.out.println(s);
                }
            });

            //Lambda方式
            printString((s)->{
                System.out.println(s);  // 只是调用了一个已经存在的System.out.println()
            });

                    // 方法引用
            printString(System.out::println);
        }
    }方法引用: 通过对象名引用成员方法知识点:    通过对象名引用成员方法的格式怎么写
    这种方式适用于什么场景
    总结:     通过对象名引用成员方法
            对象名::成员方法名
            
    适用场景:
            当Lambda表达式中, 仅仅是"通过某个对象, 调用已有的方法"时, 就可以用这种方式简化补充:    // 定义函数式接口: 模拟Java中已经提供的函数式接口
    @FunctionalInterface
    public interface Printable {
            // 定义功能: 打印s. 如何打印需要我们传递Lambda实现
        void print(String s);
    }

    // 定义一个类: 模拟Java中已经定义好的类和方法
    public class MethodRefObject {
        // 成员方法: 将字符串变大写再打印出来
        public void printUpperCaseString(String str){
            System.out.println(str.toUpperCase());
        }
    }

    public class Test {

        // 定义方法: 用于打印Hello, 参数为 打印字符串的方式
        public static void printString(Printable lambda){
            lambda.print("Hello");
        }

        public static void main(String[] args) {
                    // 普通Lambda方式
            printString((s)->{
                              // 创建对象, 调用已经存在方法printUpperCase
                MethodRefObject obj  = new MethodRefObject();
                obj.printUpperCaseString(s);
            });

            // 使用方法引用简化
            MethodRefObject obj = new MethodRefObject();
            printString(obj::printUpperCaseString);  
            // 直接引用obj的printUpperCaseString方法作为抽象方法print的实现
        }
    }5分钟练习: 简化对象调用方法    需求:
    已知如下代码, 请在Test类中补全main()方法, 分别使用Lambda和方法引用调用printString方法

    // 定义函数式接口: 模拟Java中已经提供的函数式接口
    @FunctionalInterface
    public interface Printable {
            // 定义功能: 打印s. 如何打印需要我们传递Lambda实现
        void print(String s);
    }

    // 定义一个类: 模拟Java中已经定义好的类和方法
    public class MethodRefObject {
        // 将字符串变大写再打印出来
        public void printUpperCaseString(String str){
            System.out.println(str.toUpperCase());
        }
    }

    public class Test {

        // 定义方法用于打印Hello, 参数为 打印字符串的方式
        public static void printString(Printable lambda){
            lambda.print("Hello");
        }

        public static void main(String[] args) {
                    // TODO 补全代码. 普通Lambda方式调用printString方法: 创建MethodRefObject对象, 调用已经存在方法printUpperCase


            // TODO 补全代码. 方法引用方式调用printString方法: 创建MethodRefObject对象, 直接引用obj的printUpperCaseString方法

        }
    }代码:    public class Test {

        // 定义方法用于打印Hello, 参数为 打印字符串的方式
        public static void printString(Printable lambda){
            lambda.print("Hello");
        }

        public static void main(String[] args) {
            // TODO 补全代码. 普通Lambda方式调用printString方法: 创建MethodRefObject对象, 调用已经存在方法printUpperCase
            printString((String s) -> {
                MethodRefObject obj = new MethodRefObject();
                obj.printUpperCaseString(s);
            });

            // TODO 补全代码. 方法引用方式调用printString方法: 创建MethodRefObject对象, 直接引用obj的printUpperCaseString方法
            // 对象是现成的, 打印大写字符串的方法也已经定义好了, 可以使用方法引用来简化
            MethodRefObject obj = new MethodRefObject();
            printString(obj::printUpperCaseString);  // 通过现有的对象, 引用现有的方法

        }
    }方法引用: 通过类名引用静态方法知识点:    通过类名引用静态方法的格式怎么写
    这种方式适用于什么场景
    总结:     通过类名引用静态方法
            类名::静态方法名  Math.abs(1)   Math::abs
            
    适用场景:
            当Lambda表达式中, 仅仅是"通过某个类名, 调用已有的静态方法"时, 就可以用这种方式简化补充:    // 定义函数式接口: 模拟Java中已经提供的函数式接口
    @FunctionalInterface
    public interface Calcable {
        // 计算整数的绝对值并返回. 怎么计算需要我们传递Lambda来实现
        int calcAbs(int number);
    }

    public class Test {

        //定义方法: 用来计算一个数的结果. 参数: 被计算的整数 和 计算的方式
        public static int method(int number, Calcable c){
           return c.calcAbs(number);
        }

        public static void main(String[] args) {
            // Lambda方式
            int number = method(
                -10,
                (n)->{
                    return Math.abs(n);  //对参数进行绝对值得计算并返回结果
                });
            System.out.println(number);

            // 方法引用
            int number2 = method(-10, Math::abs); //直接引用Math类中的abs方法
            System.out.println(number2);
        }
    }
总结:     通过super引用父类成员方法
            super::父类方法名
            
    适用场景
            当Lambda表达式中, 仅仅是"在子类中, 调用父类某个已有的方法"时, 就可以用这种方式简化补充:    // 定义见面打招呼的函数式接口: 模拟Java中已经提供的函数式接口
    @FunctionalInterface
    public interface Greetable {
        // 见面打招呼的方法. 具体怎么打招呼需要传递Lambda实现
        void greet();
    }

    // 定义父类: 人类
    public class Human {
        //父类方法: 打招呼
        public void sayHello(){
            System.out.println("Hello 我是Human!");
        }
    }

    // 定义子类: 男人类, 继承人类
    public class Man extends Human {

        // 子类重写了父类打招呼的方法
        @Override
        public void sayHello() {
            System.out.println("Hello 我是Man!");
        }

        //定义方法用来见面打招呼. 参数是 打招呼的方式
        public void method(Greetable g){
            g.greet();
        }

        // 因为super只能在非静态方法内使用, 所以定义了一个成员方法
        public void show(){
            // Lambda方式: 创建父类对象, 用父类对象调用方法
            method(()->{
                Human h = new Human();   // 创建父类Human对象
                h.sayHello();            // 调用父类的sayHello方法
            });

            // Lambda方式: 直接使用super调用父类方法, 省去创建父类对象的麻烦
            method(()->{
                super.sayHello();        // 直接使用super调用父类的sayHello方法
            });

                    // 方法引用方式: 直接引用父类的sayHello方法作为greet抽象方法的实现
                    method(super::sayHello);    // 其实就是 对象名::成员方法名 只不过对象用super代表
        }

        public static void main(String[] args) {
            new Man().show();
        }
    }方法引用: 通过this引用本类成员方法知识点:    通过this引用本类成员方法的格式是怎样的
    这种方式适用于什么场景
    总结:     通过this引用本类成员方法
            this::本类方法名
            
    适用场景:
            当Lambda表达式中, 仅仅是"调用本类中, 某个已有的方法"时, 就可以用这种方式简化补充:    }   
总结:     引用某个类的构造方法
            类名::new

    使用场景
            当Lambda表达式中, 仅仅是"调用某个类的构造方法, 来创建一个对象"时, 就可以用这种方式简化补充:    // Person类
    public class Person {
        private String name;

        public Person() {
        }

        public Person(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    // 定义用于创建Person对象的函数式接口, 模拟Java中已经提供的函数式接口
    @FunctionalInterface
    public interface PersonBuilder {  // Function转换
        // 根据姓名创建Person对象, 怎么创建需要Lambda来实现
        Person builderPerson(String name);
    }

    // 测试类
    public class Test {

        // 定义方法, 用于根据传入的姓名创建一个Person对象并打印名称
        // 参数: 姓名 和 创建Person对象的方式
        public static void printName(String name, PersonBuilder pb){
            Person person = pb.builderPerson(name);
            System.out.println(person.getName());
        }

        public static void main(String[] args) {
            // Lambda方式: 传递姓名和创建对象的方式
            printName("迪丽热巴",(String name)->{
                return new Person(name);  // 仅仅调用了Person类的构造方法
            });

            // 方法引用方式: 直接引用Person类的构造方法
            printName("古力娜扎",Person::new);
        }
    }5分钟练习: 引用类的构造方法    需求:
    已知如下代码, 请补全Test类中main方法的代码, 分别使用Lambda和方法引用调用printName方法:
    // Person类
    public class Person {
        private String name;

        public Person() {
        }

        public Person(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    // 定义用于创建Person对象的函数式接口, 模拟Java中已经提供的函数式接口
    @FunctionalInterface
    public interface PersonBuilder {
        // 根据姓名创建Person对象, 怎么创建需要Lambda来实现
        Person builderPerson(String name);
    }

    // 测试类
    public class Test {

        // 定义方法, 用于根据传入的姓名创建一个Person对象并打印名称
        // 参数: 姓名 和 创建Person对象的方式
        public static void printName(String name,PersonBuilder pb){
            Person person = pb.builderPerson(name);
            System.out.println(person.getName());
        }

        public static void main(String[] args) {
            // TODO 补全代码. Lambda方式调用printName方法: 传递"迪丽热巴"和创建Person对象的方式


            // TODO 补全代码. 方法引用方式调用printName方法: 传递"迪丽热巴", 直接引用Person类的构造方法

        }
    }代码:    public class Test {

        // 定义方法, 用于根据传入的姓名创建一个Person对象并打印名称
        // 参数: 姓名 和 创建Person对象的方式
        public static void printName(String name,PersonBuilder pb){
            Person person = pb.builderPerson(name);
            System.out.println(person.getName());
        }

        public static void main(String[] args) {
            // TODO 补全代码. Lambda方式调用printName方法: 传递"迪丽热巴"和创建Person对象的方式
            printName(
                    "迪丽热巴",
                    (String name) ->{
                        return new Person(name);
                    }
                    );

            // TODO 补全代码. 方法引用方式调用printName方法: 传递"迪丽热巴", 直接引用Person类的构造方法
            printName(
                    "古力娜扎",
                    Person::new
            );
        }
    }总结:     引用创建数组的方法
            数据类型[]::new

    使用场景
            当Lambda表达式中, 仅仅是"创建一个数组对象"时, 就可以用这种方式简化补充:    // 定义创建数组的函数式接口, 模拟Java中已经提供的函数式接口
    @FunctionalInterface
    public interface ArrayBuilder {
        // 根据指定length长度, 创建一个int[]数组. 怎么创建需要我们传递Lambda实现
        int[] builderArray(int length);
    }

    // 测试类
    public class Test {

        // 定义方法用于创建数组
        // 参数: 数组的长度 和 创建数组的方式
        public static int[] createArray(int length, ArrayBuilder ab){
            return ab.builderArray(length);
        }

        public static void main(String[] args) {
            // Lambda方式: 传递长度10, 以及创建数组的Lambda表达式
            int[] arr1 = createArray(
                10,
                (int len)->{
                    return new int[len];
                });
            System.out.println(arr1.length); //10

            // 方法引用方式: 传递长度10, 和数组的构造方法
            int[] arr2 = createArray(10, int[]::new);
            System.out.println(arr2.length); //10
        }
    }
    }

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马