黑马程序员技术交流社区

标题: 【石家庄校区】day13 Stream 方法引用 [打印本页]

作者: 849618121    时间: 2018-12-2 15:28
标题: 【石家庄校区】day13 Stream 方法引用
本帖最后由 小石姐姐 于 2018-12-6 17:29 编辑

day13 Stream 方法引用 今日内容
函数式编程:
        Stream流式思想:
                先编写所有处理方案, 最后再统一执行方案
                应用场景: 简化对集合/数组复杂操作的代码
                API
        方法引用:
                简化Lambda表达式, 直接引用一个已经存在的方法(成员方法, 静态方法, 构造方法)
Stream流
传统方式遍历集合进行过滤知识点:
传统方式过滤集合中的元素, 有哪些代码显得重复冗余
总结:
传统方式过滤集合中的元素, 要写很多次for循环, 代码重复冗余

总结:
Stream流式思想:
        JDK 8 出现, 是函数式编程中的一大特性
        关注做什么, 而不是怎么做

总结:
Stream流式思想处理数据的方式:
        让代码的执行像流水线一样, 先设计好处理方案, 然后一按开关开始执行

流相比于集合的2个优点:
        1. Pipelining(管道特性): "可以链式调用"
                Stream流对象的 延迟方法 调用后, 会返回新的Stream流对象, 可以链式调用
                每个方法类似于一条一条的管道, 衔接了不同的处理方案
        2. 内部迭代特性: "不用写for循环"
                集合遍历通过 Iterator 或者 增强for, 显式的在集合外部进行迭代, 这叫做外部迭代
                Stream提供了内部迭代的方法 forEach(Consumer c), 可以直接调用遍历方法使用Stream流的3个步骤:
        1. 获取数据源 (从"集合"或"数组"转换为"Stream"对象)
        2. 数据处理 (调用延迟方法, 编写处理方案)
        3. 获得结果 (调用终结方法, 启动开关)![](./img/饮料流水线.png)
总结:
获取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"类型的方法, 支持链式调用
                Stream filter(): 过滤
                Stream map(): 映射/转换
                Stream limit(): 截取
                Stream skip(): 跳过
终结方法:
        返回值类型"不是Stream"类型的方法, 不支持链式调用
        void forEach(): 遍历
        long count(): 统计
总结:
java.lang.String类:
        boolean startsWith(String prefix): 判断当前字符串是否以参数字符串开头java.util.stream.Stream<T>接口: 管道接口
        // 抽象方法
        Stream<T> filter(Predicate<? super T> predicate): 过滤符合条件的结果. 返回过滤后的流
5分钟练习: 使用filter()过滤数组
需求:
定义字符串数组: {"张三丰", "张翠山", "赵敏", "周芷若", "张无忌"}
将数组转换为Stream对象, 并过滤出姓张的, 并将元素打印出来
代码:
[AppleScript] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // 定义数组
        String[] arr = {"张三丰", "张翠山", "赵敏", "周芷若", "张无忌"};        // 将数组转换成流对象
        Stream<String> stream1 = Stream.of(arr);
        // 过滤姓张的
        Stream<String> stream2 = stream1.filter((String name) -> {
            return name.startsWith("张");  // 如果以张开头, 结果为true, 返回true正好会保留到集合中
        });
        // 遍历打印过滤后的结果
        stream2.forEach((String name) -> {
            System.out.println(name);
        });        System.out.println("---------------");        // 使用链式调用
        Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌")  // 得到流
                .filter(name -> name.startsWith("张"))           // 过滤
                .forEach(name -> System.out.println(name));      // 遍历
    }
}
Stream流的特点: 只能使用一次知识点:
每次调用延迟方法返回的Stream流对象, 是同一个流对象吗
总结:
每次调用延迟方法返回的Stream流对象, 都是经过处理后返回的"新的Stream流对象"
之前的Stream流在调用方法后, 已经使用过并关闭了, 不能再次使用, 否则会抛出异常:
        java.lang.IllegalStateException: stream has already been operated upon or closed
总结:
java.util.stream.Stream<T>接口: 管道接口
        // 抽象方法
        <R> Stream<R> map(Function<T, R> mapper): 将当前流中的T类型的元素, 转换R类型元素, 放入新流并返回
需求:
定义字符串数组: {"1", "2", "3", "4"}
将数组转换为Stream流, 使用 map() 方法将流中的字符串都转换为int, 遍历输出转换后的结果
示例:
[AppleScript] 纯文本查看 复制代码
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流对象, 调用count()获取流中元素的个数, 打印到控制台
代码:
[AppleScript] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // 集合
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        // 集合转Stream
        Stream<Integer> stream = list.stream();
        // 查看个数
        long count = stream.count();
        System.out.println(count);        System.out.println("----------------");        // 使用集合添加元素的简单方法, 和链式调用配合
        long count1 = List.of(1, 2, 3, 4, 5, 6, 7)  // 快速得到集合
                .stream()                           // 转换为Stream
                .count();                           // 统计个数
        System.out.println(count1);
    }
}
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个元素, 将截取后的流遍历打印输出到控制台
代码:
[AppleScript] 纯文本查看 复制代码
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个元素, 遍历打印输出到控制台
代码:
[AppleScript] 纯文本查看 复制代码
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个流拼接为新的流, 遍历打印新流的元素
代码:
[AppleScript] 纯文本查看 复制代码
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));
    }
}
练习: 集合元素处理-传统方式
感受一下传统方式处理集合元素的代码的繁琐冗余需求:
现在有两个ArrayList集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)依次进行以下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。
2. 第一个队伍筛选之后只要前3个人;存储到一个新集合中。3. 第二个队伍只要姓张的成员姓名;存储到一个新集合中。
4. 第二个队伍筛选之后不要前2个人;存储到一个新集合中。5. 将两个队伍合并为一个队伍;存储到一个新集合中。
6. 根据姓名创建Person对象;存储到一个新集合中。
7. 打印整个队伍的Person对象信息
代码:
[Java] 纯文本查看 复制代码
public class Demo01StreamTest {
    public static void main(String[] args) {
        //第一支队伍
        ArrayList<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("石破天");
        one.add("石中玉");
        one.add("老子");
        one.add("庄子");
        one.add("洪七公");

        //1. 第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。
        ArrayList<String> one1 = new ArrayList<>();
        for (String name : one) {
            if(name.length()==3){
                one1.add(name);
            }
        }
        //2. 第一个队伍筛选之后只要前3个人;存储到一个新集合中。
        ArrayList<String> one2 = new ArrayList<>();
        for (int i = 0; i <3 ; i++) {
            one2.add(one1.get(i));//i = 0,1,2
        }        //第二支队伍
        ArrayList<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("赵丽颖");
        two.add("张三丰");
        two.add("尼古拉斯赵四");
        two.add("张天爱");
        two.add("张二狗");
        //3. 第二个队伍只要姓张的成员姓名;存储到一个新集合中。
        ArrayList<String> two1 = new ArrayList<>();
        for (String name : two) {
            if(name.startsWith("张")){
                two1.add(name);
            }
        }
        //4. 第二个队伍筛选之后不要前2个人;存储到一个新集合中。
        ArrayList<String> two2 = new ArrayList<>();
        for (int i = 2; i <two1.size() ; i++) {
            two2.add(two1.get(i)); //i 不包含0 1
        }        //5. 将两个队伍合并为一个队伍;存储到一个新集合中。
        ArrayList<String> all = new ArrayList<>();
        all.addAll(one2);
        all.addAll(two2);        //6. 根据姓名创建Person对象;存储到一个新集合中。
        ArrayList<Person> list = new ArrayList<>();
        for (String name : all) {
            list.add(new Person(name));
        }        //7. 打印整个队伍的Person对象信息。
        for (Person person : list) {
            System.out.println(person);
        }
    }
}
练习: 集合元素处理-Stream流方式
5分钟练习: 使用Stream流方式处理集合元素
需求:
现在有两个ArrayList集合存储队伍当中的多个成员姓名,要求使用"Stream流方式"依次进行以下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。 filter
2. 第一个队伍筛选之后只要前3个人;存储到一个新集合中。      limit3. 第二个队伍只要姓张的成员姓名;存储到一个新集合中。       filter
4. 第二个队伍筛选之后不要前2个人;存储到一个新集合中。      skip5. 将两个队伍合并为一个队伍;存储到一个新集合中。          concat
6. 根据String姓名创建Person对象;存储到一个新集合中。     String -> Person 转换 map(Function)
7. 打印整个队伍的Person对象信息                        forEachpublic static void main(String[] args) {
代码:
     
[AppleScript] 纯文本查看 复制代码
   /*
            1. 第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。 filter
            2. 第一个队伍筛选之后只要前3个人;存储到一个新集合中。      limit
         */
        Stream<String> oneStream = one.stream()
                .filter(name -> name.length() == 3)
                .limit(3);
        /*
            3. 第二个队伍只要姓张的成员姓名;存储到一个新集合中。       filter
            4. 第二个队伍筛选之后不要前2个人;存储到一个新集合中。      skip
         */
        Stream<String> twoStream = two.stream()
                .filter(name -> name.startsWith("张"))
                .skip(2);
        /*
            5. 将两个队伍合并为一个队伍;存储到一个新集合中。          concat
            6. 根据String姓名创建Person对象;存储到一个新集合中。     String -> Person 转换 map(Function)
            7. 打印整个队伍的Person对象信息                        forEach
         */
        Stream.concat(oneStream, twoStream)
                .map(name->new Person(name))
                .forEach(p-> System.out.println(p));
(扩展: 收集器)
如何理解Stream流:
        Stream不是集合, 也不是数组, 也不是某种数据结构, 所以Stream内部"不能存储"元素
        Stream是一种"函数模型", 规定一些对于集合或数组的处理方案:
            在调用"延迟方法"时, 就是在编写处理方案, 但并未真正执行方案
            在调用"终结方法"时, 才一次性按照处理方案来操作集合
            这也是流式操作"延迟执行"的特点收集器的作用:
        收集Stream操作后的结果, 转换为其他容器
        对流操作完成之后, 如果需要将其结果进行收集, 例如转换为对应的"集合"或"数组"等
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集合, 以及数组
*/
[AppleScript] 纯文本查看 复制代码
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

总结:
通过对象名引用成员方法
        对象名::成员方法名

适用场景:
        当Lambda表达式中, 仅仅是"通过某个对象, 调用已有的方法"时, 就可以用这种方式简化
需求:
已知如下代码, 请在Test类中的main()方法中, 分别使用Lambda和方法引用调用method方法// 定义函数式接口: 模拟Java中已经提供的函数式接口


方法引用:
总结:
通过super引用父类成员方法
        super::父类方法名
适用场景
        当Lambda表达式中, 仅仅是"在子类中, 调用父类某个已有的方法"时, 就可以用这种方式简化
5分钟练习: 引用父类方法
需求:
在Man类中的show()方法中, 补全三种方式调用method方法的代码:// 定义见面打招呼的函数式接口: 模拟Java中已经提供的函数式接口
代码:

总结:
通过this引用本类成员方法
        this::本类方法名
适用场景:
        当Lambda表达式中, 仅仅是"调用本类中, 某个已有的方法"时, 就可以用这种方式简化

5分钟练习: 引用本类方法
总结:
引用某个类的构造方法
        类名::new
5分钟练习: 引用数组的构造方法
需求:
已知如下代码, 请补全Test类中main()方法的代码, 分别用Lambda和方法引用方式, 调用createArray方法// 定义创建数组的函数式接口, 模拟Java中已经提供的函数式接口
@FunctionalInterface
[Java] 纯文本查看 复制代码
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) {
        // TODO 补全代码. Lambda方式调用createArray: 传递长度10, 以及创建数组的Lambda表达式
        // TODO 补全代码. 方法引用方式调用createArray: 传递长度10, 和数组的构造方法    }
}
代码:
public class Test {    // 定义方法用于创建数组
    // 参数: 数组的长度 和 创建数组的方式
    public static int[] createArray(int length, ArrayBuilder ab){
        return ab.builderArray(length);
    }    public static void main(String[] args) {
        // TODO 补全代码. Lambda方式调用createArray: 传递长度10, 以及创建数组的Lambda表达式
        int[] arr1 = createArray(
                10,
                (int length)->{
                    return new int[length];
                }
        );
        System.out.println(arr1.length);
        // TODO 补全代码. 方法引用方式调用createArray: 传递长度10, 和数组的构造方法
        int[] arr2 = createArray(
                10,
                int[]::new
        );
        System.out.println(arr2.length);
    }
}
今日API
java.util.Collection<E>接口:
        // 默认方法
        default Stream<E> stream(): 将"集合"转换为Stream对象

java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型
        // 静态方法
        static<T> Stream<T> of(T... values): 将"数组"转换为Stream对象
        static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流为新流
        // 抽象方法
        void forEach(Consumer<? super T> action): 遍历流中的元素进行逐一消费 (终结方法)
        long count(): 获取流中的元素个数 (终结方法)
        Stream<T> filter(Predicate<? super T> predicate): 过滤符合条件的结果. 返回过滤后的流
        <R> Stream<R> map(Function<? super T, ? extends R> mapper): 将T元素转换为R元素, 返回新的流
    Stream<T> limit(long maxSize): 从流中获取前maxSize个
    Stream<T> skip(long n): 从流中跳过n个元素, 获取后面的元素


方法引用能简化以下场景: (方法名后不要写小括号)
        1. 通过对象名引用成员方法       对象名::成员方法名
        2. 通过类名引用静态方法         类名::静态方法名
        3. 通过super引用父类成员方法    super::父类方法名
        4. 通过this引用本类成员方法     this::本类方法名
        5. 引用某个类的构造方法         类名::new
        6. 引用创建数组的方法           数据类型[]::new
今日目标 能够理解流与集合相比的优点
1. 管道特性 链式调用
2. 内部迭代 不用for循环
能够掌握常用的流操作
集合转流:
        集合对象.stream()
数组转流:
        Stream.of(数组)延迟方法: 返回值类型Stream
        Stream filter(Predicate p)
    Stream map(Function f)
    Stream limit(long n)
    Stream skip(long n)
终结方法: 返回值类型不是Stream
        void forEach(Consumer c)
    long count()合并流:
        static Stream concat(Stream s1, Stream s2)流转数组:
        Object[] Stream对象.toArray()
流转集合:
        List list = stream对象.collect(Collectors.toList());
        Set set = stream对象.collect(Collectors.toSet());
        Map map = stream对象.collect(Collectors.toMap(fun, fun));
能够通过4种方式使用方法引用
对象名::成员方法名
类名::静态方法名
super::父类方法名
this::本来方法名
能够使用类和数组的构造器引用
类名::new
数据类型[]::new






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2