美文网首页
Java8特性学习笔记(四) Stream

Java8特性学习笔记(四) Stream

作者: 简单一点点 | 来源:发表于2021-12-29 10:38 被阅读0次

    参考:

    简介

    java.util.Stream 表示能应用在一组元素上一次执行的操作序列。Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回 Stream 本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection 的子类,List 或者 Set, Map 不支持。Stream 的操作可以串行执行或者并行执行。

    它具有如下特点:

    • 不是数据结构,不会保存数据。

    • 一般不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中。(peek方法可以修改流中元素

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

    Stream 的创建

    最常用的方式是通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个 Stream。

    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream(); // 创建顺序流
    Stream<String> parallelStream = list.parallelStream(); // 创建并行流
    

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

    Integer[] nums1 = new Integer[10]; // 注意使用Integer数组
    Stream<Integer> stream = Arrays.stream(nums1);
    int[] nums = new int[10]; // int数组只能生成 IntStream流
    IntStream iantStrem = Arrays.stream(nums);
    

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

    Stream<Integer> stream = Stream.of(1, 2, 3);
    stream.forEach(System.out::println);
    
    Stream<Integer> stream2 = Stream.iterate(0, x -> x + 2).limit(5); // limit 限制数量
    stream2.forEach(System.out::println);
    
    Stream<Integer> stream3 = Stream.generate(new Random()::nextInt).limit(5); // limit 限制数量
    stream3.forEach(System.out::println);
    

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

    BufferedReader reader = new BufferedReader(new FileReader("a.txt"));
    Stream<String> stream = reader.lines();
    stream.forEach(System.out::println);
    

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

    Pattern pattern = Pattern.compile(",");
    Stream<String> stream = pattern.splitAsStream("a,bb,f,gh");
    stream.forEach(System.out::println);
    

    Stream方法分类

    Stream方法可以分为中间操作(Intermediate Operations)和结束操作(Terminal Operations)。中间操作会返回新的Stream供后续操作,而结束操作会返回最终结果。

    中间操作可以分析有状态(只有拿到所有元素之后才能继续)和无状态(元素处理不受之前影响)两类。

    无状态操作包括:

    • unordered()
    • filter()
    • map()
    • mapToInt()
    • mapToLong()
    • mapToDouble()
    • flatMap()
    • flatMapToInt()
    • flatMapToLong()
    • flatMapToDouble()
    • peek()

    有状态操作包括:

    • distict()
    • sorted()
    • limit()
    • skip()

    结束操作可以分为非短路操作(必须处理所有元素才能得到最终结果)和短路操作(遇到某些符合条件的元素即可得到最终结果)。

    非短路操作保护:

    • forEach()
    • forEachOrdered()
    • toArray()
    • reduce()
    • collect()
    • max()
    • min()
    • count()

    短路操作包括:

    • anyMatch()
    • allMatch()
    • noneMatch()
    • findFirst()
    • findAny()

    Stream 常用方法

    本部分重点介绍一下 Stream 常用方法。

    为了方便测试,先写个例子。

    List<String> stringList = new ArrayList<>();
    stringList.add("asc");
    stringList.add("fff");
    stringList.add("sxcfg");
    stringList.add("ds");
    stringList.add("aaa3");
    

    filter

    过滤通过一个 predicate 接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。

    stringList.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);
    

    sorted

    排序是一个中间操作,返回的是排序好后的 Stream。如果你不指定一个自定义的 Comparator 则会使用默认排序。

    stringList.stream().sorted().forEach(System.out::println);
    

    需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,如我们之前所说,Stream 一般不会修改数据源。

    map

    中间操作 map 会将元素根据指定的 Function 接口来依次将元素转成另外的对象。

    stringList.stream().map(String::toUpperCase).forEach(System.out::println);
    

    match

    Stream 提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作 ,并返回一个 boolean 类型的值。

    boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a")); // true
    boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a")); // false
    boolean nonStartsWithZ = stringList.stream().noneMatch((s) -> s.startsWith("z")); // true
    

    count

    计数是一个最终操作,返回 Stream 中元素的个数,需要注意返回值类型是 long

    long countStartsWithA = stringList.stream().filter((s) -> s.startsWith("a")).count();
    

    这是一个最终操作 ,允许通过指定的函数来将stream中的多个元素规约为一个元素,规约后的结果是通过Optional 接口表示的。

    Optional<String> reduced = stringList.stream()
                                    .sorted()
                                    .reduce((s1, s2) -> (s1 + "#" + s2));
    reduced.ifPresent(System.out::println);
    

    一般来说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。例如 Stream 的 sum 就相当于Integer sum = integers.reduce(0, (a, b) -> a+b);,也有没有起始值的情况,这时会把 Stream 的前面两个元素组合起来,返回的是 Optional。

    Parallel Stream

    Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

    并行Stream效率较高,但是不保证顺序。

    IntStream、LongStream和DoubleStream

    这三者分别是int、long和double类型的流,其实有很多和Stream类似的地方。

    具体暂时先不展开介绍了。

    相关文章

      网友评论

          本文标题:Java8特性学习笔记(四) Stream

          本文链接:https://www.haomeiwen.com/subject/carvqrtx.html