Stream 介绍和使用

    技术2022-07-10  129

    文章目录

    创建Stream的几种方式中间操作筛选与切片filter:可以使用Lambda,从Stream中排除某些元素limit:截断流,使其元素不超过给定数量,超过给定数量的数据,不再继续执行skip(n):跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补distinct:筛选,通过流所生成元素的hashCode()和equals()去除重复元素map:将元素转换成其他形式提取信息,接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所以的流连接成一个流sorted():自然排序(Comparable)sorted(Comparator comparator):定制排序(Comparator) 查找与匹配allMatch:检查是否匹配所有元素anyMatch:检查是否至少匹配一个元素noneMatch:检查是否没有匹配所有元素findFirst:返回第一个元素findAny:返回当前流中的任意元素count:返回流中元素的总个数max:返回流中的最大值min:返回流中的最小值 终止操作归约和收集reduce:可以将流中的元素反复结合起来,得到一个值collect:将流转换为其他数据类型格式,接受一个Collector接口的实现,用于给Stream中元素做汇总的方法 并行流与串行流串行流:Stream上的操作是在一个线程中依次完成并行流:Stream上的操作是在多个线程上同时执行 了解Fork/Join框架Fork/Join框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join汇总。 Fork/Join框架与传统线程池的区别采用工作窃取模式(work-stealing):

    创建Stream的几种方式

    1.通过Collection集合提供的stream()(串行流),parallelStream()(并行流)

    List<String> list = new ArrayList<>(); Stream<String> str = list.stream();

    2.通过Arrays.stream,获取数组流

    Person[] employees = new Person[10]; Stream<String> stream1 = list.stream(Person);

    3.通过Stream类中的静态方法 of()

    Stream<String> aa = Stream.of("aa", "bb", "cc");

    4.创建无限流

    //第一种迭代 Stream<Integer> iterate = Stream.iterate(0, (x) -> x = 2); iterate.limit(10).forEach(System.out::println); //第二种迭代 Stream.generate(()->Math.random()) .limit(5) .forEach(System.out::println);

    中间操作

    筛选与切片
    filter:可以使用Lambda,从Stream中排除某些元素
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayList<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 89, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 793.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); /* 多个中间操作可以连接起来形成一个流水线。 除非流水线上触发终止操作,否则中间操作不会执行任何的处理! 而在终止操作时一次性全部处理 */ personArrayList .stream() // filter:中间操作。可以使用Lambda,从Stream中排除某些元素 // 如果没有终止操作,中间操作(filter)不执行 .filter((person) -> { System.out.println("Stream API 的中间操作"); return person.getAge() <= 20; }) //终止操作 .forEach(System.out::println); } }
    limit:截断流,使其元素不超过给定数量,超过给定数量的数据,不再继续执行
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayList<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 89, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 793.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); /* 多个中间操作可以连接起来形成一个流水线。 除非流水线上触发终止操作,否则中间操作不会执行任何的处理! 而在终止操作时一次性全部处理 */ personArrayList .stream() // filter:中间操作。可以使用Lambda,从Stream中排除某些元素 // 如果没有终止操作,中间操作(filter)不执行 .filter((person) -> { System.out.println("短路!"); return person.getAge() >= 20; }) // 使其元素不超过给定的数量,超过给定数量的数据,不再继续执行 .limit(2) //终止操作 .forEach(System.out::println); } }
    skip(n):跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayList<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 89, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 793.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList .stream() // filter:中间操作。可以使用Lambda,从Stream中排除某些元素 // 如果没有终止操作,中间操作(filter)不执行 .filter((person) -> person.getAge() > 10) // 跳过n元素前的元素(包括n元素) // 如果此元素前的不足n个,返回一个空流 .skip(3) //终止操作 .forEach(System.out::println); } }
    distinct:筛选,通过流所生成元素的hashCode()和equals()去除重复元素
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayList<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 87, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 793.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList .stream() // filter:中间操作。可以使用Lambda,从Stream中排除某些元素 // 如果没有终止操作,中间操作(filter)不执行 .filter((person) -> person.getAge() > 10) // 跳过n元素前的元素(包括n元素) // 如果此元素前的不足n个,返回一个空流 .skip(2) //去重操作,需要重写hashCode和equals .distinct() //终止操作 .forEach(System.out::println); } }
    map:将元素转换成其他形式提取信息,接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
    flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所以的流连接成一个流
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Test { public static void main(String[] args) { ArrayList<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 87, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 793.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); // map:将元素转换成其他形式提取信息,接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 // flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所以的流连接成一个流 List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd"); // map:接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 list.stream() // 提取aaa应用到str函数上,然后提取bbb应用到str函数上 .map((str) -> str.toUpperCase()) .forEach(System.out::println); // 输出:AAA BBB CCC DDD System.out.print("============================================"); // flatMap:将流中的每个值都换成另一个流,然后把所以的流连接成一个流 list.stream() // Test:类 // filterCharacter:类中的方法 .flatMap(Test::filterCharacter) .forEach(System.out::println); } public static Stream<Character> filterCharacter(String str){ ArrayList<Character> arrayList = new ArrayList<>(); for (Character character : str.toCharArray()) { arrayList.add(character); } return arrayList.stream(); } }
    sorted():自然排序(Comparable)
    sorted(Comparator comparator):定制排序(Comparator)
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Test { public static void main(String[] args) { //sorted():自然排序(Comparable) List<String> list = Arrays.asList("aaa", "eee", "ccc", "ddd", "bbb"); list.stream() .sorted() .forEach(System.out::println); //输出结果:aaa bbb ccc ddd eee System.out.println(" ================ 分割线 =============== "); //sorted(Comparator comparator):定制排序(Comparator) List<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 87, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 532.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.stream() .sorted((person1, person2) -> { //根据年龄(age)排序,再根据工资(salary)排序 if (person1.getAge().equals(person2.getAge())) { return person1.getSalary().compareTo(person2.getSalary()); } else { return person1.getAge().compareTo(person2.getAge()); } }).forEach(System.out::println); /* * 输出结果:Person{id=4, name='任六', age=19, salary=532.5} Person{id=6, name='王八', age=21, salary=532.5} Person{id=6, name='王八', age=21, salary=532.5} Person{id=6, name='王八', age=21, salary=532.5} Person{id=3, name='王五', age=27, salary=426.5} Person{id=5, name='田七', age=33, salary=823.5} Person{id=2, name='李四', age=66, salary=678.2} Person{id=1, name='张三', age=87, salary=342.5} * * */ } }
    查找与匹配
    allMatch:检查是否匹配所有元素
    anyMatch:检查是否至少匹配一个元素
    noneMatch:检查是否没有匹配所有元素
    findFirst:返回第一个元素
    findAny:返回当前流中的任意元素
    count:返回流中元素的总个数
    max:返回流中的最大值
    min:返回流中的最小值
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class TestFind { public static void main(String[] args) { List<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 27, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 532.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); //allMatch:检查是否匹配所有元素 boolean ballMatch = personArrayList.stream() .allMatch((person) -> person.getSalary().equals(532.5)); System.out.println("ballMatch = " + ballMatch); //false //anyMatch:检查是否至少匹配一个元素 boolean banyMatch = personArrayList.stream() .anyMatch((person) -> person.getSalary().equals(532.5)); System.out.println("banyMatch = " + banyMatch); //true //noneMatch;检查是否没有匹配所以元素 boolean bnoneMatch = personArrayList.stream() .noneMatch((person) -> person.getSalary().equals(532.5)); System.out.println("bnoneMatch = " + bnoneMatch); //findFirst:返回第一个元素 Optional<Person> findFirst = personArrayList.stream() .sorted((person1, person2) -> Double.compare(person1.getSalary(), person2.getSalary())) .findFirst(); System.out.println("findFirst = " + findFirst); //findAny:返回当前流中的任意元素 Optional<Person> findAny = personArrayList.stream() .filter((person) -> person.getAge().equals(27)) .findAny(); System.out.println("findAny = " + findAny.get()); //count:返回流中元素的总个数 long count = personArrayList.stream() .count(); System.out.println("count = " + count); //max:返回流中的最大值 //第一种写法 Optional<Person> max = personArrayList.stream() .max((person1, person2) -> Double.compare(person1.getSalary(), person2.getSalary())); System.out.println("max = " + max.get()); //第二种写法 Optional<Double> maxDouble = personArrayList.stream() .map(Person::getSalary) .max(Double::compareTo); System.out.println("maxDouble.get() = " + maxDouble.get()); //min:返回流中的最小值 //第一种写法 Optional<Person> min = personArrayList.stream() .min((person1, person2) -> Double.compare(person1.getSalary(), person2.getSalary())); System.out.println("min = " + min.get()); //第二种写法 Optional<Double> minDouble = personArrayList.stream() .map(Person::getSalary) .min(Double::compareTo); System.out.println("minDouble = " + minDouble); } }

    终止操作

    归约和收集
    reduce:可以将流中的元素反复结合起来,得到一个值
    collect:将流转换为其他数据类型格式,接受一个Collector接口的实现,用于给Stream中元素做汇总的方法
    package com.example.learnlambda.test; import com.example.learnlambda.entity.Person; import java.util.*; import java.util.stream.Collectors; public class TestReduce { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9,10); //reduce 简单归约 Integer reduce = list.stream() .reduce(0, (x, y) -> x + y); System.out.println("reduce = " + reduce); List<Person> personArrayList = new ArrayList<>(); personArrayList.add(new Person(1, "张三", 27, 342.5)); personArrayList.add(new Person(2, "李四", 66, 678.2)); personArrayList.add(new Person(3, "王五", 27, 426.5)); personArrayList.add(new Person(4, "任六", 19, 532.5)); personArrayList.add(new Person(5, "田七", 33, 823.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); personArrayList.add(new Person(6, "王八", 21, 532.5)); //map-reduce归约 Optional<Double> reduceDouble = personArrayList.stream() .map(Person::getSalary) .reduce(Double::sum); System.out.println("reduceDouble = " + reduceDouble); //collect:收集,将流转换为其他数据类型格式,接受一个Collector接口的实现,用于给Stream中元素做汇总的方法 //收集所有姓名到list中 List<String> listCollect = personArrayList.stream() .map(Person::getName) .collect(Collectors.toList()); System.out.println("listCollect = " + listCollect); //收集所有姓名到set中 Set<String> setCollect = personArrayList.stream() .map(Person::getName) .collect(Collectors.toSet()); System.out.println("setCollect = " + setCollect); //收集所有姓名到Hashset中 HashSet<String> hashSetCollect = personArrayList.stream() .map(Person::getName) .collect(Collectors.toCollection(HashSet::new)); //工资总数 Long salaryCountCollect = personArrayList.stream() .collect(Collectors.counting()); System.out.println("salaryCountCollect = " + salaryCountCollect); //工资平均值 Double salaryAvgCollect = personArrayList.stream() .collect(Collectors.averagingDouble(Person::getSalary)); System.out.println("salaryAvgCollect = " + salaryAvgCollect); //工资总和 Double salarySumCollect = personArrayList.stream() .collect(Collectors.summingDouble(Person::getSalary)); System.out.println("salarySumCollect = " + salarySumCollect); //工资最大值 Optional<Person> salaryMaxCollect = personArrayList.stream() .collect(Collectors.maxBy((person1, person2) -> Double.compare(person1.getSalary(), person2.getSalary()))); System.out.println("salaryMaxCollect = " + salaryMaxCollect); //工资最小值 Optional<Double> salaryMinCollect = personArrayList.stream() .map(Person::getSalary) .collect(Collectors.minBy(Double::compare)); System.out.println("salaryMinCollect = " + salaryMinCollect); //根据年龄分组 Map<Integer, List<Person>> ageGroupCollect = personArrayList.stream() .collect(Collectors.groupingBy(Person::getAge)); System.out.println("ageGroupCollect = " + ageGroupCollect); //多级分组 Map<Integer, Map<String, List<Person>>> ageMapGroupCollect = personArrayList.stream() .collect(Collectors.groupingBy(Person::getAge, Collectors.groupingBy((e) -> { if (e.getAge() <= 35) { return "青年"; } else if (e.getAge() <= 50) { return "中年"; } else { return "老年"; } }))); System.out.println("ageMapGroupCollect = " + ageMapGroupCollect); //分区:满足条件的一个区,不满足条件的一个区 Map<Boolean, List<Person>> salaryPartitionCollect = personArrayList.stream() .collect(Collectors.partitioningBy((e) -> e.getSalary() > 500)); System.out.println("salaryPartitionCollect = " + salaryPartitionCollect); } }

    并行流与串行流

    串行流:Stream上的操作是在一个线程中依次完成
    并行流:Stream上的操作是在多个线程上同时执行

    Stream并行流:就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 Java8中将并行进行了优化,可以很容易的对数据进行并行操作。Stream API可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换。

    了解Fork/Join框架

    Fork/Join框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join汇总。

    Fork/Join框架与传统线程池的区别

    采用工作窃取模式(work-stealing):

    当执行新的任务时,它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。 相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上。在一般线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。 而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行,那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行,这种方式减少了线程的等待时间,提高了性能。

    Processed: 0.019, SQL: 9