浅析Java中的Stream流(二)

124 阅读7分钟

在前一篇文章浅析Java中的Steam流中讲述了流式思想和Java中更适用于函数式编程的Stream流,以及Stream流中的一些常用方法,如forEach()filter()map()count()limit()skip()concat() 。本文中将讲述Stream中更多的方法,以及java.util.stream包下更多类型的Stream。

文章目录

1. 创建Stream流

前一篇文章中介绍了最为常用的两个创建Stream流的方法,即:

  • Collection集合的``stream()` 获取集合对应的Stream流

    • 使用Stream.of()创建包含多个数据的Stream流

除此之外,Stream中还有更多用于创建流的方法,如:

  • static <T> Stream<T> empty() 用于创建一个空流
  • static <T> Stream<T> generate(Supplier<? extends T> s):创建一个无限流,流中的元素通过反复调用s函数产生
  • static <T> Stream<T> iterate(T seed, UnaryOperator<T> f):创建一个无限流,参数包含seed、在seed上调用f产生的值、在前一个元素上调用f产生的值
  • static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next):类似于上一个方法,不同之处在于流会在遇到的第一个不满足hasNext条件时终止
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Stream;

public class SomeMethodsAboutGetStream {
    public static void main(String[] args) {
        // 创建空流
        final Stream<Object> empty = Stream.empty();
    empty.forEach(k-> System.out.println(k)); //
        System.out.println("-------------------");

        // 创建无限流
        BigInteger limit = new BigInteger("1000000");
        Stream.generate(()->"Hello").limit(5).forEach(k -> System.out.println(k));
        Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE)).limit(5).forEach(System.out::println);
        System.out.println("-------------------");
        
        Stream<Object> s15 = Stream.ofNullable(10);
        s15.forEach(System.out::println);  // 10
        System.out.println("-------------------");
    }
}

2. 抽取子流和组合流

类如之前的limit()skip()cooncat()都属于此类范畴的方法,它们会返回一个包含部分元素的新流。除此之外,相关的方法还有:

  • default Stream<T> takeWhile(Predicate<? super T> predicate):产生一个流,流中的元素满足传入的谓词条件
  • default Stream<T> dropWhile(Predicate<? super T> predicate):产生一个流,流的元素是当前流中排除不满足谓词条件的元素之外的所有元素
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Stream;

public class SomeMethodsAboutGetStream {
    public static void main(String[] args) {
        Stream<String> s0 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        Stream<String> s1 = Stream.of("Forlogen", "Kobe", "James", "Bill");
        s0.takeWhile(ss -> ss.startsWith("F")).forEach(System.out::println); // Forlogen
        s1.dropWhile(ss -> ss.startsWith("F")).forEach(System.out::println); // Kobe  James  Bill
        System.out.println("-------------------");
    }
}

3. 流的约简

  • Stream<T> distinct ():返回一个流,元素为原来流中的元素剔除重复元素后的结果

  • Stream<T> sorted ():按照自然序就行排列,如String按照字典序排序,数值型按照大小排序,排序的元素要实现Comparable接口

  • Stream<T> sorted (Comparator<? super T> comparator):根据传入的Comparator指定的顺序就行排列,返回一个新的流

    • 对于数值型数据,程序按数值大小进行排序
    • 对于String类型数据,程序按照字典序进行排序
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Stream;

public class SomeMethodsAboutGetStream {
    public static void main(String[] args) {
        Stream<String> s2 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forlogen","Forlogen");
        s2.distinct().forEach(System.out::println);
        System.out.println("-------------------"); // Forlogen  Kobe  James  Bill

        Stream<String> s3 = Stream.of("Forlogen", "Kobe", "James", "Bill");
        s3.sorted().forEach(System.out::println);
        System.out.println("-------------------");  // Bill Forlogen James  Kobe
        Stream<Integer> s4 = Stream.of(3, 1, 10, 7, 4);
        s4.sorted().forEach(System.out::println);  // 1 3 4 7 10
        System.out.println("-------------------");
        Stream<Integer> s5 = Stream.of(3, 1, 10, 7, 4);
        s5.sorted(Comparator.comparing(Integer::intValue).reversed()).forEach(System.out::println); // 10 7 4 3 1
        System.out.println("-------------------");

    }
}

4. 获取流中信息

之前已经学习过通过count()来获取流中元素的个数,此外还有如下的方法可以获取流中数据的一些其他信息:

  • Optional<T> max(Comparator<? super T> comparator)
  • Optional<T> min(Comparator<? super T> comparator)
  • Optional<T> findFirst()
  • Optional<T> findAny()
  • boolean anyMatch (Predicate<? super T> predicate) 流中存在匹配条件的元素时返回true
  • boolean allMatch (Predicate<? super T> predicate): 流中任意一个元素都匹配条件时返回true
  • boolean noneMatch (Predicate<? super T> predicate): 流中没有一个元素匹配条件时返回true
  • Object[] oArray(): 返回对象数组
  • <A> A[] toArray (IntFunction<A[]> generator):返回A类型的数组
  • Optional<T> reduce (BinaryOperator<T> accumulator):用给定的accumulator产生流中元素的累积总和
  • void forEachOrdered(Consumer<? super T> action): 为该流的每个元素执行一个操作,如果该流具有已定义的相遇顺序,则按照该流的相遇顺序执行
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Stream;

public class SomeMethodsAboutGetStream {
    public static void main(String[] args) {
        Stream<Integer> s6 = Stream.of(3, 1, 10, 7, 4);
        Optional<Integer> min = s6.min(Comparator.comparing(Integer::intValue));
        System.out.println(min.get());  // 1
        System.out.println("-------------------");
        Stream<Integer> s7 = Stream.of(3, 1, 10, 7, 4);
        Optional<Integer> max = s7.max(Comparator.comparing(Integer::intValue));
        System.out.println(max.get());  // 10
        System.out.println("-------------------");

        Stream<String> s8 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(s8.takeWhile(ss -> ss.startsWith("F")).findFirst().get()); // Forlogen
        System.out.println("-------------------");
        Stream<String> s9 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(s9.takeWhile(ss -> ss.startsWith("F")).findAny().get()); // Forlogen
        System.out.println("-------------------");

        Stream<String> s10 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        Stream<String> s11 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        Stream<String> s12 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(s10.anyMatch(s -> s.startsWith("F"))); // true
        System.out.println(s11.allMatch(s -> s.startsWith("F"))); // false
        System.out.println(s12.noneMatch(s -> s.startsWith("F"))); // false
        System.out.println("-------------------");

        Stream<String> s13 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(Arrays.toString(s13.takeWhile(s -> s.startsWith("F")).toArray())); // [Forlogen]
        Stream<String> s14 = Stream.of("Forever", "Kobe", "James", "Bill");
        System.out.println(Arrays.toString(s14.takeWhile(s -> s.length() > 4).toArray(String[]::new)));  // [Forever]
        System.out.println("-------------------");

        Stream<Object> s15 = Stream.ofNullable(10);
        s15.forEach(System.out::println);  // 10
        System.out.println("-------------------");

        Stream<Integer> s16 = Stream.of(3, 1, 10, 7, 4);
        System.out.println(s16.reduce(Integer::sum).get()); // 25
        System.out.println("-------------------");

        Stream<Integer> s17 = Stream.of(3, 1, 10, 7, 4);
        s17.forEach(System.out::println);
        System.out.println("-------------------");
        Stream<Integer> s18 = Stream.of(3, 1, 10, 7, 4);
        s18.forEachOrdered(System.out::println);
    }
}

5. 完整实验代码

import java.math.BigInteger;
import java.util.*;
import java.util.stream.Stream;

public class SomeMethodsAboutGetStream {
    public static void main(String[] args) {
        // 创建空流
        final Stream<Object> empty = Stream.empty();
        empty.forEach(k-> System.out.println(k)); //
        System.out.println("-------------------");

        // 创建无限流
        BigInteger limit = new BigInteger("1000000");
        Stream.generate(()->"Hello").limit(5).forEach(k -> System.out.println(k));
        Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE)).limit(5).forEach(System.out::println);
//        System.out.println("-------------------");


        // stream()、map()、forEach()
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "Hello", "World");
        list.forEach(System.out::println);
        Stream<Stream<String>> out = list.stream().map(w -> codePoints(w));
        codePoints("World").forEach(System.out::println);
        System.out.println("-------------------");

        /*
        takeWhile()、dropWhile()
            takeWhile():产生一个流,流中的元素满足传入的谓词条件
            dropWhile():产生一个流,流的元素是当前流中排除不满足谓词条件的元素之外的所有元素
         */
        Stream<String> s0 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        Stream<String> s1 = Stream.of("Forlogen", "Kobe", "James", "Bill");
        s0.takeWhile(ss -> ss.startsWith("F")).forEach(System.out::println); // Forlogen
        s1.dropWhile(ss -> ss.startsWith("F")).forEach(System.out::println); // Kobe  James  Bill
        System.out.println("-------------------");

        /*
        Stream<T> distinct ():返回一个流,元素为原来流中的元素剔除重复元素后的结果
         */
        Stream<String> s2 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forlogen","Forlogen");
        s2.distinct().forEach(System.out::println);
        System.out.println("-------------------"); // Forlogen  Kobe  James  Bill

        /*
        Stream<T> sorted ():按照自然序就行排列,如String按照字典序排序,数值型按照大小排序
                            排序的元素要实现Comparable接口
        Stream<T> sorted (Comparator<? super T> comparator): 根据传入的Comparator指定的顺序就行排列,返回一个新的流
         */
        Stream<String> s3 = Stream.of("Forlogen", "Kobe", "James", "Bill");
        s3.sorted().forEach(System.out::println);
        System.out.println("-------------------");  // Bill Forlogen James  Kobe
        Stream<Integer> s4 = Stream.of(3, 1, 10, 7, 4);
        s4.sorted().forEach(System.out::println);  // 1 3 4 7 10
        System.out.println("-------------------");
        Stream<Integer> s5 = Stream.of(3, 1, 10, 7, 4);
        s5.sorted(Comparator.comparing(Integer::intValue).reversed()).forEach(System.out::println); // 10 7 4 3 1
        System.out.println("-------------------");

        /*
        Optional<T>	max(Comparator<? super T> comparator):返回按指定排序规则排序后流中的最小元素
        Optional<T>	min(Comparator<? super T> comparator):返回按指定排序规则排序后流中的最大元素
         */
        Stream<Integer> s6 = Stream.of(3, 1, 10, 7, 4);
        Optional<Integer> min = s6.min(Comparator.comparing(Integer::intValue));
        System.out.println(min.get());  // 1
        System.out.println("-------------------");
        Stream<Integer> s7 = Stream.of(3, 1, 10, 7, 4);
        Optional<Integer> max = s7.max(Comparator.comparing(Integer::intValue));
        System.out.println(max.get());  // 10
        System.out.println("-------------------");

        /*
        Optional<T>	findFirst():返回产生这个流的第一个元素
        Optional<T>	findAny():返回产生这个流的任意一个元素
        如果流为空,则返回空的Optional对象
         */
        Stream<String> s8 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(s8.takeWhile(ss -> ss.startsWith("F")).findFirst().get()); // Forlogen
        System.out.println("-------------------");
        Stream<String> s9 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(s9.takeWhile(ss -> ss.startsWith("F")).findAny().get()); // Forlogen
        System.out.println("-------------------");

        /*
        boolean	anyMatch (Predicate<? super T> predicate): 流中存在匹配条件的元素时返回true
        boolean	allMatch (Predicate<? super T> predicate): 流中任意一个元素都匹配条件时返回true
        boolean	noneMatch (Predicate<? super T> predicate): 流中没有一个元素匹配条件时返回true
         */
        Stream<String> s10 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        Stream<String> s11 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        Stream<String> s12 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(s10.anyMatch(s -> s.startsWith("F"))); // true
        System.out.println(s11.allMatch(s -> s.startsWith("F"))); // false
        System.out.println(s12.noneMatch(s -> s.startsWith("F"))); // false
        System.out.println("-------------------");

        /*
        Object[] oArray(): 返回对象数组
        <A> A[]	toArray (IntFunction<A[]> generator):返回A类型的数组
         */
        Stream<String> s13 = Stream.of("Forlogen", "Kobe", "James", "Bill", "Forever");
        System.out.println(Arrays.toString(s13.takeWhile(s -> s.startsWith("F")).toArray())); // [Forlogen]
        Stream<String> s14 = Stream.of("Forever", "Kobe", "James", "Bill");
        System.out.println(Arrays.toString(s14.takeWhile(s -> s.length() > 4).toArray(String[]::new)));  // [Forever]
        System.out.println("-------------------");

        /*
        static <T> Stream<T> ofNullable(T t):返回含单个元素的流
         */
        Stream<Object> s15 = Stream.ofNullable(10);
        s15.forEach(System.out::println);  // 10
        System.out.println("-------------------");

        /*
        Optional<T>	reduce (BinaryOperator<T> accumulator):用给定的accumulator产生流中元素的累积总和
         */
        Stream<Integer> s16 = Stream.of(3, 1, 10, 7, 4);
        System.out.println(s16.reduce(Integer::sum).get()); // 25
        System.out.println("-------------------");

        /*
        void forEachOrdered(Consumer<? super T> action): 为该流的每个元素执行一个操作,如果该流具有已定义的相遇顺序,则按照该流的相遇顺序执行。
         */
        Stream<Integer> s17 = Stream.of(3, 1, 10, 7, 4);
        s17.forEach(System.out::println);
        System.out.println("-------------------");
        Stream<Integer> s18 = Stream.of(3, 1, 10, 7, 4);
        s18.forEachOrdered(System.out::println);
    }

    public static Stream<String> codePoints(String s){
        ArrayList<String> list = new ArrayList<>();
        int i = 0;
        while (i < s.length()){
            int j = s.offsetByCodePoints(i, 1);
            list.add(s.substring(i, j));
            i = j;
        }
        return list.stream();
    }
}

6. 基本流

之前所有的关于Stream的操作,我们使用的都是java.util.Stream<T>,如果想要将int型的数据存储到流中程序实际上是将其保存到Stream<Integer>Stream<int>是不存在的,但这样就需要将其转换为对应的包装类型,效率较低。

java.util.stream中有DoubleStream、IntStream和LongStream来直接存储基本类型的值,而无需使用包装类

  • IntStream用于存储short、char、byte和boolean类型的数据
  • DoubleStream用于存储float、double型数据

基本类型流的创建同样可以使用of()generate()iterate()。除此之外,IntStream和LongStream有静态的方法range()rangeClosed()用于生成步长为1的整数范围

import java.util.Arrays;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.stream.IntStream;

public class BasicStream {
    public static void main(String[] args) {
        private static void TestIntStream() {
            System.out.println(Arrays.toString(IntStream.of(1, 4, 3, 15).toArray()));  // [1, 4, 3, 15]
            System.out.println("--------------------");

            System.out.println(Arrays.toString(IntStream.range(1, 10).toArray()));   // [1, 2, 3, 4, 5, 6, 7, 8, 9]
            System.out.println("--------------------");

            System.out.println(Arrays.toString(IntStream.rangeClosed(1, 10).toArray()));  // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
            System.out.println("--------------------");

            OptionalInt min = IntStream.range(1, 10).min();
            System.out.println(min.getAsInt());  // 1
            System.out.println("--------------------");

            OptionalInt max = IntStream.range(1, 10).max();
            System.out.println(max.getAsInt());  // 9
            System.out.println("--------------------");

            OptionalDouble average = IntStream.range(1, 10).average();
            System.out.println(average.getAsDouble());  // 5.0
            System.out.println("--------------------");

            int sum = IntStream.range(1, 10).sum();
            System.out.println(sum);   // 45
            System.out.println("--------------------");
        }
    }
}

DoubleStream和LongStream有相似的操作,详细信息可以查看API文档。

7. 并行流

并行流的获取方法:

  • 使用Collection.parallelStream()从任意集合中获取一个并行流
  • 使用parallel()将任意顺序的流转换为并行流