集合框架——stream流

目录

前言

一、 认识Stream流

二、 体验stream流 

三、 stream流使用步骤

四、 获取Stream流 

4.1 集合获取stream流

 4.2 数组获取stream流

五、 Stream流提供的常用中间方法

5.1 Stream filter(Predicate predicate)——用于对流中的数据进行过滤。 

5.2 Stream sorted()——对元素进行升序排序 

5.2.1 问题演示

5.2.2 解决方案 

实现方式一:匿名内部类方式

实现方式二:lambda表达式优化

5.3 Stream limit——获取前几个元素

5.4  Stream skip​(long n)——跳过前几个元素

5.5 加工方法map——对元素进行加工,并返回对应的新流

 5.6 Stream distinct​()——去除流中重复的元素。

5.6.1 基本包装类型去重

5.6.2 自定义类型去重 

 5.7 static Stream concat​(Stream a, Stream b)——合并a和b两个流为一个流

六、 终结方法、收集Stream流 

6.1 Stream流的终结方法 ​编辑

6.1.1 void forEach​(Consumer action)——对此流运算后的元素执行遍历

6.1.2 long count​()——统计此流运算后的元素个数

6.1.3 Optional min​(Comparator comparator)——获取此流运算后的最小值元素

6.1.4 Optional max​(Comparator comparator)——获取此流运算后的最大值元素

6.2 收集Stream流

6.2.1 R collect​(Collector collector)——把流处理后的结果收集到一个指定的集合中去 

6.2.2  Object[] toArray()——把流处理后的结果收集到一个数组中去


前言

博主计划使用CSDN来记录Java后端开发的学习经历,并分享自己的编程心得和知识,期望能为那些有需求的朋友提供帮助。

博主也期望能与那些持续努力学习的朋友们共同进步!编程之路是一条充满艰辛与挑战的路,需要我们付出更多的心血,才能走得更远。只有通过不懈的研究和深入的思考,以及勤于实践,我们才能在编程的道路上取得真正的成就

一、 认识Stream流

Stream 是 Java 8 引入的一套处理集合数据的“流水线工具”,可以举一个例子,stream就像工厂流水线一样,把数据一步步过滤、转换、计算,最后得到结果。可以让你用更简洁、更高效的方式操作数组、集合等数据源。

Stream流大量的结合了Lambda的语法风格来编程,功能强大,性能高效,代码简洁,可读性好。

 

二、 体验stream流 

现在有段代码:

List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");

假设有个需求是把集合中所有以“张”开头,且是3个字的元素存储到一个新的集合。

传统做法

// 找出姓张,三个字的人名到新集合。
        //非Stream流方式
        //定义新集合
        ArrayList arrayList = new ArrayList();
        //遍历list,查找匹配
        for (String name : list) {
            if(name.startsWith("张") && name.length() == 3){
                //将符合的名字添加arrayList中
                arrayList.add(name);
            }
        }
        System.out.println(arrayList);

stream做法

//Stream流方式
        List<String> arrayList2 = list.stream()
                .filter(name -> name.startsWith("张") && name.length() == 3)
                .collect(Collectors.toList());
        System.out.println(arrayList2);

 结论:

stream流可以让你用更简洁、更高效的方式操作数组、集合等数据源。

 

三、 stream流使用步骤

stream流的使用可以分为三个步骤,第一步是获取Stream流 Stream流代表一条流水线,并能与数据源建立连接。第二步是调用流水线的各种方法,对数据进行处理、计算。第三步获取处理的结果,遍历、统计、收集到一个新集合中返回

下面我们将开始逐步学习并使用stream

四、 获取Stream流 

集合和数组分别提供了不同的API来获取stream流 

4.1 集合获取stream流

集合我们知道可以分为单列集合Collection和双列集合Map,Collection作为单列集合的祖宗,它提供了default Stream<E> stream​(),该方法返回当前集合对象stream流,那么对于List、Set子接口以及它们的实现类ArrayList,LinkedList、HashSet等待都能继承它的API ,所以,对于单列集合获取流的方法都是:调用stream()方法

 public static void main(String[] args) {
        // 目标:获取stream流。
        // 1、单列集合获取流的方法都是:调用stream()方法
        ArrayList<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
}

对于双列集合Map并没有直接提供获取stream流的API,但经过我们之前的学习,可以清楚的知道,我们是可以获取Map集合的Key集合、value集合,键值对集合,它们最终返回都是Set集合,所以,我们也是可以获取到stream流的

获取键的stream流,我们可以调用map集合提供的keyset()方法,该方法返回的是所有键的set集合,通过返回的set集合调用Collection提供的stream方法获取当前对象的stream流

 获取值的stream流,我们可以调用map集合提供的values()方法,该方法返回的是所有值的Collection集合,然后通过返回的Collection集合调用提供的stream方法获取当前对象的stream流

获取键值对的stream流,我们可以调用map集合提供的entrySet()方法,该方法返回的是所有键值对的Set集合,然后通过返回的set集合调用Collection提供的stream方法获取当前对象的stream流 

 我们来编码实操一下

// 2、Map集合获取stream()流。
        // 创建map集合
        HashMap<String, Integer> map = new HashMap<>();
        // 获取map集合的键流
        Stream<String> stream1 = map.keySet().stream();

        // 获取map集合的值流
        Stream<Integer> stream2 = map.values().stream();

        // 获取map集合的键值对对象流
        Stream<Map.Entry<String, Integer>> stream3 = map.entrySet().stream();

 4.2 数组获取stream流

数组获取stream流常用方法有两种,第一种是用Arrays类提供的stream方法,该方法需要传入一个数组对象,第二种方法是用Stream类提供的of方法,这个方法有很多个重载,其中有个重载是可以给它传入一个数组对象

// 3、获取数组的流。
        //准备数组
        String[] arr = {"张三丰", "张无忌", "赵敏", "周芷若"};
        //方式1:
        Stream<String> stream4 = Arrays.stream(arr);
        //方式2:
        Stream<String> stream5 = Stream.of(arr);

五、 Stream流提供的常用中间方法

中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)

接下来我们逐个学习,首先,我们准备个集合,然后获取个stream对象

public static void main(String[] args) {
        // 目标:搞清楚Stream流提供的中间方法。
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
        //获取stream流
        Stream<String> stream = list.stream();
    }

5.1 Stream<T> filter(Predicate<? super T> predicate)——用于对流中的数据进行过滤。 

        // 1、过滤:筛选数据的,查找姓“张”,并遍历
        stream.filter(s->s.startsWith("张")).forEach(System.out::println);

filter方法可以对符合条件表达式数据进行筛选,比如上面查找姓“张”,说明是以张开头,我们可以利用lambda表达式,利用String提供startsWith这个方法,来判断是不是以“张”开头,最终将符合条件的数据进行筛选打印

5.2 Stream<T> sorted()——对元素进行升序排序 

对于包装类型,排序默认是升序的

        // 2、排序的:sorted 默认是升序。
        List<Double> list2 = new ArrayList<>();
        list2.add(3.14);
        list2.add(1.14);
        list2.add(4.14);
        list2.add(2.14);
        list2.add(5.14);
        // 获取stream流
        Stream<Double> stream2 = list2.stream();
        stream2.sorted().forEach(System.out::println);

运行结果

 

但对于自定义类型,则需要指明排序规则,否则会抛ClassCastException异常

5.2.1 问题演示

准备Student类,并提供set、get方法,重写tostring

public class Student {
 
    private String name;
    private int age;
    private double score;
    private String address;
 
    public Student() {
    }
 
    public Student(String name, int age, double score, String address) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.address = address;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public double getScore() {
        return score;
    }
 
    public void setScore(double score) {
        this.score = score;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                ", address='" + address + '\'' +
                '}' + "\n";
    }
}

 声明Student集合,并添加元素

        // 3、集合中是对象的排序
        List<Student> students = new ArrayList<>();
                students.add(new Student("小明", 18, 90.0, "北京"));
                students.add(new Student("小红", 19, 80.0, "上海"));
                students.add(new Student("小刚", 20, 70.0, "广州"));
                students.add(new Student("小花", 21, 60.0, "深圳"));

获取stream流并进行排序操作

// 3、集合中是对象的排序
        List<Student> students = new ArrayList<>();
                students.add(new Student("小明", 18, 90.0, "北京"));
                students.add(new Student("小红", 19, 80.0, "上海"));
                students.add(new Student("小刚", 20, 70.0, "广州"));
                students.add(new Student("小花", 21, 60.0, "深圳"));
        students.stream().sorted().forEach(System.out::println);

运行结果

 

5.2.2 解决方案 

第一种方案是可以使用自定义类去实现Comparable接口,并重写提供的compareTo方法

在compareTo方法中,提供了一个类型为Student的参数o,这里代表的是传入对象

jdk官方比较规则认为:

当前对象this.getAge() - 传入对象o.getAge() 返回大正整数,代表当前对象大于传入对象

当前对象this.getAge() - 传入对象o.getAge() 返回大负整数,代表当前对象小于传入对象

当前对象this.getAge() - 传入对象o.getAge() 返回值等于0,代表当前对象等于传入对象

这里假设我们需要对学生的年龄进行升序排序,那么我们需要用当前对象的成绩减去传入对象的成绩,如果它是大于0,则可以认为是当前对象成绩的值是大于传入对象的,即this.getAge() - o.getAge()

    public int compareTo(Student o) {
        //jdk官方比较规则
        //升序规则
        //    当前对象this.getAge() - 传入对象o.getAge() 返回大正整数,代表当前对象大于传入对象
        //    当前对象this.getAge() - 传入对象o.getAge() 返回大负整数,代表当前对象小于传入对象
        //    当前对象this.getAge() - 传入对象o.getAge() 返回值等于0,代表当前对象等于传入对象
        // if(this.getAge() - o.getAge() > 0) return 1;
        // if(this.getAge() - o.getAge() < 0) return -1;
        // if(this.getAge() - o.getAge() == 0) return 0;
        return this.getAge() - o.getAge();
    }

重写运行程序

 

可以发现,问题已经解决,并且按照我们预期,对年龄进行了升序排序

除了上述继承Comparable接口的方式,还有另一种方式,就是可以利用softed方法的另一个重载,这个重载是支持我们可以去自定义它的排序规则

Comparator是什么呢?我们按照ctrl加鼠标点击,进入看看

可以看到 Comparator其实就是一个函数式接口,里面有一个compare函数,需要我们待会去实现它,来完成自定义排序规则,它既然是函数式接口,我们可以考虑用匿名内部类的方式来实现它,也可以使用Lambda表达式进行优化,我们两种方式都体验一下

实现方式一:匿名内部类方式

返回我们的Test类,采用匿名内部类方式来重写compare方法

这个compare方法 需要两个参数,一个是类似于compareTo方法中的当前对象,第二个参数是传入对象,但是这里不是这么称呼,而是直接比较它们两个参数的值来决定如何排序

如果认为第一个元素 >  第二个元素 返回正整数即可。

如果认为第一个元素 < 第二个元素返回负整数即可。

如果认为第一个元素 = 第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复

这里我们按照学生的成绩进行升序排序处理,因为学生成绩是double类型,我们可以使用Double包装类提供的compare方法进行比较值,这个方法也需要传入两个值,如果前者大于后者,则会返回大于1的数,如果两个值相等,则会返回0,否则就返回-1

 public static void main(String[] args) {
// 3、集合中是对象的排序
        List<Student> students = new ArrayList<>();
                students.add(new Student("小明", 18, 90.0, "北京"));
                students.add(new Student("小红", 19, 80.0, "上海"));
                students.add(new Student("小刚", 20, 70.0, "广州"));
                students.add(new Student("小花", 21, 60.0, "深圳"));
        students.stream().sorted(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getScore(), o2.getScore());
            }
        }).forEach(System.out::println);
    }

运行结果 

可以看到,TreeSet集合已经按照我们的预期,实现了按学生成绩进行升序排序

实现方式二:lambda表达式优化

把鼠标放到Comparator那里,按住ALT+ENTER(回车),将表达式替换成lambda表达式即可

    public static void main(String[] args) {
 List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));
        students.stream().sorted((o1, o2) -> Double.compare(o1.getScore(), o2.getScore())).forEach(System.out::println);
    }

 运行结果

可以看到,两种方式效果是一样的

5.3 Stream<T> limit——获取前几个元素

       // 目标:搞清楚Stream流提供的中间方法。
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
        // 获取stream流
        Stream<String> stream = list.stream();
        // 4、limit 取前几个
        Stream<String> limit = stream.limit(3);
        limit.forEach(System.out::println);

运行结果

 

  可以用limit来获取集合或数据里面前几个元素

5.4  Stream<T> skip​(long n)——跳过前几个元素

       // 目标:搞清楚Stream流提供的中间方法。
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
        // 获取stream流
        Stream<String> stream3 = list.stream();
        Stream<String> skip = stream3.skip(3);
        skip.forEach(System.out::println);

运行结果

5.5 加工方法map——对元素进行加工,并返回对应的新流

可以使用stream流提供的map方法,对流中的数据进行加工,map方法的入参是一个Function接口类型,Function是一个函数式接口

使用时可以用lambda进行优化,也可以用匿名内部类的方式去实现apply方法,这个方法入参是个泛型,可以在这个方法里面写我们需要的逻辑,比如我们可以获取集合里面的年龄属性,那么我们可以这样写

List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));        
// 6、加工方法:map
        students.stream().sorted().map(new Function<Student, Object>() {
            @Override
            public Object apply(Student student) {
                return student.getAge();
            }
        }).forEach(s-> System.out.println(s));

 运行结果

也可以用lambda进行优化,鼠标放到Function,按照Alt + 回车,生成lambda表达式

 

List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));

students.stream().sorted().map(s-> "姓名:"+s.getName()+","+"年龄:"+s.getAge()).forEach(s-> System.out.println(s));

 运行结果

注意,map加工后返回元素类型可以与原集合元素类型不一样,返回元素的类型由map里面决定

 5.6 Stream<T> distinct​()——去除流中重复的元素。

在stream流中,可以使用distinct方法对流中的元素进行去重,它的底层其实就是调用了Object提供的HashCode方法来获取哈希值和调用Object提供equals方法,来比较这个对象是否是同一个对象

5.6.1 基本包装类型去重

我们都知道,如果只是调用Object类提供的equals方法,那么这个方法比较的就是内存地址,对于不同的对象,这个内存地址是不一样的,但是对于基本包装类型(如Integer、String、Double),它们底层都有重写了Object提供的equals方法和HashCode方法,因此,它们比较的不在是内存地址,而是具体的值,所以基本包装类型可以直接用distinct去重

准备数据

        List<Double> list2 = new ArrayList<>();
        list2.add(3.14);
        list2.add(1.14);
        list2.add(4.14);
        list2.add(4.14);
        list2.add(2.14);
        list2.add(5.14);
        list2.add(5.14);
        // 8、去重
        list2.stream().distinct().forEach(System.out::println);

运行结果

 

可以发现,对于基本包装类型, distinct已经帮我们去除重复元素5.14和4.14

5.6.2 自定义类型去重 

刚刚我们了解到去重的原理是基于比较equals和比较元素的哈希值进行去重的,所以,我们自定义类型必须要重写equals方法和hashCode方法,否则不能去重

准备数据

        List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));
        students.add(new Student("小花", 21, 60.0, "深圳"));
 // 8、去重
        students.stream().distinct().forEach(System.out::println);

运行结果

 

可以发现,对于基本数据类型,我们没有重写 equals方法和hashCode方法,distinct是不能帮我们去重的

解决方案:重写equals方法和hashCode方法

 返回我们的Student类,按住ALT + Insert,选择生成equals和hashCode,然后一直确定即可

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Double.compare(score, student.score) == 0 && Objects.equals(name, student.name) && Objects.equals(address, student.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, score, address);
    }

第九步:重写equals源码分析

 第十步: 重写HashCode源码分析

第十一步:重新运行程序

可以发现,HashSet集合已经帮我们去除了相同的元素数据

 5.7 static <T> Stream<T> concat​(Stream a, Stream b)——合并a和b两个流为一个流

List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
List<Double> list2 = new ArrayList<>();
        list2.add(3.14);
        list2.add(1.14);
        list2.add(4.14);
        list2.add(4.14);
        list2.add(2.14);
        list2.add(5.14);
        list2.add(5.14);        
Stream<String> stream1 = list.stream();
        Stream<Double> stream2 = list2.stream();
        Stream<Object> stream3 = Stream.concat(stream1, stream2);
        stream3.forEach(System.out::println);
        System.out.println("----------------------------");

运行结果

 

可以用concat来讲两个流中的元素进行合并,并返回一个新的流

六、 终结方法、收集Stream流 

 终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。

6.1 Stream流的终结方法 

6.1.1 void forEach​(Consumer action)——对此流运算后的元素执行遍历

forEach其实在之前的例子里面已经用过了,它就是其中一种终结方法,并且可以遍历输出元素

// 目标:学习Stream流的终结方法。
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
        // 1、遍历方法
        list.stream().filter(name->name.startsWith("张")).forEach(System.out::println);

运行结果

 

6.1.2 long count​()——统计此流运算后的元素个数

// 目标:学习Stream流的终结方法。
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
 // 2、统计数据的个数 count()
        long count = list.stream().filter(name -> name.startsWith("张")).count();
        System.out.println("姓张的同学人数:"+count);

运行结果

 

6.1.3 Optional<T> min​(Comparator<? super T> comparator)——获取此流运算后的最小值元素

这个方法需要有一个入参,就是Comparator类型的参数,上面我们已经知道,Comparator是一个接口,需要我们重写它的比较方法compare方法才可以,这里我们直接lambda进行编写

// 3、挑选出最小值
        List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));
        Optional<Student> min = students.stream().min((s1, s2) -> s1.getAge() - s2.getAge());

          Student student = min.get();
            System.out.println("年龄最小是:"+student.getAge()+"岁,姓名:"+student.getName());
        }

运行结果

 

为什么返回的是Optional类型?这是因为可能没有最小年龄同学会返回null容易发生空指针异常,所以返回Optional<Student>接收null的值,所以我们可以对这个代码进行优化

 

        // 3、挑选出最小值
        List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));
        Optional<Student> min = students.stream().min((s1, s2) -> s1.getAge() - s2.getAge());
        //为什么返回Optional<Student>,而不是最小年龄的学生Student? 答:因为可能没有最小年龄同学会返回null容易发生空指针异常,所以返回Optional<Student>接收null的值
        if(!min.isEmpty()){
            Student student = min.get();
            System.out.println("年龄最小是:"+student.getAge()+"岁,姓名:"+student.getName());
        }

6.1.4 Optional<T> max​(Comparator<? super T> comparator)——获取此流运算后的最大值元素

 List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));
 // 4、挑选出最大值
        Optional<Student> max = students.stream().max((s1, s2) -> s1.getAge() - s2.getAge());
        if(max!=null){
            Student student = max.get();
            System.out.println("年龄最大是:"+student.getAge()+"岁,姓名:"+student.getName());
        }

运行结果

 

经过上面的讲解,我们已经清除的知道Stream流的终结方法和使用方法,但是,有个非常要注意的一点是,一旦用了总结方法,那么这个流的对象就被关闭,不能再去使用中间方法,需要重新获取Stream流 

6.2 收集Stream流

收集Stream流:就是把Stream流操作后的结果转回到集合或者数组中去返回。

其实收集Stream流也是总结方法中的一种方式,Stream提供了两个常用的收集流的方法

 

6.2.1 R collect​(Collector collector)——把流处理后的结果收集到一个指定的集合中去 

方式一:收集到一个全新的List集合

// 目标:收集Stream流。把流收集成集合: 流只能用一次
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");

        // 收集List集合
        List<String> list2 = list.stream().filter(name -> name.startsWith("张")).collect(Collectors.toList());
        System.out.println("新的List:" + list2);

运行结果

 

方式二:收集到一个权限的Set集合

        // 目标:收集Stream流。把流收集成集合: 流只能用一次
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
 // 收集成Set集合
        Set<String> set = list.stream().collect(Collectors.toSet());
        System.out.println("新的Set:" + set);

运行结果

 

方式三:收集到一个权限的Map集合

收集到Map集合和前两个不太一样,因为它是双列集合,所以在收集的时候,必须指定Key和Value值,这两个参数类型都是Function接口类型,经过上面的学习,我们已经知道,它也是函数式接口,需要我们重写apply方法,来写我们的逻辑

准备数据

// 收集成Map集合。
        List<Student> students = new ArrayList<>();
        students.add(new Student("小明", 18, 90.0, "北京"));
        students.add(new Student("小红", 19, 80.0, "上海"));
        students.add(new Student("小刚", 20, 70.0, "广州"));
        students.add(new Student("小花", 21, 60.0, "深圳"));

方式一:匿名内部类方式

 //  方式1:匿名内部类方式
        Map<String, Integer> map1 = students.stream().filter(s -> s.getName().startsWith("小")).collect(Collectors.toMap(new Function<Student, String>() {
            @Override
            public String apply(Student student) {
                return student.getName();
            }
        }, new Function<Student, Integer>() {

            @Override
            public Integer apply(Student student) {
                return student.getAge();
            }
        }));
        System.out.println("map1:"+map1);

这里是先用了filter方法对流中的元素进行筛选,筛选出以“小”开头的元素,然后再用收集流的方法,以学生的名字作为Key键,年龄作为Value值

 运行结果

方式二:lambda方式

鼠标放到Function那里,按照alt+回车即可替换成lambda表达式

//  方式2:lambda方式
        Map<String, Integer> map2 = students.stream().filter(s -> s.getName().startsWith("小")).collect(
                Collectors.toMap(student -> student.getName(), student -> student.getAge()));
        System.out.println("map2:"+map2);

运行结果

 

方式三(推荐):特殊方法引用方式(类名::实例方法,要求:传入的第一个参数是方法体内主调用方法参数,其他参数作为调用方法的参数)

把鼠标放到student.getName()或student.getAge()按住alt + 回车,即可替换成方法引用方式

//  方式3(推荐):特殊方法引用方式(类名::实例方法,要求:传入的第一个参数是方法体内主调用方法参数,其他参数作为调用方法的参数)
        Map<String, Integer> map3 = students.stream().filter(s -> s.getName().startsWith("小")).collect(
                Collectors.toMap(Student::getName, Student::getAge));
        System.out.println("map3:"+map3);

运行结果

 

6.2.2  Object[] toArray()——把流处理后的结果收集到一个数组中去

 可以用toArray将Stream流转成数组

// 目标:收集Stream流。把流收集成集合: 流只能用一次
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张无忌");
        Object[] array = list.stream().toArray();
        System.out.println("数组:" + array);

运行结果

 

默认打印的是内存地址,我们需要用Ayyays类提供的ToString方法,将内存地址转成字符串

System.out.println("数组:" + Arrays.toString(array));

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值