java--Stream流

153 阅读4分钟

Stream流

什么是Stream流

Stream是JAVA8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找,过滤,筛选等操作

为什么使用Stream流

当我们需要对集合的元素进行操作的时候,除了必须的添加,删除,获取外,最典型的就是集合遍历。我们来体验集合操作数据的弊端,需求如下:

一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰

需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3. 打印这些数据

public class Test {

    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("张无忌");
        names.add("周芷若");
        names.add("赵敏");
        names.add("张强");
        names.add("张三丰");
        //拿到所有姓张的名字
        ArrayList<String> zhang = new ArrayList<>();
        for (String s : names) {
            //判断s前缀是否是张
            if(s.startsWith("张")){
                zhang.add(s);
            }
        }
        //拿到名字长度为三个字的
        ArrayList<String> san = new ArrayList<>();
        for (String s : zhang) {
            if(s.length()==3){
                san.add(s);
            }
        }
        //打印这些数据
        for (String s : san) {
            System.out.println(s);
        }

    }
}

分析

循环遍历的弊端

这段代码中有三个循环,每一个作用不同:

1.首先筛选所有姓张的人;

2.然后筛选名字有三个字的人;

3.最后进行对结果的输出打印

每当我们需要对集合中的元素进行操作的时候,总是需要进行循环,循环,再循环。 这显然不是理所应当的,而是我们完成业务的一种方式而已,每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能使用另一个循环从头开始

那Stream能给我们带来怎样更加优雅的写法呢?

Stream初体验

public class Test {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("张无忌");
        names.add("周芷若");
        names.add("赵敏");
        names.add("张强");
        names.add("张三丰");
        //过滤出姓张并且姓名长度为3的名字
        names.stream().filter(t->t.startsWith("张")).filter(t->t.length()==3).forEach(System.out::println);
    }
}

Stream流的原理

Stream流的思想类似于工厂车间的"生产流水线",Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

image.png

Stream流的操作步骤

一、创建Stream流

从一个数据源,如集合,数组中获取流

二、中间操作

一个操作的中间链,对数据源的数据进行操作。---返回的类型还是Stream流对象

三、终止操作

返回类型不再是Stream流对象

获取Stream流对象的方式

1.通过集合对象调用Stream()方法

//通过集合调用stream流方法
ArrayList<String> strings = new ArrayList<>();
Stream<String> stream = strings.stream();

2.通过Arrays获取Stream流对象

//通过Arrays工具类获取
String[] arr ={};
Stream<String> stream1 = Arrays.stream(arr);

3.通过Stream流里面的of方法

//通过Stream类获取
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 1, 5, 7);

以上三种都是串行流输出的是一个一个执行,而并行流相当于同时有多个线程同时执行该流速度更快,但是输出顺序是随机的,下面例子为并行流 parallelStream

//并行流
ArrayList<String> names = new ArrayList<>();
names.add("张无忌");
names.add("周芷若");
names.add("赵敏");
names.add("张强");
names.add("张三丰");
Stream<String> stringStream = names.parallelStream();
stringStream.forEach(System.out::println);

Stream流的api方法

image.png

筛选filter,forEach循环 统计个数 count 找到最大值max 找到最小值min的使用方法

public static void main(String[] args) {
    List<Person> personList = new ArrayList<>();
    personList.add(new Person("欧阳雪",18,"中国",'F'));
    personList.add(new Person("Tom",24,"美国",'M'));
    personList.add(new Person("Harley",22,"英国",'F'));
    personList.add(new Person("向天笑",20,"中国",'M'));
    personList.add(new Person("李康",22,"中国",'M'));
    personList.add(new Person("小梅",20,"中国",'F'));
    personList.add(new Person("何雪",21,"中国",'F'));
    personList.add(new Person("李康",22,"中国",'M'));
    //1. 年龄大于18  filter:过滤掉不满足条件的元素.  forEach:输出元素. ---如果没有终止函数,那么中间函数的代码不会被执行。
    personList.stream().filter(t->t.getAge()>18).forEach(System.out::println);
    //2. 找出中国人  并统计个数: count()
    long count = personList.stream().filter(t -> t.getCountry().equals("中国")).count();
    System.out.println("中国人有"+count);
    //3.找出年龄最大和年龄最小的人 max  min 
    Optional<Person> max = personList.stream().max((t1, t2) -> t1.getAge() - t2.getAge());
    Person person = max.get();
    System.out.println("年龄最大的人是"+person);
    Optional<Person> min = personList.stream().min((t1, t2) -> t1.getAge() - t2.getAge());
    Person person1 = min.get();
    System.out.println("年龄最小的人是"+person1);
}

map-->把集合中的元素转换成另一种类型

map会把集合中的元素转换成另一种类型

image.png

public class Test {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("欧阳雪",18,"中国",'F'));
        personList.add(new Person("Tom",24,"美国",'M'));
        personList.add(new Person("Harley",22,"英国",'F'));
        personList.add(new Person("向天笑",20,"中国",'M'));
        personList.add(new Person("李康",22,"中国",'M'));
        personList.add(new Person("小梅",20,"中国",'F'));
        personList.add(new Person("何雪",21,"中国",'F'));
        personList.add(new Person("李康",22,"中国",'M'));
        //使用map将姓名剥离并且打印出来,结果为string类型的集合,与之前的不同
        personList.stream().map(Person::getName).forEach(System.out::println);
        //使用map集合剥离姓名和年龄使用student类接收
        personList.stream().map(t->new Student(t.getName(),t.getAge())).forEach(t-> System.out.println(t));
    }
}
class Student{
    String name;
    Integer age;
    public Student() {
    }
    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public Integer getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(Integer age) {
        this.age = age;
    }
    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}
class Person {
    private String name;
    private Integer age;
    private String country;
    private char sex;
    public Person() {
    }
    public Person(String name, Integer age, String country, char sex) {
        this.name = name;
        this.age = age;
        this.country = country;
        this.sex = sex;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public Integer getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(Integer age) {
        this.age = age;
    }
    /**
     * 获取
     * @return country
     */
    public String getCountry() {
        return country;
    }
    /**
     * 设置
     * @param country
     */
    public void setCountry(String country) {
        this.country = country;
    }
    /**
     * 获取
     * @return sex
     */
    public char getSex() {
        return sex;
    }
    /**
     * 设置
     * @param sex
     */
    public void setSex(char sex) {
        this.sex = sex;
    }
    public String toString() {
        return "Person{name = " + name + ", age = " + age + ", country = " + country + ", sex = " + sex + "}";
    }
}

image.png

收集--->collect 把处理过的集合搜集成新的集合

把处理过的集合搜集成新的集合

过滤出年龄大于20岁,将大于20岁的人的名字封装成一个新的集合

List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//过滤出年龄大于20岁,将大于20岁的人的名字封装成一个新的集合
List<String> collect = personList.stream().filter(t -> t.getAge() > 20).map(t -> t.getName()).collect(Collectors.toList());
System.out.println(collect);

stream流排序方法--->sorted

List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//将集合中的元素按照年龄排序,之后封装到新的集合中
List<Person> collect1 = personList.stream().sorted((t1, t2) -> t1.getAge() - t2.getAge()).collect(Collectors.toList());
System.out.println(collect1);

reduce--->规约

规约,也称为缩减,是把一个流缩减成一个值,能实现对集合求和,求乘积和求最值的操作

image.png

List<Integer> integers = Arrays.asList(1, 2, 3, 5);
Optional<Integer> reduce = integers.stream().reduce((t1, t2) -> t1 + t2);
//t1==1 t2==2 ===3
//t1==3 t2==3  ====6
//t1==6 t2==5 ====11
Integer x = reduce.get();
System.out.println(x);
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//求集合中所有的年龄之和
Optional<Integer> reduce = personList.stream().map(t -> t.getAge()).reduce((t1, t2) -> t1 + t2);
Integer integer = reduce.get();
System.out.println(integer);

匹配--->find

匹配第一个元素 ---findFirst

List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//匹配第一个对象
Optional<Person> first = personList.stream().findFirst();
Person person = first.get();
System.out.println(person);

提取、组合

image.png

中间的操作: filter map sorted distinct() skip limit()

终止操作: forEach count() reduce() collect(Collectors.toList()) findFirst max min