stream 订阅
Stream泛指流媒体技术。流媒体实际指的是一种新的媒体传送方式,而非一种新的媒体,是指采用流式传输的方式在Internet播放的媒体格式。可指大河,也可指小河或小溪,指小溪时与brook,creek同义。creek侧重其狭长蜿蜒,缓缓流动,且多流入大河或湖泊。brook侧重发源于山泉。creek和stream都比brook大。stream还可引申表示事物连绵不断。stream还可作动词,意为“流动,飘动”。常用作不及物动词,也可用作及物动词。 展开全文
Stream泛指流媒体技术。流媒体实际指的是一种新的媒体传送方式,而非一种新的媒体,是指采用流式传输的方式在Internet播放的媒体格式。可指大河,也可指小河或小溪,指小溪时与brook,creek同义。creek侧重其狭长蜿蜒,缓缓流动,且多流入大河或湖泊。brook侧重发源于山泉。creek和stream都比brook大。stream还可引申表示事物连绵不断。stream还可作动词,意为“流动,飘动”。常用作不及物动词,也可用作及物动词。
信息
外文名
Stream
基本解释
泛指流媒体技术
词    性
动词,名词
中文名
流媒体技术
stream英语单词
基本释义v. [striːm] ( streams; streamed; streaming )vt. & vi. 流; 移动 flow freely; move continuously and smoothly in one directionvi. 飘扬; 招展 float or wave (in the wind)词语要点1.stream的基本意思是“流动”,指受限制的流动,如通过一定的路线或出口。也可指大量不断地流动。引申可指“飘动”。2.stream既可用作及物动词,也可用作不及物动词。用作及物动词时,可接名词或代词作宾语。3.stream接介词with表示“被…覆盖”。词语搭配~+副词stream torrentially 激流涌进stream back 向后飘动stream in 络绎进入~+介词stream behind 在…后面飘动stream down one's cheeks (眼泪)从脸颊流下stream into the auditorium (人群)络绎不绝进入礼堂stream out of the station (人群)涌出车站stream with 被…覆盖辨析pour, flow, run, stream这组词的共同意思是“流”“流动”。其区别是:1.flow, run, stream和pour都可指液体流动; flow还可指气体流动; pour还可指光线、微粒等倾泻。2.时间上:flow一般指源源不断地、长时间地流动; run既可以是源源不断地、长时间地流动,也可以是流动一段时间; stream和pour多指短时间地流动。3.方向上:指液体流动时, flow是水平流动; run和stream既可水平流动,也可垂直流动; pour是垂直流动。4.流速上:从快到慢依次为pour, stream, run, flow。具体说就是flow是平平稳稳地流动; run比较湍急; stream比run更有力; pour则是“倾泻”。5.flow, stream和pour常用于比喻, run很少用于比喻。例如:The river was flowing quietly.河水静静流着。She let her hair down so that it flew darkly over her shoulders.她让乌黑的头发披散下来,飘垂到肩上。  The river runs through hills and fields.河水流经山冈和田野。The water runs out of the pipe into the bucket.水自管内注入水桶中。Tears were streaming down her face.她脸上热泪滚滚而下。The students streamed into the auditorium.学生们络绎不绝地进入礼堂。下面三句话的意思相同:She poured me a cup of tea.She poured a cup of tea for me.She poured me out a cup of tea.她给我倒了一杯茶。词源<古英语stream(流动)基本释义C 小河,溪流 a small river C 流,一股,一串 flow (of liquid, people, things, etc.)S 水流方向,潮流 current or direction of sth flowing or movingC (按能力分的)班级 class or division of a class into which children of the same age and level of ability are placedC 川流不息 a continuous series of people, things, or events, usually moving in a line or in a certain direction常见搭配动词+~cross a stream 涉过一条小溪tap a stream 引流形容词+~clear〔dancing, quiet, running〕 stream 清澈〔奔腾欢跳,平静,流动〕的溪流rapid〔strong〕 stream 湍急〔强劲〕的水流rushing stream 激流名词+~mountain stream 山涧sun streams 太阳光线介词+~in streams 连续不断,川流不息on stream 进行生产,投入生产up the stream 向〔在〕上游~+介词a stream of light 一缕光线a stream of words 滔滔不绝的话the stream of history 历史潮流词语辨析branch,brook,canal,creek,river,stream,torrent这组词的共同意思是“流水的通道”。其区别是:1.除canal指人工开挖的河流或渠道外,其余各词均指自然形成的水道。2.river和torrent均指流量较大的河流,river可泛指(自然形成的)江河;torrent则特指急流、湍流。这两个词还常用于比喻。3.stream可指大河,也可指小河或小溪,指小溪时与brook,creek同义。creek侧重其狭长蜿蜒,缓缓流动,且多流入大河或湖泊。brook侧重发源于山泉。creek和stream都比brook大。stream还可引申表示事物连绵不断。4.branch指江河的支流。同义词n. brook, course, flow, rush, streamlet [1] 
收起全文
精华内容
下载资源
问答
  • stream
    千次阅读 多人点赞
    2022-03-13 22:32:49

    个人简介

    作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。

    JDK8新特性-Stream流

    教程概述

    • 本教程附有非常多的例子,看完肯定能懂Stream流!
    • 看完本教程,对于Stream api基本的使用完全没有问题,底层原理则不会深究!
    • 本教程借鉴过很多其他大佬的教程,并进行总结创新,难免会有相同之处。

    Stream流的创建

    用集合创建流

    	  //创建普通顺序流
          Stream<Integer> stream = asList.stream();
    
          //创建并行流
          Stream<Integer> parallelStream = asList.parallelStream();
    

    用数组创建流

    	  int arr[]={1,2,3,4,5};
          IntStream intStream = Arrays.stream(arr);
    

    使用Stream的静态方法创建流

    Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
    

    顺序流转换成并行流

    	  List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5);
          //创建顺序流
          Stream<Integer> integerStream = asList.stream();
          //把顺序流转换成并行流
          Stream<Integer> parallel = integerStream.parallel();
    

    实体类Person:

    class Person {
        private String name;  // 姓名
        private double salary; // 薪资
        private int age; // 年龄
    
        public Person(String name, double salary, int age) {
            this.name = name;
            this.salary = salary;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", salary=" + salary +
                    ", age=" + age +
                    '}';
        }
    }
    

    流的遍历和查找元素(forEach、find)

    遍历Stream顺序流

    	  List<Person> list=new ArrayList<>();
    
          list.add(new Person("z1",2000.0,18));
          list.add(new Person("z2",3200.0,15));
          list.add(new Person("z3",1500.0,27));
          list.add(new Person("z4",7000.0,36));
          list.add(new Person("z5",5000.0,22));
          list.add(new Person("z6",4200.0,42));	  
    	  //创建Stream顺序流
          Stream<Person> stream = list.stream();
          //遍历Stream顺序流
          stream.forEach(System.out::println);
    

    遍历并行流(多线程,输出顺序会不一样)

    	  //创建并行流(多线程)
          Stream<Person> parallelStream = list.parallelStream();
    	  //遍历并行流(多线程,输出顺序会不一样)
    	  parallelStream.forEach(System.out::println);
    

    找出流中第一个元素

    	  Optional<Person> first = stream.findFirst();
          System.out.println(first.get());
    

    流的筛选(filter)

    案例1:集合中大于5的元素,并打印出来

    	  List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
    
          Stream<Integer> stream = list.stream();
    
          //1:集合中大于5的元素,并打印出来
          stream.filter(el->el>5).forEach(System.out::println);
    

    案例2:筛选年龄大于25岁的人,并形成一个只有name的新的集合

    	  List<Person> personList = new ArrayList<Person>();
          personList.add(new Person("z1",2000.0,18));
          personList.add(new Person("z2",3200.0,15));
          personList.add(new Person("z3",1500.0,27));
          personList.add(new Person("z4",7000.0,36));
          personList.add(new Person("z5",5000.0,22));
          personList.add(new Person("z6",4200.0,42));
    
          Stream<Person> personStream = personList.stream();
    
          List<String> collect = personStream
                  .filter(person -> person.getAge() > 25)
              	  //只筛选出name,如果直接collect则返回的是person对象
                  .map(Person::getName) 
                  .collect(Collectors.toList());
          collect.forEach(System.out::println);
    

    聚合(max、min、count)

    案例3:获取String集合中最长的元素

    	 List<String> list1 = Arrays.asList("qdiq", "sdji", "aaa", "ihduxdswaa", "qwer");
    
          Stream<String> stream1 = list1.stream();
    
          Optional<String> maxString = stream1.max(Comparator.comparing(String::length));
          System.out.println("maxString="+maxString.get());
    

    案例4:比较集合中数字最大的并输出

    	  List<Integer> integerList = Arrays.asList(20, 10, 30, 52, 42, 15, 11, 13, 19, 30);
    
          Stream<Integer> integerStream = integerList.stream();
    
          Optional<Integer> optionalInteger = integerStream.max(Comparator.comparing(Integer::intValue));
          System.out.println(optionalInteger.get());
    

    案例5:计算Integer集合中大于6的元素的个数

    	  List<Integer> list2 = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
          long count = list2.stream().filter(integer -> integer > 6).count();
          System.out.println("集合中大于6的个数="+count);
    

    映射(map)

    • 可以直接操作每一个流的元素
    • 凡是需要操作流中元素的都用map,filter只是起到筛选的作用

    案例6:英文字符串数组的元素全部改为大写

    	  Stream<String> stream = Arrays.stream(strArr);
    
          //s就是每一个元素
          List<String> collect = stream.map(s -> s.toUpperCase()).collect(Collectors.toList());
    
          collect.forEach(System.out::println);
    

    案例7:整数数组每个元素+3

    	  List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
    
          Stream<Integer> stream1 = intList.stream();
          stream1.map(integer -> integer+=3).collect(Collectors.toList()).forEach(System.out::println);
    

    案例8:将员工的薪资全部增加1000

    	  List<Person> personList = new ArrayList<Person>();
          personList.add(new Person("z1",2000.0,18));
          personList.add(new Person("z2",3200.0,15));
          personList.add(new Person("z3",1500.0,27));
          personList.add(new Person("z4",7000.0,36));
          personList.add(new Person("z5",5000.0,22));
          personList.add(new Person("z6",4200.0,42));
    
          Stream<Person> personStream = personList.stream();
    
          personStream.map(person -> {
              double old = person.getSalary();
              person.setSalary(old+1000); //增加1000
              return person; //返回原对象
          }).collect(Collectors.toList()).forEach(System.out::println);
    

    归约(reduce)

    • 把一个流缩减成一个值
    • 作用:实现一个流的加法、乘法、求最值等计算

    整个流的加法、乘法、最大值

    	  List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
    
          Stream<Integer> stream = list.stream();
    
          //整个流的加法
          Optional<Integer> add = stream.reduce((x, y) -> x + y);
          System.out.println(add.get());
    
          //整个流的乘法
          Optional<Integer> num = stream.reduce((x, y) -> x * y);
          System.out.println(num.get());
    
          //最大值
          Optional<Integer> maxNumber = stream.reduce((x, y) -> x > y ? x : y);
          System.out.println(maxNumber.get());
    

    案例9:求所有员工的工资之和。

    	  List<Person> personList = new ArrayList<Person>();
          personList.add(new Person("z1",2000.0,18));
          personList.add(new Person("z2",3200.0,15));
          personList.add(new Person("z3",1500.0,27));
          personList.add(new Person("z4",7000.0,36));
          personList.add(new Person("z5",5000.0,22));
          personList.add(new Person("z6",4200.0,42));
    	  Stream<Person> personStream1 = personList.parallelStream();
          Optional<Double> sum = personStream1
                  //指定选择操作薪资
                  .map(person -> person.getSalary())
                  .reduce((x, y) -> x + y);
          System.out.println(sum.get());
    

    案例10:最高工资

    	  List<Person> personList = new ArrayList<Person>();
          personList.add(new Person("z1",2000.0,18));
          personList.add(new Person("z2",3200.0,15));
          personList.add(new Person("z3",1500.0,27));
          personList.add(new Person("z4",7000.0,36));
          personList.add(new Person("z5",5000.0,22));
          personList.add(new Person("z6",4200.0,42));
    	  Stream<Person> personStream2 = personList.parallelStream();
          Optional<Double> max = personStream2
                  //指定操作salary
                  .map(person -> person.getSalary())
                  .reduce((x, y) -> x > y ? x : y);
          System.out.println(max.get());
    

    收集(collect)

    Stream流转List(toList)

    	List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
        Stream<Integer> parallel1 = list.stream().parallel();
    	List<Integer> list1 = parallel1.collect(Collectors.toList());
        list1.forEach(System.out::println);
    

    Stream流转Set(toSet)

    	List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
        Stream<Integer> parallel1 = list.stream().parallel();
    	Set<Integer> set = parallel2.collect(Collectors.toSet());
        set.forEach(System.out::println);
    

    Stream流转Map(toMap)

    	List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("z1", 2000.0, 18));
        personList.add(new Person("z2", 3200.0, 15));
        personList.add(new Person("z3", 1500.0, 27));
        personList.add(new Person("z4", 7000.0, 36));
        personList.add(new Person("z5", 5000.0, 22));
        personList.add(new Person("z6", 4200.0, 42));
        Stream<Person> personStream = personList.stream().parallel();
        Map<String, Person> map =
            personStream
                // toMap(k, v)
                .collect(Collectors.toMap(x -> x.getName(), y -> y));
    
    	// lambda遍历map
        map.forEach(
            (k, v) -> {
              System.out.println("key=" + k + ",v=" + v);
            });
    

    案例11:求流的平均值

    	List<Integer> list2 = Arrays.asList(1, 2, 3, 4, 10);
    
        Stream<Integer> integerStream = list2.stream();
    
        Double averag = integerStream.collect(Collectors.averagingInt(x -> x));
        System.out.println(averag);
    

    排序(sorted)

    排序注意点

    • 排序不能用并行流,否则将失效

    案例12:对纯数字进行排序

    	  List<Integer> list = Arrays.asList(12, 5, 6, 3, 2, 9, 22, 17, 15, 13, 6, 5, 1);
          Stream<Integer> integerStream1 = list.stream();
          //1:对纯数字进行排序
          integerStream1.sorted(Comparator.comparingInt(x->x)).forEach(System.out::println);
    

    案例13:将对象的薪资属性进行排序

    	  List<Person> personList = new ArrayList<Person>();
          personList.add(new Person("z1",2000.0,18));
          personList.add(new Person("z2",3200.0,15));
          personList.add(new Person("z3",1500.0,27));
          personList.add(new Person("z4",7000.0,36));
          personList.add(new Person("z5",5000.0,22));
          personList.add(new Person("z6",4200.0,42));
    
          Stream<Person> stream = personList.stream();
    
          stream.sorted(Comparator.comparing(el->el.getSalary())).forEach(System.out::println);
    

    去重和限制(distinct、limit)

    	  List<Integer> list = Arrays.asList(3, 6, 6, 2, 3, 1, 2, 9, 12, 15);
          Stream<Integer> stream = list.stream();
          stream
                  //去重
                  .distinct()
                  //分页,限制最多输出前几个
                  .limit(3)
                  .forEach(System.out::println);
    
    更多相关内容
  • Java8 Stream横空出世,让我们从繁琐冗长的迭代中解脱出来,集合数据操作变得优雅简洁。 这些操作:集合的filter(筛选)、归约(reduce)、映射(map)、收集(collect)、统计(max、min、avg)等等,一行代码即可...

    点波关注不迷路,一键三连好运连连!
    博客的示例代码已大部分整理在Github中:https://github.com/ThinkMugz/springboot-demo-major ,需要的伙伴儿自取

    免费在线作图工具,点击邀请链接注册赠送7天会员:https://www.processon.com/i/5c51384de4b08a7683b99e16
    在这里插入图片描述

    先贴上几个案例,水平高超的同学可以挑战一下:

    1. 从员工集合中筛选出salary大于8000的员工,并放置到新的集合里。
    2. 统计员工的最高薪资、平均薪资、薪资之和。
    3. 将员工按薪资从高到低排序,同样薪资者年龄小者在前。
    4. 将员工按性别分类,将员工按性别和地区分类,将员工按薪资是否高于8000分为两部分。

    用传统的迭代处理也不是很难,但代码就显得冗余了,跟Stream相比高下立判。

    1 Stream概述

    Java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。

    那么什么是Stream

    Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。

    Stream可以由数组或集合创建,对流的操作分为两种:

    1. 中间操作,每次返回一个新的流,可以有多个。
    2. 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

    另外,Stream有几个特性:

    1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
    2. stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
    3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

    2 Stream的创建

    Stream可以通过集合数组创建。

    1、通过 java.util.Collection.stream() 方法用集合创建流

    List<String> list = Arrays.asList("a", "b", "c");
    // 创建一个顺序流
    Stream<String> stream = list.stream();
    // 创建一个并行流
    Stream<String> parallelStream = list.parallelStream();
    

    2、使用java.util.Arrays.stream(T[] array)方法用数组创建流

    int[] array={1,3,5,6,8};
    IntStream stream = Arrays.stream(array);
    

    3、使用Stream的静态方法:of()、iterate()、generate()

    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
    
    Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
    stream2.forEach(System.out::println);
    
    Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
    stream3.forEach(System.out::println);
    

    输出结果:

    0 3 6 9
    0.6796156909271994
    0.1914314208854283
    0.8116932592396652

    streamparallelStream的简单区分: stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:
    在这里插入图片描述
    如果流中的数据量足够大,并行流可以加快处速度。

    除了直接创建并行流,还可以通过parallel()把顺序流转换成并行流:

    Optional<Integer> findFirst = list.stream().parallel().filter(x->x>6).findFirst();
    

    3 Stream的使用

    在使用stream之前,先理解一个概念:Optional

    Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
    更详细说明请见:菜鸟教程Java 8 Optional类

    接下来,大批代码向你袭来!我将用20个案例将Stream的使用整得明明白白,只要跟着敲一遍代码,就能很好地掌握。
    在这里插入图片描述

    案例使用的员工类

    这是后面案例中使用的员工类:

    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person("Tom", 8900, "male", "New York"));
    personList.add(new Person("Jack", 7000, "male", "Washington"));
    personList.add(new Person("Lily", 7800, "female", "Washington"));
    personList.add(new Person("Anni", 8200, "female", "New York"));
    personList.add(new Person("Owen", 9500, "male", "New York"));
    personList.add(new Person("Alisa", 7900, "female", "New York"));
    
    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;
    	}
    	// 省略了get和set,请自行添加
    
    }
    

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

    Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Stream的遍历、匹配非常简单。
    在这里插入图片描述

    // import已省略,请自行添加,后面代码亦是
    
    public class StreamTest {
    	public static void main(String[] args) {
            List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
    
            // 遍历输出符合条件的元素
            list.stream().filter(x -> x > 6).forEach(System.out::println);
            // 匹配第一个
            Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
            // 匹配任意(适用于并行流)
            Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
            // 是否包含符合特定条件的元素
            boolean anyMatch = list.stream().anyMatch(x -> x > 6);
            System.out.println("匹配第一个值:" + findFirst.get());
            System.out.println("匹配任意一个值:" + findAny.get());
            System.out.println("是否存在大于6的值:" + anyMatch);
        }
    }
    

    3.2 筛选(filter)

    筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。
    在这里插入图片描述

    案例一:筛选出Integer集合中大于7的元素,并打印出来

    public class StreamTest {
    	public static void main(String[] args) {
    		List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
    		Stream<Integer> stream = list.stream();
    		stream.filter(x -> x > 7).forEach(System.out::println);
    	}
    }
    

    预期结果:

    8 9

    案例二: 筛选员工中工资高于8000的人,并形成新的集合。 形成新集合依赖collect(收集),后文有详细介绍。

    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"));
    		personList.add(new Person("Anni", 8200, 24, "female", "New York"));
    		personList.add(new Person("Owen", 9500, 25, "male", "New York"));
    		personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
    
    		List<String> fiterList = personList.stream().filter(x -> x.getSalary() > 8000).map(Person::getName)
    				.collect(Collectors.toList());
    		System.out.print("高于8000的员工姓名:" + fiterList);
    	}
    }
    

    运行结果:

    高于8000的员工姓名:[Tom, Anni, Owen]

    3.3 聚合(max/min/count)

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

    案例一:获取String集合中最长的元素。

    public class StreamTest {
    	public static void main(String[] args) {
    		List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");
    
    		Optional<String> max = list.stream().max(Comparator.comparing(String::length));
    		System.out.println("最长的字符串:" + max.get());
    	}
    }
    

    输出结果:

    最长的字符串:weoujgsd

    案例二:获取Integer集合中的最大值。

    public class StreamTest {
    	public static void main(String[] args) {
    		List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6);
    
    		// 自然排序
    		Optional<Integer> max = list.stream().max(Integer::compareTo);
    		// 自定义排序
    		Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
    			@Override
    			public int compare(Integer o1, Integer o2) {
    				return o1.compareTo(o2);
    			}
    		});
    		System.out.println("自然排序的最大值:" + max.get());
    		System.out.println("自定义排序的最大值:" + max2.get());
    	}
    }
    

    输出结果:

    自然排序的最大值:11
    自定义排序的最大值:11

    案例三:获取员工工资最高的人。

    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"));
    		personList.add(new Person("Anni", 8200, 24, "female", "New York"));
    		personList.add(new Person("Owen", 9500, 25, "male", "New York"));
    		personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
    
    		Optional<Person> max = personList.stream().max(Comparator.comparingInt(Person::getSalary));
    		System.out.println("员工工资最大值:" + max.get().getSalary());
    	}
    }
    

    输出结果:

    员工工资最大值:9500

    案例四:计算Integer集合中大于6的元素的个数。

    import java.util.Arrays;
    import java.util.List;
    
    public class StreamTest {
    	public static void main(String[] args) {
    		List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
    
    		long count = list.stream().filter(x -> x > 6).count();
    		System.out.println("list中大于6的元素个数:" + count);
    	}
    }
    

    输出结果:

    list中大于6的元素个数:4

    3.4 映射(map/flatMap)

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

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

    在这里插入图片描述
    在这里插入图片描述
    案例一:英文字符串数组的元素全部改为大写。整数数组每个元素+3。

    public class StreamTest {
    	public static void main(String[] args) {
    		String[] strArr = { "abcd", "bcdd", "defde", "fTr" };
    		List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
    
    		List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
    		List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
    
    		System.out.println("每个元素大写:" + strList);
    		System.out.println("每个元素+3:" + intListNew);
    	}
    }
    

    输出结果:

    每个元素大写:[ABCD, BCDD, DEFDE, FTR]
    每个元素+3:[4, 6, 8, 10, 12, 14]

    案例二:将员工的薪资全部增加1000。

    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"));
    		personList.add(new Person("Anni", 8200, 24, "female", "New York"));
    		personList.add(new Person("Owen", 9500, 25, "male", "New York"));
    		personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
    
    		// 不改变原来员工集合的方式
    		List<Person> personListNew = personList.stream().map(person -> {
    			Person personNew = new Person(person.getName(), 0, 0, null, null);
    			personNew.setSalary(person.getSalary() + 10000);
    			return personNew;
    		}).collect(Collectors.toList());
    		System.out.println("一次改动前:" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());
    		System.out.println("一次改动后:" + personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());
    
    		// 改变原来员工集合的方式
    		List<Person> personListNew2 = personList.stream().map(person -> {
    			person.setSalary(person.getSalary() + 10000);
    			return person;
    		}).collect(Collectors.toList());
    		System.out.println("二次改动前:" + personList.get(0).getName() + "-->" + personListNew.get(0).getSalary());
    		System.out.println("二次改动后:" + personListNew2.get(0).getName() + "-->" + personListNew.get(0).getSalary());
    	}
    }
    

    输出结果:

    一次改动前:Tom–>8900
    一次改动后:Tom–>18900
    二次改动前:Tom–>18900
    二次改动后:Tom–>18900

    案例三:将两个字符数组合并成一个新的字符数组。

    public class StreamTest {
    	public static void main(String[] args) {
    		List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7");
    		List<String> listNew = list.stream().flatMap(s -> {
    			// 将每个元素转换成一个stream
    			String[] split = s.split(",");
    			Stream<String> s2 = Arrays.stream(split);
    			return s2;
    		}).collect(Collectors.toList());
    
    		System.out.println("处理前的集合:" + list);
    		System.out.println("处理后的集合:" + listNew);
    	}
    }
    

    输出结果:

    处理前的集合:[m-k-l-a, 1-3-5]
    处理后的集合:[m, k, l, a, 1, 3, 5]

    3.5 归约(reduce)

    归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
    在这里插入图片描述

    案例一:求Integer集合的元素之和、乘积和最大值。

    public class StreamTest {
    	public static void main(String[] args) {
    		List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
    		// 求和方式1
    		Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
    		// 求和方式2
    		Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
    		// 求和方式3
    		Integer sum3 = list.stream().reduce(0, Integer::sum);
    		
    		// 求乘积
    		Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
    
    		// 求最大值方式1
    		Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
    		// 求最大值写法2
    		Integer max2 = list.stream().reduce(1, Integer::max);
    
    		System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3);
    		System.out.println("list求积:" + product.get());
    		System.out.println("list求和:" + max.get() + "," + max2);
    	}
    }
    

    输出结果:

    list求和:29,29,29
    list求积:2112
    list求和:11,11

    案例二:求所有员工的工资之和和最高工资。

    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"));
    		personList.add(new Person("Anni", 8200, 24, "female", "New York"));
    		personList.add(new Person("Owen", 9500, 25, "male", "New York"));
    		personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
    
    		// 求工资之和方式1:
    		Optional<Integer> sumSalary = personList.stream().map(Person::getSalary).reduce(Integer::sum);
    		// 求工资之和方式2:
    		Integer sumSalary2 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(),
    				(sum1, sum2) -> sum1 + sum2);
    		// 求工资之和方式3:
    		Integer sumSalary3 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);
    
    		// 求最高工资方式1:
    		Integer maxSalary = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),
    				Integer::max);
    		// 求最高工资方式2:
    		Integer maxSalary2 = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),
    				(max1, max2) -> max1 > max2 ? max1 : max2);
    
    		System.out.println("工资之和:" + sumSalary.get() + "," + sumSalary2 + "," + sumSalary3);
    		System.out.println("最高工资:" + maxSalary + "," + maxSalary2);
    	}
    }
    

    输出结果:

    工资之和:49300,49300,49300
    最高工资:9500,9500

    3.6 收集(collect)

    collect,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。

    collect主要依赖java.util.stream.Collectors类内置的静态方法。

    3.6.1 归集(toList/toSet/toMap)

    因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toListtoSettoMap比较常用,另外还有toCollectiontoConcurrentMap等复杂一些的用法。

    下面用一个案例演示toListtoSettoMap

    public class StreamTest {
    	public static void main(String[] args) {
    		List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
    		List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
    		Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
    
    		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"));
    		personList.add(new Person("Anni", 8200, 24, "female", "New York"));
    		
    		Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
    				.collect(Collectors.toMap(Person::getName, p -> p));
    		System.out.println("toList:" + listNew);
    		System.out.println("toSet:" + set);
    		System.out.println("toMap:" + map);
    	}
    }
    

    运行结果:

    toList:[6, 4, 6, 6, 20]
    toSet:[4, 20, 6]
    toMap:{Tom=mutest.Person@5fd0d5ae, Anni=mutest.Person@2d98a335}

    3.6.2 统计(count/averaging)

    Collectors提供了一系列用于数据统计的静态方法:

    • 计数:count
    • 平均值:averagingIntaveragingLongaveragingDouble
    • 最值:maxByminBy
    • 求和:summingIntsummingLongsummingDouble
    • 统计以上所有:summarizingIntsummarizingLongsummarizingDouble

    案例:统计员工人数、平均工资、工资总额、最高工资。

    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"));
    
    		// 求总数
    		Long count = personList.stream().collect(Collectors.counting());
    		// 求平均工资
    		Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
    		// 求最高工资
    		Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
    		// 求工资之和
    		Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
    		// 一次性统计所有信息
    		DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
    
    		System.out.println("员工总数:" + count);
    		System.out.println("员工平均工资:" + average);
    		System.out.println("员工工资总和:" + sum);
    		System.out.println("员工工资所有统计:" + collect);
    	}
    }
    

    运行结果:

    员工总数:3
    员工平均工资:7900.0
    员工工资总和:23700
    员工工资所有统计:DoubleSummaryStatistics{count=3, sum=23700.000000,min=7000.000000, average=7900.000000, max=8900.000000}

    3.6.3 分组(partitioningBy/groupingBy)

    • 分区:将stream按条件分为两个Map,比如员工按薪资是否高于8000分为两部分。
    • 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。

    在这里插入图片描述

    案例:将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组

    public class StreamTest {
    	public static void main(String[] args) {
    		List<Person> personList = new ArrayList<Person>();
    		personList.add(new Person("Tom", 8900, "male", "New York"));
    		personList.add(new Person("Jack", 7000, "male", "Washington"));
    		personList.add(new Person("Lily", 7800, "female", "Washington"));
    		personList.add(new Person("Anni", 8200, "female", "New York"));
    		personList.add(new Person("Owen", 9500, "male", "New York"));
    		personList.add(new Person("Alisa", 7900, "female", "New York"));
    
    		// 将员工按薪资是否高于8000分组
            Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
            // 将员工按性别分组
            Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
            // 将员工先按性别分组,再按地区分组
            Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
            System.out.println("员工按薪资是否大于8000分组情况:" + part);
            System.out.println("员工按性别分组情况:" + group);
            System.out.println("员工按性别、地区:" + group2);
    	}
    }
    

    输出结果:

    员工按薪资是否大于8000分组情况:{false=[mutest.Person@2d98a335, mutest.Person@16b98e56, mutest.Person@7ef20235], true=[mutest.Person@27d6c5e0, mutest.Person@4f3f5b24, mutest.Person@15aeb7ab]}
    员工按性别分组情况:{female=[mutest.Person@16b98e56, mutest.Person@4f3f5b24, mutest.Person@7ef20235], male=[mutest.Person@27d6c5e0, mutest.Person@2d98a335, mutest.Person@15aeb7ab]}
    员工按性别、地区:{female={New York=[mutest.Person@4f3f5b24, mutest.Person@7ef20235], Washington=[mutest.Person@16b98e56]}, male={New York=[mutest.Person@27d6c5e0, mutest.Person@15aeb7ab], Washington=[mutest.Person@2d98a335]}}
    

    3.6.4 接合(joining)

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

    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);
    	}
    }
    

    运行结果:

    所有员工的姓名:Tom,Jack,Lily
    拼接后的字符串:A-B-C

    3.6.5 归约(reducing)

    Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对自定义归约的支持。

    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"));
    
    		// 每个员工减去起征点后的薪资之和(这个例子并不严谨,但一时没想到好的例子)
    		Integer sum = personList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> (i + j - 5000)));
    		System.out.println("员工扣税薪资总和:" + sum);
    
    		// stream的reduce
    		Optional<Integer> sum2 = personList.stream().map(Person::getSalary).reduce(Integer::sum);
    		System.out.println("员工薪资总和:" + sum2.get());
    	}
    }
    

    运行结果:

    员工扣税薪资总和:8700
    员工薪资总和:23700

    3.7 排序(sorted)

    sorted,中间操作。有两种排序:

    • sorted():自然排序,流中元素需实现Comparable接口
    • sorted(Comparator com):Comparator排序器自定义排序

    案例:将员工按工资由高到低(工资一样则按年龄由大到小)排序

    public class StreamTest {
    	public static void main(String[] args) {
    		List<Person> personList = new ArrayList<Person>();
    
    		personList.add(new Person("Sherry", 9000, 24, "female", "New York"));
    		personList.add(new Person("Tom", 8900, 22, "male", "Washington"));
    		personList.add(new Person("Jack", 9000, 25, "male", "Washington"));
    		personList.add(new Person("Lily", 8800, 26, "male", "New York"));
    		personList.add(new Person("Alisa", 9000, 26, "female", "New York"));
    
    		// 按工资升序排序(自然排序)
    		List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
    				.collect(Collectors.toList());
    		// 按工资倒序排序
    		List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
    				.map(Person::getName).collect(Collectors.toList());
    		// 先按工资再按年龄升序排序
    		List<String> newList3 = personList.stream()
    				.sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
    				.collect(Collectors.toList());
    		// 先按工资再按年龄自定义排序(降序)
    		List<String> newList4 = personList.stream().sorted((p1, p2) -> {
    			if (p1.getSalary() == p2.getSalary()) {
    				return p2.getAge() - p1.getAge();
    			} else {
    				return p2.getSalary() - p1.getSalary();
    			}
    		}).map(Person::getName).collect(Collectors.toList());
    
    		System.out.println("按工资升序排序:" + newList);
    		System.out.println("按工资降序排序:" + newList2);
    		System.out.println("先按工资再按年龄升序排序:" + newList3);
    		System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
    	}
    }
    

    运行结果:

    按工资升序排序:[Lily, Tom, Sherry, Jack, Alisa]
    按工资降序排序:[Sherry, Jack, Alisa, Tom, Lily]
    先按工资再按年龄升序排序:[Lily, Tom, Sherry, Jack, Alisa]
    先按工资再按年龄自定义降序排序:[Alisa, Jack, Sherry, Tom, Lily]

    3.8 提取/组合

    流也可以进行合并、去重、限制、跳过等操作。
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    public class StreamTest {
    	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> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
    		// limit:限制从流中获得前n个数据
    		List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
    		// skip:跳过前n个数据
    		List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
    
    		System.out.println("流合并:" + newList);
    		System.out.println("limit:" + collect);
    		System.out.println("skip:" + collect2);
    	}
    }
    

    运行结果:

    流合并:[a, b, c, d, e, f, g]
    limit:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
    skip:[3, 5, 7, 9, 11]

    好,以上就是全部内容,能坚持看到这里,你一定很有收获,那么动一动拿offer的小手,点个赞再走吧,听说这么做的人2021年都交了好运!

    展开全文
  • Elecard.Streameye.Tools v4.0,一个强大的视频序列或码流分析软件,YUV分析,264文件分析软件,H.264视频编解码学习必备的东西,Elecard StreamEye Suite是一套用于专业视频压缩领域的功能强大的工具 ,能够帮助...
  • Java 8 Stream常用方法学习

    万次阅读 多人点赞 2021-01-21 09:21:11
    Stream Stream流是 Java8 API 新增的一个处理集合的关键抽象概念,是一个来自数据源的元素队列并支持聚合操作。以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对...

    Stream基础概念

    Stream流是 Java8 API 新增的一个处理集合的关键抽象概念,是一个来自数据源的元素队列并支持聚合操作。以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

    相关名词描述
    元素对象形成的一个队列。 Java中的Stream并不会存储元素,而是按需计算
    数据源是流Stream的来源。 可以是集合、数组、I/O channel、 产生器generator 等
    聚合操作类似SQL语句一样的操作,比如filter, map, reduce, find, match, sorted等。
    内部迭代中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
    Pipelining以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现

    Stream的特点:

    1. Stream不是什么数据结构,它不会保存数据,只是将操作的数据结果保存到另一个对象中。
    2. Stream是惰性求值的(延迟执行),在中间处理的过程中,只对操作进行记录,并不会立即执行,只有等到执行终止操作的时候才会进行实际的计算,这时候中间操作才会执行。
    3. 可以把Stream当成一个高级版本的Iterator来使用。(原始版本的Iterator,只能一个个的遍历操作)

    1. 分类

    Stream操作分类作用描述常用方法
    无状态中间操作, 该操作不受之前元素的影响unordered、filter、map、mapToInt、mapToLong、mapToDouble、flatMap、flatMapToInt、flatMapToLongg、flatMapToDouble、peek
    有状态中间操作,该操作只有拿到所有元素之后才能继续执行distinct、sorted、limit、skip
    非短路操作结束操作 , 必须处理所有元素才能得到最终结果forEach、forEachOrdered、toArray、collect、max、min、count、reduce
    短路操作结束操作 , 遇到某些符合条件的元素就可以得到最终结果anyMatch、allMatch、noneMatch、findFirsh、findAny

    2. 常用方法

    初始化一个String类型的List集合

    List<String> stringList = Arrays.asList("a","b", "", "", "c", "", "a", "d","e","a");
    System.out.println("字符串集合:" + stringList);
    

    运行结果:

    字符串集合:[a, b, , , c, , a, d, e, a]

    创建JavaBean对象User,初始化一个User列表

    @Data
    class User{
        String name;
        String description;
    }
    List<User> userList = new ArrayList<>(
      Arrays.asList(
          new User("strive", "努力"),
          new User("fighter", "奋斗"),
          new User("lucky",  "幸运"),
          new User("lucky",  "幸运222")
          )
    );
    

    运行结果:

    [User{name=‘strive’, description=‘努力’}, User{name=‘fighter’, description=‘奋斗’}, User{name=‘lucky’, description=‘幸运’}, User{name=‘lucky’, description=‘幸运222’}]

    2.1 forEach

    forEach方法用于迭代遍历每个数据

    //迭代遍历输出
    stringList.forEach(str ->{
        System.out.print(str + " ");
    });
    

    运行结果:

    a b c a d e a


    2.2 filter

    使用 filter 按照设置的条件过滤元素,得到满足条件的元素。
    在这里插入图片描述

    //获取stringList中非空字符串的集合
    List<String> collect = stringList.stream().filter(str -> !str.isEmpty())
            .collect(Collectors.toList());
    System.out.println("非空字符串集合:" + collect);
    

    运行结果:

    非空字符串集合:[a, b, c, a, d, e, a]

    count() 方法,用来统计数量

    long emptyStrNum = stringList.stream().filter(str -> str.isEmpty()).count();
    System.out.println("空字符串数量 = " + emptyStrNum);
    

    运行结果:

    空字符串数量 = 3


    2.3 distinct

    distinct() 方法用于去重
    在这里插入图片描述

    //获取stringList中非空字符串的集合 去重后 转化为list集合
    List<String> collect3 = stringList.stream().filter(str -> !str.isEmpty()).distinct()
            .collect(Collectors.toList());
    System.out.println("去重后字符串集合:" + collect3);
    
    
    //提取出userList对象中的属性name并去重
    List<String> nameList = userList.stream().map(User::getName).distinct().collect(Collectors.toList());
    System.out.println("nameList = " + nameList);
    

    运行结果:

    去重后字符串集合:[a, b, c, d, e]

    nameList = [strive, fighter, lucky]


    2.4 Collectors - (Collector工具库)

    Collectors 类中实现了很多的规约操作(可用于返回列表或字符串)

    最常用的是将流转换为 集合或聚合元素对象

    2.4.1 Collectors.toList()方法将Stream转化为List对象
    //查找非空、去重后通过 Collectors.toList() 转化为List列表
    List<String> strList = stringList.stream().filter(str -> !str.isEmpty())
      .distinct().collect(Collectors.toList());
    System.out.println("strList = " + strList);
    

    运行结果:

    strList = [a, b, c, d, e]

    2.4.2 Collectors.toSet()方法将Stream转化为Set对象
    //通过 Collectors.toSet() 方法转化为set列表
    //set集合,不去重也输出相同的结果(set中不会有重复的元素)
    Set<String> strSet = stringList.stream().filter(str -> !str.isEmpty())
      .collect(Collectors.toSet());
    System.out.println("strSet = " + strList);
    

    运行结果:

    strSet = [a, b, c, d, e]

    2.4.3 Collectors.toMap()方法将Stream转化为Map对象
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,BinaryOperator mergeFunction,Supplier mapSupplier)
    

    参数1: keyMapper 用来生成key值的。

    参数2: valueMapper 用来生成value值的。

    参数3: mergeFunction 用在key值冲突的情况下使用(可省略),如果新元素产生的key在Map中已经出现过了,第三个参数就会定义解决的办法。

    参数4:mapSupplier 默认返回的map类型为hashMap,可以按自己的需要自己返回不同的map实现。( 可省略

    主要举个3个参数的案例来说明:

    Collectors.toMap(keyMapper, valueMapper, mergeFunction)
    

    该toMap()方法有三个参数.

    比如 collect Collectors.toMap(User::getName, i -> i, (v1, v2) -> v1)

    第一个参数 User::getName 表示选择User对象的的getName方法获取的值作为map的key值;

    第二个参数 i -> i 表示选择将原来的对象作为map的value值(这里的i只是对遍历对象取的别名)

    第三个参数 (v1, v2) -> v1,当出现key值相同时(也就是如果v1与v2的key值相同),选择前面的 也就是v1 作为那个key所对应的值,**就是出现相同key时,谁覆盖谁的问题 **

    案例:

    创建一个Javabean对象User

    @Data
    class User{
        String name;
        String description;
    }
    

    A. 使用Collectors.toMap(keyMapper, valueMapper)两个参数来将List转化为Map

    //初始化一个User的List列表
    List<User> list = new ArrayList<>(
            Arrays.asList(
                    new User("strive", "努力"),
                    new User("fighter", "奋斗"),
                    new User("lucky",  "幸运"),
                    
            )
    );
    //Collectors.toMap()方法,将List转化为Map集合
    //Map<String, String> map = list.stream().collect(Collectors.toMap(item -> item.getName(), item -> item.getDescription()));
    //简写为下面这种方式
    Map<String, User> map = list.stream().collect(Collectors.toMap(User::getName, i -> i));
    System.out.println(map);
    

    运行结果:

    {lucky=User{name=‘lucky’, description=‘幸运’}, strive=User{name=‘strive’, description=‘努力’}, fighter=User{name=‘fighter’, description=‘奋斗’}}

    B. 如果出现key相同,但是没有设置第三个参数对其进行处理,就会报错 IllegalStateException

     		//初始化一个User的List列表,里面有两个lucky
            List<User> list = new ArrayList<>(
                    Arrays.asList(
                            new User("strive", "努力"),
                            new User("fighter", "奋斗"),
                            new User("lucky",  "幸运"),
                            new User("lucky",  "幸运222")
                    )
            );	
            Map<String, User> map = list.stream().collect(Collectors.toMap(User::getName, i -> i));
            System.out.println(map);
    

    运行结果:

    报错:java.lang.IllegalStateException: Duplicate key User{name=‘lucky’, description=‘幸运’}

    因为按照User的name转换有两个相同的key值lucky,没有选择处理方式报错:IllegalStateException

    C. 设置第三个参数,解决出现相同key时,谁覆盖谁的问题

            List<User> list = new ArrayList<>(
                    Arrays.asList(
                            new User("strive", "努力"),
                            new User("fighter", "奋斗"),
                            new User("lucky",  "幸运"),
                            new User("lucky",  "幸运222")
                    )
            );
    		//设置当key相同的时候,保留前面的 【如果为 (v1,v2)->v2 就是用新的覆盖旧的】
            Map<String, User> map = list.stream().collect(Collectors.toMap(User::getName, i -> i, (v1,v2) -> v1));
            System.out.println(map);
    

    运行结果:

    {lucky=User{name=‘lucky’, description=‘幸运’}, strive=User{name=‘strive’, description=‘努力’}, fighter=User{name=‘fighter’, description=‘奋斗’}}

    2.4.4 统计

    count获取集合数量

    List<String> stringList = Arrays.asList("a","b", "", "", "c", "", "a", "d","e","a");
    //获取集合StringList的元素数量
    //Collectors.counting()
    stringList.stream().collect(Collectors.counting());
    //简写为count()
    stringList.stream().count();
    //等价于集合的size方法
    (long) stringList.size();
    

    运行结果:

    三种结果最终的效果相同

    10

    10

    10


    求平均值:averagingInt、averagingLong、averagingDouble
    求最大/最小值:maxBy、minBy
    统计求和:summingInt、summingLong、summingDouble
    统计所有(包括计数、求和、最小、最大、平均):summarizingInt、summarizingLong、summarizingDouble

     		List<Integer> intList = Arrays.asList(2, 3, 10, 6, 8, 5, 2, 9);
    
            // maxBy 求最大值  --  等价于max
            Optional<Integer> maxBy = intList.stream().collect(Collectors.maxBy(Integer::compareTo));
            // minBy 求最大值  --  等价于min
            Optional<Integer> minBy = intList.stream().collect(Collectors.minBy(Integer::compareTo));
            // averagingInt 求平均值
            Double averagingInt = intList.stream().collect(Collectors.averagingInt(i -> i));
            // 求和summingInt(需要求和的参数) -- 等价于 mapToInt
            Integer summingInt = intList.stream().collect(Collectors.summingInt(i -> i));
            //summarizingInt 统计数目、求和、最小值、平均值、最大值
            IntSummaryStatistics summarizingInt = intList.stream().collect(Collectors.summarizingInt(i -> i));
    
            System.out.println("maxBy = " + maxBy);
            System.out.println("minBy = " + minBy);
            System.out.println("averagingInt = " + averagingInt);
            System.out.println("summingInt = " + summingInt);
            System.out.println("summarizingInt = " + summarizingInt);
    

    运行结果:

    maxBy = Optional[10]
    minBy = Optional[2]
    averagingInt = 5.625
    summingInt = 45
    summarizingInt = IntSummaryStatistics{count=8, sum=45, min=2, average=5.625000, max=10}


    2.4.5 分组

    partitioningBy(分区):按照条件分为两个Map<Boolean, List>,一个是满足条件的Map和一个不满足条件的Map。
    groupingBy(分组):类似于分区,但是是将集合按照条件分为多个Map,可以对进行分组之后的结果再分组

    List<Integer> intList = Arrays.asList(2, 3, 10, 6, 8, 5, 2, 9);
            //按 >5 分为两个区间
            Map<Boolean, List<Integer>> partitioningBy = intList.stream().collect(Collectors.partitioningBy(i -> i > 5));
            //按 >5 分为两组
            Map<Boolean, List<Integer>> groupingBy = intList.stream().collect(Collectors.groupingBy(i -> i > 5));
            //先按 >5 分为两组,然后再在前面分组满足条件的基础上对(满足条件的集合)再对 >8 进行分组
            Map<Boolean, Map<Boolean, List<Integer>>> groupingBy2 = intList.stream().collect(Collectors.groupingBy(i -> i > 5, Collectors.groupingBy(i -> i > 8)));
            System.out.println("分区partitioningBy = " + partitioningBy);
            System.out.println("分组groupingBy = " + groupingBy);
            System.out.println("两次分组groupingBy2 = " + groupingBy2);
    
    

    运行结果:

    分区partitioningBy = {false=[2, 3, 5, 2], true=[10, 6, 8, 9]}
    分组groupingBy = {false=[2, 3, 5, 2], true=[10, 6, 8, 9]}
    两次分组groupingBy2 = {false={false=[2, 3, 5, 2]}, true={false=[6, 8], true=[10, 9]}}


    2.4.6 joining(连接)

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

            List<String> stringList2 = Arrays.asList("a","b", " ", " ", "c", " ", "a", "d","e","a");
            String joining = stringList2.stream().collect(Collectors.joining("-"));
            System.out.println("joining = " + joining);
    

    运行结果:

    joining = a-b- - -c- -a-d-e-a


    2.4.7 reducing (规约)

    reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) 
    

    reducing:Collectors类提供的reducing方法,类似于stream本身的reduce方法,但是增加了对自定义归约的支持。
    参数 BinaryOperator<T>: 这是一个函数式接口,是给两个相同类型的量,返回一个跟这两个量相同类型的一个结果,伪表达式为 (T,T) -> T。默认给了两个实现 maxByminBy ,根据比较器来比较大小并分别返回最大值或者最小值。当然你也可以灵活定制。然后 reducing 就很好理解了,元素两两之间进行比较根据策略淘汰一个,随着轮次的进行元素个数就是 reduce 的。

            List<Integer> intList2 = Arrays.asList(1, 2, 3);
            Integer reducing = intList2.stream().collect(Collectors.reducing(100, i -> i, (v1, v2) -> (v1 + v2 - 1)));
            System.out.println("reducing = " + reducing);
    

    运行结果:

    reducing = 103

    Stream提供的reduce方法也有类似的作用

            // stream的reduce  --  T reduce(T identity, BinaryOperator<T> accumulator);
            //参1:(identity):求出结果之后再加该值
            Optional<Integer> reduce = Optional.ofNullable(intList2.stream().reduce(100, Integer::sum));
            System.out.println("reduce = " + reduce.get());
    

    运行结果:

    reduce = 106

    Optional<Integer> reduce = Optional.ofNullable(intList2.stream().reduce(100, Integer::sum, (v1, v2) -> (v1 + v2 - 1)));
    System.out.println("reduce = " + reduce.get());
    

    2.5 map、flatMap

    map方法用于 映射每个元素到对应的结果,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    在这里插入图片描述

    flatMap方法用于 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
    在这里插入图片描述

    //使用 map 输出stringList中元素对应的两倍并去重
    List<String> doubleStr = stringList.stream().map(str -> str += str).distinct()
            .collect(Collectors.toList());
    System.out.print(doubleStr + " ");
    

    运行结果:

    [aa, bb, , cc, dd, ee]

    //通过map获取userList列表中的User对象的name属性组成一个list列表
    List<String> nameList = list.stream().map(user -> user.getName()).distinct()
            .collect(Collectors.toList());
    System.out.println(nameList);
    

    运行结果:

    [strive, fighter, lucky]


    //flagMap转换为流后再转化为list列表输出
    List<String> s = stringList.stream().flatMap(s -> {
        //将每个元素按照分隔符,转换成一个stream
        String[] split = s.split(",");
        return Arrays.stream(split);
    }).collect(Collectors.toList());
    System.out.println(s);
    

    运行结果:

    [a, b, , , c, , a, d, e, a]


    2.6 peek

    peek 方法(消费),类似于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,是没有返回值的。
    在这里插入图片描述

    //peek消费,去重输出
    stringList.stream().peek(i -> i += i).distinct().forEach(i-> System.out.print(i + " "));
    

    输出结果:

    a b c d e


    2.7 limit

    limit(n) 方法用于获取指定数量 (n个) 的流
    在这里插入图片描述

    Random random = new Random();
    // 通过 limit 输出3个随机数
    random.ints().limit(3).forEach(r ->{
        System.out.print(r + " ");
    });
    

    运行结果:

    1677393552 -608502510 2060923188

    // 三个参数:random.ints(生成数量,最小值,最大值)
    //生成10个1-100之间的随机数,再通过limit取出5个输出
    random.ints(10,1,100).limit(5).forEach(r ->{
        System.out.print(r + " ");
    });
    

    运行结果:

    7 85 73 60 49


    2.8 skip

    skip(n) 方法用于跳过 (n个) 元素,配合 limit(n) 可实现分页
    在这里插入图片描述

    		List<Integer> numbers = Arrays.asList(0, 9 ,6 , 5, 6, 3, 2, 1, 12, 5, 8, 3, 9, 3);
    		//过滤得到集合中>1的元素,然后去重,跳过前2个,然后取出5个
            List<Integer> collect = numbers.stream().filter(i -> i > 1)
                    .distinct()
                    .skip(2)
                    .limit(5).collect(Collectors.toList());
            System.out.println(collect);
    

    运行结果:

    [5, 3, 2, 12, 8]


    2.9 sorted

    sorted() 方法用于对流进行排序,这是自然排序,流中元素需实现Comparable接口。

    sorted(Comparator com) : 带参数是定制排序,使用自定义的Comparator排序器进行排序

    Random random = new Random();
    //两个参数:random.ints(最小值,最大值)
    //随机生成0-1000的随机数,通过limit取8个,然后排序输出
    random.ints(0,1000)
            .limit(8).sorted().forEach(i ->{
        System.out.print(i + " ");
    });
    

    运行结果:

    86 192 232 552 560 776 928 929


    2.10 统计结果收集器

    比如:getCount、getMax、getMin、getSum、getAverage等等用于统计结果的收集器,主要用于int、double、long等基本类型上

    //定义一个int类型的集合
    List<Integer> numbers = Arrays.asList(6, 2, 1, 2, 5, 8, 3, 9);
    //通过mapToInt转化
    IntSummaryStatistics intStatus = numbers.stream().mapToInt((i) -> i).summaryStatistics();
    
    System.out.println("列表中元素数量:" + intStatus.getCount());
    System.out.println("列表中最大数 : " + intStatus.getMax());
    System.out.println("列表中最小数 : " + intStatus.getMin());
    System.out.println("所有数之和 : " + intStatus.getSum());
    System.out.println("平均值 : " + intStatus.getAverage());
    

    运行结果:

    列表中元素数量:8
    列表中最大数 : 9
    列表中最小数 : 1
    所有数之和 : 36
    平均值 : 4.5


    2.11 流的终止操作

    方法名称描述
    count返回流中元素的总个数
    max返回流中元素最大值
    min返回流中元素最小值
    findFirst返回流中第一个元素
    findAny返回流中第一个元素(随机)
    allMatch接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
    noneMatch接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
    anyMatch接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
            List<Integer> intList = Arrays.asList(2, 3, 10, 6, 8, 5, 2, 9);
    
            long count = intList.stream().count();// 等价于intList.size()
            Integer max = intList.stream().max(Integer::compareTo).get();
            Integer min = intList.stream().min(Integer::compareTo).get();
            Integer findFirst = intList.stream().findFirst().get();
            Integer findAny = intList.stream().findAny().get();
            boolean allMatch = intList.stream().allMatch(i -> i > 1);
            boolean noneMatch = intList.stream().noneMatch(i -> i > 1);
            boolean anyMatch = intList.stream().anyMatch(i -> i > 5);
    

    运行结果:

    count = 8
    max = 10
    min = 2
    findFirst = 2
    findAny = 2
    allMatch = true
    noneMatch = false
    anyMatch = true

    图片来自:https://ifeve.com/stream/


    3. 创建流的两种方式

    创建流的方式描述
    stream为集合创建串行流
    parallelStream为集合创建并行流

    parallelStream里面的执行是异步的,并且使用的线程池是 ForkJoinPool.common,可以通过设置 -Djava.util.concurrent.ForkJoinPool.common.parallelism = N 来调整线程池的大小。可能提高你的多线程任务的速度。

            List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6);
            System.out.print("stream串行:");
            intList.stream().forEach(System.out::print);
            System.out.print("\nparallelStream并行:");
            intList.parallelStream().forEach(System.out::print);
    

    三次运行结果:

    第一次运行:

    stream串行:123456
    parallelStream并行:456321

    第二次运行:

    stream串行:123456
    parallelStream并行:451623

    第三次运行:

    stream串行:123456
    parallelStream并行:465321

    可以发现,Stream每次运行都是相同的结果,且是顺序输出的,但是parallelStream每次运行结果可能不同,顺序也是错乱的。

    打印执行线程信息,查看是否是并行的

            List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6);
            intList.parallelStream().forEach(i -> System.out.println("线程 = " + Thread.currentThread().getName() +" : 输出 = " + i));
    

    运行结果:

    线程 = main : 输出 = 4
    线程 = ForkJoinPool.commonPool-worker-2 : 输出 = 1
    线程 = ForkJoinPool.commonPool-worker-2 : 输出 = 3
    线程 = ForkJoinPool.commonPool-worker-2 : 输出 = 5
    线程 = main : 输出 = 6
    线程 = ForkJoinPool.commonPool-worker-9 : 输出 = 2

    所以 parallelStream 是利用多线程并行执行的,通过 parallelStream 可以很大程度简化我们使用并发操作。

    使用 parallelStream 是平行处理的,所以顺序每次都不一定一致,如果想要顺序是按照原来Stream的数据一样顺序输出,可以通过 forEachOrdered 方法实现。

            List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6);
            System.out.println("parallelStream并行使用forEachOrdered顺序输出:");
            intList.parallelStream().forEachOrdered(System.out::print);
            System.out.println();
            intList.parallelStream().forEachOrdered(i ->   System.out.println("线程 = " + Thread.currentThread().getName() +" : 输出 = " + i));
    

    运行结果:

    parallelStream并行使用forEachOrdered顺序输出:123456
    线程 = ForkJoinPool.commonPool-worker-6 : 输出 = 1
    线程 = ForkJoinPool.commonPool-worker-6 : 输出 = 2
    线程 = ForkJoinPool.commonPool-worker-6 : 输出 = 3
    线程 = ForkJoinPool.commonPool-worker-6 : 输出 = 4
    线程 = ForkJoinPool.commonPool-worker-6 : 输出 = 5
    线程 = ForkJoinPool.commonPool-worker-6 : 输出 = 6

    所以调用 forEachOrdered 方法顺序执行的话,就不是多线程并行处理了,是一个线程进行处理。

    展开全文
  • Java 8 stream的详细用法

    万次阅读 多人点赞 2019-01-08 23:12:43
    Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以...

    一、概述

    Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

    特点:

            1 . 不是数据结构,不会保存数据。

            2. 不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中。(保留意见:毕竟peek方法可以修改流中元素

            3. 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。

    二、分类

        无状态:指元素的处理不受之前元素的影响;

        有状态:指该操作只有拿到所有元素之后才能继续下去。

        非短路操作:指必须处理所有元素才能得到最终结果;

        短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。

    三、具体用法

    1. 流的常用创建方法

    1.1 使用Collection下的 stream() 和 parallelStream() 方法

    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream(); //获取一个顺序流
    Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

    1.2 使用Arrays 中的 stream() 方法,将数组转成流

    Integer[] nums = new Integer[10];
    Stream<Integer> stream = Arrays.stream(nums);

    1.3 使用Stream中的静态方法:of()、iterate()、generate()

    Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
    
    Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
    stream2.forEach(System.out::println); // 0 2 4 6 8 10
    
    Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
    stream3.forEach(System.out::println);
    

    1.4 使用 BufferedReader.lines() 方法,将每行内容转成流

    BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));
    Stream<String> lineStream = reader.lines();
    lineStream.forEach(System.out::println);

    1.5 使用 Pattern.splitAsStream() 方法,将字符串分隔成流

    Pattern pattern = Pattern.compile(",");
    Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
    stringStream.forEach(System.out::println);

    2. 流的中间操作

    2.1 筛选与切片
            filter:过滤流中的某些元素
            limit(n):获取n个元素
            skip(n):跳过n元素,配合limit(n)可实现分页
            distinct:通过流中元素的 hashCode() 和 equals() 去除重复元素

    Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);
    
    Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14
            .distinct() //6 7 9 8 10 12 14
            .skip(2) //9 8 10 12 14
            .limit(2); //9 8
    newStream.forEach(System.out::println);

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

    List<String> list = Arrays.asList("a,b,c", "1,2,3");
    
    //将每个元素转成一个新的且不带逗号的元素
    Stream<String> s1 = list.stream().map(s -> s.replaceAll(",", ""));
    s1.forEach(System.out::println); // abc  123
    
    Stream<String> s3 = list.stream().flatMap(s -> {
        //将每个元素转换成一个stream
        String[] split = s.split(",");
        Stream<String> s2 = Arrays.stream(split);
        return s2;
    });
    s3.forEach(System.out::println); // a b c 1 2 3

    2.3 排序
            sorted():自然排序,流中元素需实现Comparable接口
            sorted(Comparator com):定制排序,自定义Comparator排序器  

    List<String> list = Arrays.asList("aa", "ff", "dd");
    //String 类自身已实现Compareable接口
    list.stream().sorted().forEach(System.out::println);// aa dd ff
    
    Student s1 = new Student("aa", 10);
    Student s2 = new Student("bb", 20);
    Student s3 = new Student("aa", 30);
    Student s4 = new Student("dd", 40);
    List<Student> studentList = Arrays.asList(s1, s2, s3, s4);
    
    //自定义排序:先按姓名升序,姓名相同则按年龄升序
    studentList.stream().sorted(
            (o1, o2) -> {
                if (o1.getName().equals(o2.getName())) {
                    return o1.getAge() - o2.getAge();
                } else {
                    return o1.getName().compareTo(o2.getName());
                }
            }
    ).forEach(System.out::println);

    2.4 消费
            peek:如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。

    Student s1 = new Student("aa", 10);
    Student s2 = new Student("bb", 20);
    List<Student> studentList = Arrays.asList(s1, s2);
    
    studentList.stream()
            .peek(o -> o.setAge(100))
            .forEach(System.out::println);   
    
    //结果:
    Student{name='aa', age=100}
    Student{name='bb', age=100}            

    3. 流的终止操作

    3.1 匹配、聚合操作
            allMatch:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
            noneMatch:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
            anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
            findFirst:返回流中第一个元素
            findAny:返回流中的任意元素
            count:返回流中元素的总个数
            max:返回流中元素最大值
            min:返回流中元素最小值

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    
    boolean allMatch = list.stream().allMatch(e -> e > 10); //false
    boolean noneMatch = list.stream().noneMatch(e -> e > 10); //true
    boolean anyMatch = list.stream().anyMatch(e -> e > 4);  //true
    
    Integer findFirst = list.stream().findFirst().get(); //1
    Integer findAny = list.stream().findAny().get(); //1
    
    long count = list.stream().count(); //5
    Integer max = list.stream().max(Integer::compareTo).get(); //5
    Integer min = list.stream().min(Integer::compareTo).get(); //1

    3.2 规约操作
            Optional<T> reduce(BinaryOperator<T> accumulator):第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
            T reduce(T identity, BinaryOperator<T> accumulator):流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。
            <U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner):在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行规约。

    //经过测试,当元素个数小于24时,并行时线程数等于元素个数,当大于等于24时,并行时线程数为16
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24);
    
    Integer v = list.stream().reduce((x1, x2) -> x1 + x2).get();
    System.out.println(v);   // 300
    
    Integer v1 = list.stream().reduce(10, (x1, x2) -> x1 + x2);
    System.out.println(v1);  //310
    
    Integer v2 = list.stream().reduce(0,
            (x1, x2) -> {
                System.out.println("stream accumulator: x1:" + x1 + "  x2:" + x2);
                return x1 - x2;
            },
            (x1, x2) -> {
                System.out.println("stream combiner: x1:" + x1 + "  x2:" + x2);
                return x1 * x2;
            });
    System.out.println(v2); // -300
    
    Integer v3 = list.parallelStream().reduce(0,
            (x1, x2) -> {
                System.out.println("parallelStream accumulator: x1:" + x1 + "  x2:" + x2);
                return x1 - x2;
            },
            (x1, x2) -> {
                System.out.println("parallelStream combiner: x1:" + x1 + "  x2:" + x2);
                return x1 * x2;
            });
    System.out.println(v3); //197474048

    3.3 收集操作
            collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。
            Collector<T, A, R> 是一个接口,有以下5个抽象方法:
                Supplier<A> supplier():创建一个结果容器A
                BiConsumer<A, T> accumulator():消费型接口,第一个参数为容器A,第二个参数为流中元素T。
                BinaryOperator<A> combiner():函数接口,该参数的作用跟上一个方法(reduce)中的combiner参数一样,将并行流中各                                                                 个子进程的运行结果(accumulator函数操作后的容器A)进行合并。
                Function<A, R> finisher():函数式接口,参数为:容器A,返回类型为:collect方法最终想要的结果R。
                Set<Characteristics> characteristics():返回一个不可变的Set集合,用来表明该Collector的特征。有以下三个特征:
                    CONCURRENT:表示此收集器支持并发。(官方文档还有其他描述,暂时没去探索,故不作过多翻译)
                    UNORDERED:表示该收集操作不会保留流中元素原有的顺序。
                    IDENTITY_FINISH:表示finisher参数只是标识而已,可忽略。
            注:如果对以上函数接口不太理解的话,可参考我另外一篇文章:Java 8 函数式接口

    3.3.1 Collector 工具库:Collectors

    Student s1 = new Student("aa", 10,1);
    Student s2 = new Student("bb", 20,2);
    Student s3 = new Student("cc", 10,3);
    List<Student> list = Arrays.asList(s1, s2, s3);
    
    //装成list
    List<Integer> ageList = list.stream().map(Student::getAge).collect(Collectors.toList()); // [10, 20, 10]
    
    //转成set
    Set<Integer> ageSet = list.stream().map(Student::getAge).collect(Collectors.toSet()); // [20, 10]
    
    //转成map,注:key不能相同,否则报错
    Map<String, Integer> studentMap = list.stream().collect(Collectors.toMap(Student::getName, Student::getAge)); // {cc=10, bb=20, aa=10}
    
    //字符串分隔符连接
    String joinName = list.stream().map(Student::getName).collect(Collectors.joining(",", "(", ")")); // (aa,bb,cc)
    
    //聚合操作
    //1.学生总数
    Long count = list.stream().collect(Collectors.counting()); // 3
    //2.最大年龄 (最小的minBy同理)
    Integer maxAge = list.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // 20
    //3.所有人的年龄
    Integer sumAge = list.stream().collect(Collectors.summingInt(Student::getAge)); // 40
    //4.平均年龄
    Double averageAge = list.stream().collect(Collectors.averagingDouble(Student::getAge)); // 13.333333333333334
    // 带上以上所有方法
    DoubleSummaryStatistics statistics = list.stream().collect(Collectors.summarizingDouble(Student::getAge));
    System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage());
    
    //分组
    Map<Integer, List<Student>> ageMap = list.stream().collect(Collectors.groupingBy(Student::getAge));
    //多重分组,先根据类型分再根据年龄分
    Map<Integer, Map<Integer, List<Student>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(Student::getType, Collectors.groupingBy(Student::getAge)));
    
    //分区
    //分成两部分,一部分大于10岁,一部分小于等于10岁
    Map<Boolean, List<Student>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10));
    
    //规约
    Integer allAge = list.stream().map(Student::getAge).collect(Collectors.reducing(Integer::sum)).get(); //40

    3.3.2 Collectors.toList() 解析

    //toList 源码
    public static <T> Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                (left, right) -> {
                    left.addAll(right);
                    return left;
                }, CH_ID);
    }
    
    //为了更好地理解,我们转化一下源码中的lambda表达式
    public <T> Collector<T, ?, List<T>> toList() {
        Supplier<List<T>> supplier = () -> new ArrayList();
        BiConsumer<List<T>, T> accumulator = (list, t) -> list.add(t);
        BinaryOperator<List<T>> combiner = (list1, list2) -> {
            list1.addAll(list2);
            return list1;
        };
        Function<List<T>, List<T>> finisher = (list) -> list;
        Set<Collector.Characteristics> characteristics = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
    
        return new Collector<T, List<T>, List<T>>() {
            @Override
            public Supplier supplier() {
                return supplier;
            }
    
            @Override
            public BiConsumer accumulator() {
                return accumulator;
            }
    
            @Override
            public BinaryOperator combiner() {
                return combiner;
            }
    
            @Override
            public Function finisher() {
                return finisher;
            }
    
            @Override
            public Set<Characteristics> characteristics() {
                return characteristics;
            }
        };
    
    }

     

     

    展开全文
  • Java Stream流(详解)

    万次阅读 多人点赞 2021-08-29 19:23:17
    一、Stream流引入 Lambda表达式,基于Lambda所带来的函数式编程,又引入了一个全新的Stream概念,用于解决集合类库既有的鼻端。(Lambda表达式详解在上篇博客内容) 现有一个需求: 将list集合中姓张的元素...
  • 在Java8 API中增添了新的抽象类Stream,将待处理的元素集和视作一种流,并在管道中传输,且可在管道的节点上进行多种处理,比如排序、筛选、聚合等。 因此,在Java8及以上版本中,可利用stream().filter来筛选出...
  • Java 8 Stream流API解析

    千次阅读 2021-06-18 09:59:14
    1. Stream流简介 Java 8 API添加了一个新的抽象称为流Stream,可以以一种声明的方式处理数据。 Stream流使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。 Stream流...
  • stream流详解

    万次阅读 2020-11-17 00:11:00
    Stream流 一 :Stream流的介绍 stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果; stream不会改变数据源,通常情况下会产生一个新的集合; stream具有延迟执行特性,只有调用终端操作时,中间...
  • Java8中Stream详细用法大全

    万次阅读 多人点赞 2021-11-15 09:57:28
    Stream流是JDK8新增的成员,允许以声明性方式处理数据集合,可以把Stream流看作是遍历数据集合的一个高级迭代器。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的...
  • springcloud 入门(8) springcloud Stream

    千次阅读 2021-12-10 11:43:09
    文章目录项目环境介绍入门使用消息生产者消息消费者注解解释 项目环境 1、IDE:idea ,maven 2、操作系统:win10 ...1、新建一个cloud-stream-provider,添加依赖 <dependency> <groupId>org
  • 【java基础】吐血总结Stream流操作

    千次阅读 多人点赞 2022-03-24 17:21:57
    Stream流操作讲解 1 Stream概述 java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。 那么什么是StreamStream将要处理的元素集合...
  • Elasticsearch 7.X data stream 深入详解

    千次阅读 热门讨论 2021-07-26 00:16:05
    直接从一个新概念的认知过程说下 elasticsearch data stream。记得第一次听到 data stream 的时候,还是去年下半年在公交大巴车上早 8 点听魏彬老师的直播,...
  • redis stream 实现消息队列

    千次阅读 2022-04-07 16:40:07
    redis stream 实现消息队列 Redis5.0带来了Stream类型。从字面上看是流类型,但其实从功能上看,应该是Redis对消息队列(MQ,Message Queue)的完善实现。 基于redis实现消息队列的方式有很多: PUB/SUB,订阅/发布...
  • Java Stream 流高级使用全解

    千次阅读 2020-12-26 18:38:56
    Java Stream 流高级使用全解一 基本汇总1. 创建流2. 中间操作3. 终止操作二 经验累积1. 统计1.1 取最大值1.2 取最小值1.3 取总和值1.4 取平均值2. 过滤2.1 获取最近时间3. 排序3.1 根据字段排序4. 分组4.1 获取字段...
  • JAVA stream流详细教程

    万次阅读 多人点赞 2021-10-24 21:58:28
    结果为:[Java, 8, Lambdas, In, Action] map(w -> w.split(" ")) 的返回值为 Stream,想获取 Stream,可以通过flatMap方法完成 Stream ->Stream 的转换。 allMatch 匹配所有元素 List<Integer> integerList = ...
  • stream进行分组统计

    千次阅读 2022-04-12 16:04:23
    map = houseList.stream().collect(Collectors.groupingBy(House::getBuildId, Collectors.counting())); // //控制台输出map // map.forEach((k,v)->{ // System.out.println("k="+k+",v="+v); // }); // /...
  • Java Stream流使用及性能分析

    千次阅读 2022-01-19 17:25:12
    Java Stream流 一、Stream简介 1、什么是Stream? Java8 中,Collection 新增了两个流方法,分别是 Stream() 和 parallelStream() Java8 中添加了一个新的接口类 Stream,相当于高级版的 Iterator,它可以通过 ...
  • Java8新特性——Stream API的创建方式及中间操作

    千次阅读 多人点赞 2021-11-08 16:19:08
    1.什么是StreamAPI? Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 m Stream API (java.util.stream.*) 。 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作...
  • gRPC的stream使用

    千次阅读 2020-11-28 16:25:41
    gRPC的stream介绍gRPC的stream介绍gRPC为什么提供 steam功能?gRPC的stream的分类一元RPC客户端流RPC服务端流RPC双向流RPC gRPC的stream介绍 gRPC为什么提供 steam功能? 在以下场景使用unary rpc 可能有如下问题 ...
  • 此章节将详细对官方案例:`deepstream_test_1_rtsp_out.py`作解读。`deepstream_test_1_rtsp_out.py`的主要作用是可以输入rtsp格式的视频流。当我们成功运行了这个Python文件后,我们在屏幕上并不会看到视频,但是,...
  • 玩转Java8 Stream

    千次阅读 2021-08-29 13:48:40
    Java8中Stream流总结 因为在工作后,发现项目代码里经常会出现Stream流以及和lambda表达式联合使用。但之前对于这块的学习有点一知半解,所以花了几天空闲时间将这些知识总结一下。 一、概述 **(参考百度)**Stream...
  • Stream流常用方法

    千次阅读 多人点赞 2020-10-13 13:44:45
    Stream流 获取Stream流的方式 java.util.stream.Stream 是Java 8新加入的流接口。(并不是一个函数式接口) 获取一个流非常简单,有以下几种常用的方式: 所有的 Collection 集合都可以通过 stream 默认方法获取流...
  • java.util.stream.Stream

    千次阅读 2020-03-22 20:21:38
    Stream
  • 5万字长文详解介绍Stream和Lambda表达式最佳实践,干货实在太多,最后附上PDF下载,方便大家查阅!
  • DeepStream初步学习

    万次阅读 多人点赞 2020-02-04 18:27:17
    一、简介 二、下载 可以直接源码git:git clone https://github.com/deepstreamIO/deepstream.io.git 我是下载的v4.0.0版本:...当然我实际使用的deepstream是在Jetson Xavier上的dee...
  • Java中Stream流的基本操作

    千次阅读 2021-12-20 15:05:51
    Stream流的思想和生成方式 Stream流的常见生成方式 Stream流的常见中间操作方法: Stream流的常见终结操作方法 Stream流的练习 Stream流的收集操作 Stream流的思想和生成方式 1、生成流 通过数据源(集合,...
  • Stream流的常用方法

    千次阅读 多人点赞 2022-03-25 17:30:44
    List list = Stream.of("1", "2").collect(Collectors.toList()); 2、取对象的某一列 低效方式: List<String> userNameList = new ArrayList<>(); for (String) List<String> userNameList = ...
  • 通过这篇文章提供的方法,您也能在`CentOS 8`上升级到`CentOS Stream 9`,保留所有数据,并且不用重装系统!
  • Stream和parallelStream

    万次阅读 多人点赞 2019-04-22 15:16:54
    Stream 和 parallelStream ParallelStream stream parallelstream stream和parallelStream 一.什么是StreamStream 是在 Java8 新增的特性,普遍称其为流;它不是数据结构也不存放任何数据,其主要用于集合的逻辑...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,200,723
精华内容 480,289
关键字:

stream