Stream流

文章介绍了Java8引入的StreamAPI如何简化集合处理,通过Stream流的思想,实现了对集合的高效过滤、筛选和操作,减少了传统循环遍历的复杂性。StreamAPI的核心包括获取流对象、中间操作和终止操作,提供了filter、map、reduce、collect等多种功能,提高了代码的可读性和性能。

Java8的两个重大改变,一个是Lambda表达式,另一个就是Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作。

1为什么使用stream流

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

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

public class Test {
    public static void main(String[] args) {
//        一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,成俊杰,张三丰

//        需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
        List<String> list=new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("程俊杰");
        list.add("张三丰");

        //1.拿到所有姓张的
        List<String> newList01=new ArrayList<>();
        for(String n:list){
            if(n.startsWith("张")){
                 newList01.add(n);
            }
        }

        //2.拿到名字长度为3个字的
        List<String> newList02=new ArrayList<>();
        for(String n:newList01){
             if(n.length()==3){
                 newList02.add(n);
             }
        }

        //3.打印这些数据
        for(String s:newList02){
            System.out.println(s);
        }


    }
}

分析:

循环遍历的弊端

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

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

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

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

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

Stream初体验  

public class Test2 {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("程俊杰");
        list.add("张三丰");
        //list.stream().filter(t->t.startsWith("张")).filter(t->t.length() == 3).forEach(item-> System.out.println(item));
        list.stream().filter(t->t.startsWith("张")).filter(t->t.length() == 3).forEach(System.out::println);
    }
}

2.Stream流的原理

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

3.步骤

(1)获取Stream流对象

(2) 中间操作---返回类型还是Stream流对象。

(3)终止操作---不在是Stream流对象

4.获取Stream流对象的方式

(1) 通过集合对象调用stream()

(2)通过Arrays获取stream流对象

(3)通过Stream流里面of方

public class Test3 {
    public static void main(String[] args) {
      List<String> list = new ArrayList<>();
      list.add("张无忌");
      list.add("周世荣");
      list.add("赵敏");
      //第一种:通过集合对象调用stream()
        Stream<String> stream = list.stream();
        stream.forEach(System.out::println);
        //第二种:使用Arrays工具类
        String [] arr={};
        Stream<String> stream1 = Arrays.stream(arr);
        stream1.forEach(System.out::println);
        //第三种:Stream类
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        integerStream.forEach(System.out::println);
        
        //上边的流都是串行流,并行流
        Stream<String> stringStream = list.parallelStream();
        stringStream.forEach(System.out::println);
    }
}

5.Stream流的api方法

举个简单的例子:

假设有一个Person类和一个Person列表,现在有两个需求:1)找到年龄大于18岁的人并输出;2)找出所有中国人的数量

public class Test03 {
    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+"个");
    }
}

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 + "}";
    }
}

(2)找出年龄最大和最小

 //3.找出年龄最大的人
        Person person1 = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge()).get();
        System.out.println(person1);
        //4.找出年龄最小的人
        Person person2 = personList.stream().min((o1, o2) -> o1.getAge() - o2.getAge()).get();
        System.out.println(person2);

(3)map->会把集合中的元素转化成另一种类型

personList.stream().filter(t->t.getCountry().equals("中国")).map(t->new P(t.getName(),t.getAge())).forEach(System.out::println);

案例一:英文字符串数组的元素全部改为大写。整数数组每个元素+3

public class Test04 {
    public static void main(String[] args) {
        //字符串大写
        List<String> list = Arrays.asList("hello", "world", "java", "spring", "springmvc");
        list.stream().map(String::toUpperCase).forEach(System.out::println);
        //整数数组每个元素+3
        List<Integer> list2 = Arrays.asList(1, 3, 15, 23, 29);
        list2.stream().map(item->item+3).forEach(System.out::println);
    }
}

(4)收集 collect

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

  List<Person> personList = new ArrayList<>();
        personList.add(new Person("小梅",24,"中国",'F'));
        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("Tom",21,"中国",'F'));
        personList.add(new Person("李康",22,"中国",'M'));

        //把Person-年龄大于20人--里面名称----新的集合。
        List<String> collect = personList.stream().filter(item -> item.getAge() > 20).map(item -> item.getName()).collect(Collectors.toList());
        System.out.println(collect);

(5)sorted排序

List<Person> collect1 = personList.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).collect(Collectors.toList());
System.out.println(collect1);

(6) reduce规约

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。  

 

整型集合: -----求和

public class Test4 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Optional<Integer> reduce = list.stream().reduce((t1, t2) -> t1 + t2);
        System.out.println(reduce.get());
    }
}

(7)查询第一个findFirst

Optional<Person> first = personList.stream().filter(t -> t.getAge() >= 18 && t.getAge() <= 20).findFirst();
        Person person = first.get();
        System.out.println(person);

(8) 去重、合并(distinct、skip、limit)

流也可以进行合并、去重、限制、跳过等操作。

public class Test04 {
    public static void main(String[] args) {
        String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };

        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // concat:合并两个流 distinct:去重
        List<String> collect = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
       System.out.println("流合并"+collect);
        // limit:限制从流中获得前n个数据
       List<String> collect1 = Stream.concat(stream1, stream2).limit(3).collect(Collectors.toList());
        System.out.println("limit"+collect1);
        // skip:跳过前n个数据  这里的1代表把1代入后边的计算表达式
        List<String> collect2 = Stream.concat(stream1, stream2).skip(6).limit(3).collect(Collectors.toList());
        System.out.println("skip"+collect);
    }
}

(9)

anyMatch:判断的条件里,任意一个元素成功,返回true

allMatch:判断条件里的元素,所有的都是,返回true

noneMatch:与allMatch相反,判断条件里的元素,所有的都不是,返回true

  boolean name = personList.stream().anyMatch(t -> t.equals("张无忌"));
        System.out.println(name);

 (10)接合(joining)

joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。

public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
       return joining(delimiter, "", "");
   }
public class StreamTest {
	public static void main(String[] args) {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 23, "male", "New York"));
		personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

		String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
		System.out.println("所有员工的姓名:" + names);
		List<String> list = Arrays.asList("A", "B", "C");
		String string = list.stream().collect(Collectors.joining("-"));
		System.out.println("拼接后的字符串:" + string);
	}
}

运行结果:

 总结:

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

  2. 终止操作: forEach count() reduce() collect(Collectors.toList()) findFirst match

max min

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值