Java8新特性-Stream API

淡淡的烟草味﹌ 2023-10-02 10:01 114阅读 0赞

一、Stream简介

1.1 Stream API说明
  • Stream API(java.util.stream)把真正的函数式编程风格引入到Java中,提供了简单高效的操作
  • Stream 是Java8中处理集合的关键抽象概念,它可以指定对集合进行操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作
1.2 什么是Stream

Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。集合存储数据,Stream是对集合元素进行计算

  • Stream本省并不存储元素
  • Stream不会改变源对象,会返回一个持有结果的新Stream
  • Stream是延迟执行的,只有等到需要结果的时候才执行
1.3 Stream操作步骤
  • 创建Stream

    一个数据源(如:集合、数组)获取一个流

  • 中间操作

    一个中间操作链,可以进行多种操作,对数据源的数据进行处理

  • 终止操作

    一旦执行终止操作,就执行中间操作链,并产生结果,之后,创建的流将不能再被使用,如果使用,需要重新创建一个新的流

image-20210920092018265

二、Stream使用

2.1 创建执行流
  • 集合创建执行流

    1. List<User> userList = User.getUserList();
    2. //创建顺序流
    3. Stream<User> userStream = userList.stream();
    4. //创建并行流 中间操作可以并行执行
    5. Stream<User> userParallelStream = userList.parallelStream();

    Collection接口中实现了默认的stream和parallelStream方法,所以Collection的实现类可以直接调用这两个方法

  • 通过数组创建执行流

    1. int[] intArr = {
    2. 1,2,3,4,5,6};
    3. IntStream intStream = Arrays.stream(intArr);
    4. int[] longArr = {
    5. 1,2,3,4,5,6};
    6. IntStream longStream = Arrays.stream(longArr);
    7. double[] doubleArr = {
    8. 1.1,2.2,3.3};
    9. DoubleStream stream = Arrays.stream(doubleArr);
    10. User[] userArr = {
    11. new User(1,"zhangsan",25),new User(2,"lisi",26)};
    12. Stream<User> userStream = Arrays.stream(userArr);

    Arrays工具类中提供了静态的stream方法实现,其中基本类型int、long、double的数组返回的是对应与基本类型的执行流

  • 通过Stream的of方法创建

    1. Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
    2. Stream<Boolean> booleanStream = Stream.of(true, false);
    3. Stream<Float> floatStream = Stream.of(1.1f, 2.2f, 3.3f);

    通过of方法创建基本数据类型的执行流时,返回的基本类型对应的包装类型的执行流

  • 通过Stream的iterate()和generate()创建无限流

    1. Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println);
    2. Stream.generate(Math::random).limit(10).forEach(System.out::println);

    iterate是通过迭代的方式一直生成数据,其中第一个参数为起始值,后面的lambda表达式为具体的迭代逻辑,如果没有通过后面的limit方法限制,则会一直迭代下去

    generate是通过重复调用lambda表达式来生成数据,如果不加limit限制,也会一直调用里面的lambda表达式

2.2 Stream的中间操作

Stream的中间操作可以连接起来形成一个调用链(流水线),只有流水线执行了终止操作,中间操作才会执行,否则中间操作不会做任何处理,而是在终止操作时一次性处理,这种方式称为“惰性求值”

  • 筛选与切片

    1. //过滤出年龄大于25的用户,filter的参数是Predicate函数接口的实现
    2. List<User> userList = User.getUserList();
    3. userList.stream().filter(user -> user.getAge() >25).forEach(System.out::println);
    4. //限制集合元素的数量,只输出三个用户
    5. List<User> userList = User.getUserList();
    6. userList.stream().limit(3).forEach(System.out::println);
    7. //跳过前面指令数量的集合元素,例子中为跳过前两个
    8. List<User> userList = User.getUserList();
    9. userList.stream().skip(2).forEach(System.out::println);
    10. //distinct去重,通过流所生成元素的hashCode()和equals()去除重复元素
    11. List<User> userListDistinct = new ArrayList<User>(){
    12. {
    13. new User(1,"lizhi",23);
    14. new User(1,"lizhi",23);
    15. new User(1,"lizhi",23);
    16. }
    17. };
    18. userListDistinct.stream().distinct().forEach(System.out::println);

    如果Stream流已经执行过了终止操作,再次调用该流的Stream API将会导致异常:java.lang.IllegalStateException: stream has already been operated upon or closed

  • 映射

    1. //通过映射原有Stream的元素映射成新的元素构成的Stream
    2. List<String> list = Arrays.asList("aa","bb","cc");
    3. list.stream().map(String::toUpperCase).forEach(System.out::println);
    4. //将user实体集合映射成user的name集合
    5. List<User> userList = User.getUserList();
    6. Stream<String> nameStream = userList.stream().map(User::getName);
    7. nameStream.filter(name -> name.startsWith("li")).forEach(System.out::println);
    8. //flatmap接收一个函数作为参数,将流中的每个值都映射成另一个流,然后将所有流合并成一个流
    9. Stream<Character> characterStream = list.stream().flatMap(StreamOperateTest::stringFormat);
    10. characterStream.forEach(System.out::println);
    11. /** 原始写法 */
    12. Stream<Stream<Character>> streamStream = list.stream().map(StreamOperateTest::stringFormat);
    13. streamStream.forEach(stream -> stream.forEach(System.out::println));
    14. public static Stream<Character> stringFormat(String string){
    15. List<Character> list = new ArrayList<>(8);
    16. for (Character c: string.toCharArray()) {
    17. list.add(c);
    18. }
    19. return list.stream();
    20. }

    映射将原有的Stream流通过映射关系转换成一个新的Stream流

  • 排序

    1. //默认排序
    2. List<Integer> integerList = Arrays.asList(12, 95, 32, 2, 95, -2, 35);
    3. integerList.stream().sorted().forEach(System.out::println);
    4. //自定义排序
    5. List<User> userList = User.getUserList();
    6. userList.stream().sorted(Comparator.comparingInt(User::getAge)).forEach(System.out::println);
2.3 终止操作
  • 查找与匹配

    1. //检查是否匹配所有元素
    2. List<User> userList = User.getUserList();
    3. boolean allMatch = userList.stream().allMatch(user -> user.getAge() > 24);
    4. //检查是否匹配任何一个元素
    5. boolean anyMatch = userList.stream().anyMatch(user -> user.getAge() > 25);
    6. //检查是否没有匹配的元素
    7. boolean noneMatch = userList.stream().noneMatch(user -> user.getAge() > 25);
    8. //查找第一个元素
    9. Optional<User> firstUser = userList.stream().findFirst();
    10. //查找任意一个元素
    11. Optional<User> anyUser = userList.stream().findAny();
    12. //统计流中元素个数
    13. long count = userList.stream().count();
    14. //统计流中最大值 如果比较的用户最大年龄有多个时,则任意返回一个
    15. Optional<User> maxUser = userList.stream().max(Comparator.comparing(User::getAge));
  • 归约

    1. //将流中元素反复结合起来,得到一个值
    2. //计算集合中元素的和 第一个参数为起始值,也参与运算
    3. List<Integer> integerList = Arrays.asList(5, 6, 8, 22, 72, 365, 85);
    4. Integer reduce = integerList.stream().reduce(0, Integer::sum);
    5. //不需要初始值反复运算,通过map将User流变成age流
    6. Optional<Integer> allAge = userList.stream().map(User::getAge).reduce(Integer::sum);
  • 收集

    1. //将操作后的数据收集到一个集合中
    2. List<User> userList = User.getUserList();
    3. List<User> collect = userList.stream().filter(user ->
    4. user.getAge() > 25).collect(Collectors.toList());
    5. Set<User> userSet = userList.stream().filter(user ->
    6. user.getName().startsWith("zhu")).collect(Collectors.toSet());

发表评论

表情:
评论列表 (有 0 条评论,114人围观)

还没有评论,来说两句吧...

相关阅读