您的位置 首页 java

Java8新特性Stream的常见用法

Stream简介

Stream流是java 8 中新引入的特性,用来处理集合中的数据,它与 java .io 包里的 InputStream 和 OutputStream 是完全不同的概念。

Stream不是数据结构,也不保存数据,它是有关算法和计算的,更像一个高级版本的 迭代器 Iterator。原始版本的 Iterator,只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“判断是否包含某个字符”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。

Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,可以很方便地写出高性能的并发程序。

Stream的使用

流操作的类型有三种:

(1)创建流

(2)修改流元素(中间操作,Intermediate Operations)

(3)消费流元素(终端操作,Terminal Operations)

创建流

流有两种: (1)stream() : 创建串行流。(2)parallelStream() : 创建并行流。

并行流的特点就是将一个大任务切分成多个小任务,无序一起执行,当然如果我们需要顺序输出的话可以使用forEachOrdered,速度会比串行流快一些。它通过默认的 Fork JoinPool,可能提高你的 多线程 任务的速度。

(1) 通过Stream.of()将元素转化成流

 Stream.of创建流
 Stream <String> stream = Stream.of("你", "我", "她");  

(2)每个集合都可以通过调用 stream() 方法来产生一个流

 //
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 
List<String> list = Arrays.asList(strArray);
stream = list.stream();
//
Set<String> w = new HashSet<>(Arrays.asList(strArray))
stream = w.stream();  

使用举例

案例里使用的类

 class Person {
        private String name;  // 姓名
        private int salary; // 战斗力
        private int age; // 年龄
        private String sex; //性别
        private String area;  // 必杀技

        // 构造方法
        public Person(String name, int salary, int age,String sex,String area) {
            this.name = name;
            this.salary = salary;
            this.age = age;
            this.sex = sex;
            this.area = area;
        }

        public String getName() {
            return name;
        }

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

        public int getSalary() {
            return salary;
        }

        public void setSalary(int salary) {
            this.salary = salary;
        }

        public int getAge() {
            return age;
        }

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

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }

        public String getArea() {
            return area;
        }

        public void setArea(String area) {
            this.area = area;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + ''' +
                    ", salary=" + salary +
                    ", age=" + age +
                    ", sex='" + sex + ''' +
                    ", area='" + area + ''' +
                    '}';
        }
    }  

(1) 遍历/匹配(foreach/find/match)

Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Optional类是一个可以为null的容器对象,调用get()方法会返回该对象。

     @Test
    public void streamTest1() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
        personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
        personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
        personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
        personList.add(new Person("大蛇丸", 9500, 30, "1","八岐大蛇"));
        personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));

        // 遍历输出符合条件的对象, 战斗力大于8000
        personList.stream().filter(person -> person.getSalary() > 8000).forEach(System.out::println);
        // 匹配第一个
        Optional<Person> findFirst = personList.stream().filter(person -> person.getAge() > 18).findFirst();
        System.out.println("匹配第一个值:" + findFirst.get());
        // 匹配随机一个(适用于并行流)
        Optional<Person> findAny = personList.parallelStream().filter(person -> person.getAge() > 18).findAny();
        System.out.println("匹配随机一个值:" + findAny.get());
        // 是否包含符合特定条件  年龄大于20
        boolean anyMatch = personList.stream().anyMatch(person -> person.getAge() > 20);
        System.out.println("是否存在年龄大于20的:" + anyMatch);
    }  

运行结果:

Java8新特性Stream的常见用法

(2)筛选(filter)

筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

  @Test
    public void streamTest2() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
        personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
        personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
        personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
        personList.add(new Person("大蛇丸", 9500, 30, "1","八岐大蛇"));
        personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));

        //筛选出所有战斗力大于8000的
        List<Person> list =  personList.stream().filter(person -> person.getSalary() > 8000).collect(Collectors.toList());
        System.out.println("战斗力大于8000的值:" + list);
    }  

运行结果:

Java8新特性Stream的常见用法

(3)聚合(max/min/count/sum)

max、min、count、sum这些字眼你一定不陌生,没错,在 mysql 中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。

     @Test
    public void streamTest3() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
        personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
        personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
        personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
        personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
        personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));

        //获取年龄最大的
        Optional<Person> max = personList.stream().max(Comparator.comparing(Person::getAge));
        System.out.println("年龄最大的是:" + max.get());

        //获取战斗力最小的
        Optional<Person> min = personList.stream().min(Comparator.comparing(Person::getSalary));
        System.out.println("战斗力最小的是:" + min.get());

        //计算战斗力大于8000的有几个人
        long count = personList.stream().filter(person -> person.getSalary() > 8000).count();
        System.out.println("战斗力大于8000的人数是:" + count);

        //计算总年龄是多少
        int sum = personList.stream().mapToInt(person -> person.getAge()).sum();
        System.out.println("总年龄是是:" + sum);
    }  

运行结果:

Java8新特性Stream的常见用法

(4)排序(sorted)

stream中有两种排序:

sorted():自然排序,流中元素需实现Comparable接口

sorted(Comparator com):自定义排序,自定义Comparator排序器

     @Test
    public void streamTest4() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
        personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
        personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
        personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
        personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
        personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));

        //按战斗力升序排序(自然排序)
        List<Person> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).collect(Collectors.toList());
        System.out.println("按战斗力升序排序:" + newList);

        //按战斗力降序排序(自然排序)
        List<Person> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).collect(Collectors.toList());
        System.out.println("按战斗力降序排序:" + newList2);

        // 先按年龄再按战斗力排序(自定义排序 降序)
        List<Person> newList3 = personList.stream().sorted((p1, p2) -> {
            if (p1.getAge() == p2.getAge()) {
                return p2.getSalary() - p1.getSalary();
            } else {
                return p2.getAge() - p1.getAge();
            }
        }).collect(Collectors.toList());
        System.out.println("先按年龄再按战斗力:" + newList3);

    }  

运行结果:

Java8新特性Stream的常见用法

(5) 映射(map/flatMap)

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:

  • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

     @Test
    public void streamTest5() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
        personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
        personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
        personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
        personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
        personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));

        //将人物和必杀技组合,
        List<String> strList = personList.stream().map(person -> person.getName() + "-->" + person.getArea()).collect(Collectors.toList());
        System.out.println("人物和必杀技组合:" + strList);
        
    }  

运行结果:

Java8新特性Stream的常见用法

(6)归约(reduce)

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

     @Test
    public void streamTest6() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
        personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
        personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
        personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
        personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
        personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));

        //求战斗力总和 方式1
         Integer  sum = personList.stream().map(Person::getSalary).reduce((x,y) -> x + y).get();
        System.out.println("战斗力总和(方式1):" + sum);
        //求战斗力总和 方式2
        Integer sum2 = personList.stream().map(Person::getSalary).reduce(Integer::sum).get();
        System.out.println("战斗力总和(方式2):" + sum2);
        //求战斗力总和 方式3
        Integer sum3 = personList.stream().map(Person::getSalary).reduce(0,Integer::sum);
        System.out.println("战斗力总和(方式3):" + sum3);
        //求年龄的乘积
        Integer product  = personList.stream().map(Person::getAge).reduce((x,y) -> x * y).get();
        System.out.println("年龄的乘积:" + product);
        //求战斗力最大的值
        Integer max  = personList.stream().map(Person::getSalary).reduce(1,Integer::max);
        System.out.println("斗力最大的值:" + max);
    }  

运行结果:

Java8新特性Stream的常见用法

(7)收集(collect)

收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。主要依赖java.util.stream.Collectors类内置的静态方法。

(8)归集(toList/toSet/toMap)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap是比较常见的用法

 @Test
    public void streamTest7() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("鸣人", 8900, 18, "1", "螺旋丸"));
        personList.add(new Person("佐助", 8800, 18, "1", "须佐能乎"));
        personList.add(new Person("小樱", 7800, 17, "2", "治疗术"));
        personList.add(new Person("自来也", 8200, 30, "1", "通灵术"));
        personList.add(new Person("大蛇丸", 9500, 31, "1", "八岐大蛇"));
        personList.add(new Person("纲手", 7900, 29, "2", "百豪之术"));

        //必杀技list集合
        List<String> list = personList.stream().map(person -> person.getArea()).collect(Collectors.toList());
        System.out.println("必杀技集合toList:" + list);

        //大于18的年龄set集合
        Set<Integer> set = personList.stream().filter(person -> person.getAge() > 18).map(Person::getAge).collect(Collectors.toSet());
        System.out.println("大于18的年龄集合toSet:" + set);

        //战斗力大于8000的map集合 (写法1)
        Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
                .collect(Collectors.toMap(Person::getName, p -> p));
        System.out.println("战斗力大于8000的集合toMap:" + map);
        //战斗力大于8000的map集合 (写法2)
        Map<?, Person> map2 = personList.stream().filter(p -> p.getSalary() > 8000)
                .collect(Collectors.toMap(Person::getName, Function.identity()));
        System.out.println("战斗力大于8000的集合toMap:" + map2);
    }  

运行结果:

Java8新特性Stream的常见用法

总结

好了,以上就是我总结的Stream的常见用法,感谢大家的阅读,如果有什么疑问或者建议,欢迎评论区留下你的独到见解~

文章来源:智云一二三科技

文章标题:Java8新特性Stream的常见用法

文章地址:https://www.zhihuclub.com/190049.shtml

关于作者: 智云科技

热门文章

网站地图