Java8新特性之—-Stream

Java8新特性之----Stream

  • 前言
  • Stream介绍
  • Stream的操作
    • 创建流
    • 四种创建流的方法
      • 通过一个集合创建Stream
      • 通过一个数组创建Stream
      • 通过Stream.of
      • 创建无限流
    • 使用Stream操作数据
      • 操作一:筛选和切片
      • 操作二:映射
      • 操作三:排序
    • 终止Stream
      • 操作一:匹配和查找
      • 操作二:归约
      • 操作三:收集
  • 结尾

前言

Java作为一门火热的编程语言,为当今的互联网世界立下了汗马功劳,如今她已经25 岁了,从诞生至今随着时间的推移,Java已经更新换代到了Java14了,但是根据JetBrains发布的调查结果来看,Java8,即JDK1.8仍是最常被使用的一个版本,她向我们提供了很多方便的新接口,今天来讲一下Stream这个新特性。

Stream介绍

Stream也是一个流,不过和一般的IO流有一些不一样的地方。

Stream是在Java.util.Stream包路径下,主要作用就是对集合数据进行查找过滤等操作,是一种高效且易用的数据处理方式。

对于一般规模的数据其实和普通的集合没有什么太大的区别,但是数据一旦规模很大,Stream的效果就很明显了。它会将数据处理为一种流。

在大数据领域有一个Stream流实时框架

Stream和Collection的区别:

  1. Collection只是负责存储数据,不对数据做其他处理主要和内存打交道。
  2. Stream主要是负责计算数据的,主要和CPU打交道(查询过滤)。

Stream的操作

操作流程比较简单(和IO流类似):

  1. 创建一个Stream:从一个数据源,如集合、数组中获取流;
  2. 使用Stream操作数据:一个操作的中间链,对数据源的数据进行操作;
  3. 终止Stream:一个终止操作,执行中间操作链,并产生结果;

创建流

首先创建一个数据源类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class Student  implements Comparable{
    private Integer id;
    private String name;
    private Integer age;
    private Double score;

    public Student(Integer id, String name, Integer age, Double score) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public Double getScore() {
        return score;
    }

    public void setId(Integer id) {
        this.id = id;
    }

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

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    @Override
    public int compareTo(Object o) {
        Student o1=(Student)o;
        return o1.getAge()-this.getAge();
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

创建数据(仅仅是为了方便数据的写入)

1
2
3
4
5
6
7
8
9
10
public class StudentData {
    public static List <Student> getStudents(){
        ArrayList <Student> students=new ArrayList<>();
        students.add(new Student(1,"赤",21,89.5));
        students.add(new Student(2,"橙",22,90.5));
        students.add(new Student(3,"黄",23,87.1));
        students.add(new Student(4,"绿",24,89.7));
        return students;
    }
}

四种创建流的方法

通过一个集合创建Stream

1
2
3
4
5
6
7
public static void test1() {
    List<Student> students = StudentData.getStudents();
    // 第一种 返回一个顺序流
    Stream<Student> stream = students.stream();
    // 第二种 返回一个并行流
    Stream<Student> stream1 = students.parallelStream();
}

通过一个数组创建Stream

1
2
3
4
5
public static void test2() {
    // 获取一个整形Stream
    int[] arr = {1, 34, 2, 54, 56, 34};
    IntStream stream = Arrays.stream(arr);
}

通过Stream.of

1
2
3
4
5
6
7
public static void test3() {
    Stream<String> stringStream = Stream.of("A", "B", "C", "D");
    Stream.of(
            new Student(1, "Chuki", 20, 90.5),
            new Student(2, "Zorina", 20, 99.9)
    );
}

创建无限流

1
2
3
4
5
6
7
8
9
10
public static void test4() {
        // 每隔5个数取一次,从0开始,此时就会无限循环
//        相当于:
//        for (int i = 0; ; ) {
//            i += 5;
//        }
        Stream<Integer> iterate = Stream.iterate(0, t -> t + 5);
        // 取出一个随机数
        Stream<Double> generate = Stream.generate(Math::random);
    }

使用Stream操作数据

操作一:筛选和切片

filter——接收lambda,从流中排除某些操作;
limit——截断流,使其元素不超过给定对象
skip(n)——跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
distinct——筛选,通过流所生成元素的hashCode()和equals去除重复元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void test5() {
    /**
     * 写成System.out::println这种语法叫做方法引用。该功能特性也是JDK8以后引入的,你可以把它看成lambdas表达式的语法糖
     * 可以用lambdas表达式改写成以下代码:list.forEach((t) -> System.out.println(t));
     * 这样还不明白的话,也可以这样:list.forEach((String t)-> System.out.println(t));
     * 这样的效果跟System.out::println是一样
     */
    List<Student> list = StudentData.getStudents();
    // 过滤:过滤出所有年龄大于22岁的同学
    System.out.println("=============");
    list.stream().filter(item -> item.getAge() > 22).forEach(System.out::println);
    // 截断流:筛选出前三条
    list.stream().limit(3).forEach(System.out::println);
    // 跳过元素:跳过前两个元素
    list.stream().skip(2).forEach(System.out::println);
    System.out.println("================");
    // 过滤重复元素
    list.stream().distinct().forEach(System.out::println);//没有重复的,根据hashcode判断
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

操作二:映射

map——接受Lambda,将元素转换成其他形式或提取信息。接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public static void test6() {
        //map操作
        List<String> list = Arrays.asList("hello", "word", "chuki");
        Stream<String> stream = list.stream();
        //将每一个小写字母都转换为大写字母映射
        stream.map(str -> str.toUpperCase()).forEach(System.out::println);

        //筛选出所有的年龄,再过滤出所有大于23的年龄
        List<Student> students = StudentData.getStudents();
        Stream<Student> stream1 = students.stream();
        //将流中的每一值转换为另一个值
        Stream<Integer> stream2 = stream1.map(Student::getAge);
        stream2.filter(age -> age > 23).forEach(System.out::println);
    }

在这里插入图片描述

操作三:排序

sorted()——自然排序(Comparable)
sorted(Comparator com)——定制排序(Comparator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public static void test7() {
        // 自然排序
        List<Integer> list = Arrays.asList(4, 8, 6, 5, 2, 3, 1, 7);
        Stream<Integer> stream = list.stream();
        stream.sorted().forEach(System.out::println);

        // 对象排序,对象排序可以先实现comparable接口或者直接指定
        // 第一种:先实现comparabl
        System.out.println("=========年龄从大到小排序==========");
        List<Student> students = StudentData.getStudents();
        students.stream().sorted().forEach(System.out::println);
        // 第二种:直接指定comparator
        System.out.println("==========年龄从小到大排序==========");
        List<Student> students1 = StudentData.getStudents();
        students1.stream().sorted((e1, e2) -> (int) (e1.getAge() - e2.getAge())).forEach(System.out::println);
    }

在这里插入图片描述

终止Stream

操作一:匹配和查找

allMatch–检查是否匹配所有元素
anyMatch–检查是否至少匹配一个元素
noneMatch–检查是否没有匹配所有元素
findFirst–返回第一个元素
findAny–返回当前流中的任意元素
count–返回流中元素的总个数
max–返回流中最大值
min–返回流中最小值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void test8() {
    List<Student> list = StudentData.getStudents();
    //判断所有的学生年龄是否都大于20岁
    boolean allMatch = list.stream().allMatch(student -> student.getAge() > 20);
    //判断是否存在学生的年龄大于20岁
    boolean anyMatch = list.stream().anyMatch(student -> student.getAge() > 20);
    //判断是否不存在学生叫小白
    boolean noneMatch = list.stream().noneMatch(student -> student.getName().equals("黄"));
    //查找第一个学生
    Optional<Student> first = list.stream().findFirst();
    //查找当前流中的元素
    Optional<Student> any = list.stream().findAny();
    //查找所有的学生数量
    long count = list.stream().count();
    //查找成绩大于90的数量
    long count1 = list.stream().filter(student -> student.getScore() > 90).count();
    //查找学生的最高分数
    Stream<Double> doubleStream = list.stream().map(student -> student.getScore());
    Optional<Double> max = doubleStream.max(Double::compareTo);
    System.out.println(max);
}

操作二:归约

reduce–归约操作可以将流中元素反复结合起来,得到一个值

1
2
3
4
5
6
7
8
9
10
11
12
public static void test9() {
    //计算数的总和
    List<Integer> list = Arrays.asList(4, 5, 6, 1, 8, 9, 2, 3, 7);
    Integer reduce = list.stream().reduce(0, Integer::sum);
    System.out.println(reduce);

    //计算学生总分
    List<Student> students = StudentData.getStudents();
    Stream<Double> doubleStream = students.stream().map(Student::getScore);
    Optional<Double> reduce1 = doubleStream.reduce(Double::sum);
    System.out.println(reduce1.get());
}

在这里插入图片描述

操作三:收集

collect:将流转换为其他形式,接收一个Collector接口实现,用于给Stream中汇总的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public static void test10() {
        //返回一个list
        List<Student> students = StudentData.getStudents();
        List<Student> list = students.stream().filter(student -> student.getScore() > 88).collect(Collectors.toList());
        System.out.println(list);
        //返回一个set
        Set<Student> set = students.stream().filter(s -> s.getAge() > 23).collect(Collectors.toSet());
        System.out.println(set);
    }

        List<Student> list = students.stream().filter(student -> student.getScore() > 88).collect(Collectors.toList());
        System.out.println(list);
        //返回一个set
        Set<Student> set = students.stream().filter(s -> s.getAge() > 23).collect(Collectors.toSet());
        System.out.println(set);
    }

结尾

stream基本的语法就是这样,你会发现Stream就像是一个下具一样,可以帮我们分析处理数据,极其的好用,但是目前还不知道其效率如何。
根据网上一位大佬的内存时间分析,其实在数据量比较庞大的时候,Stream可以为我们节省大量的时间。