JDK Stream

方法名JDK版本备注
创建Streamof(T... )8
empty()8创建空的Stream流
generate()8生成无限流
iterate()9创建无限流
ofNullable()9类似于Optional ofNullable()
映射和过滤filter()8
map[int double long]()8一一映射
flatMap[int double long]()81、一对多映射
抽取流和组合流limit()8
skip()8跳过前几个,和limit互补
takeWhile()9当满足条件留下
dropWhile()9满足条件丢弃
concat()8连接两个流,静态方法
其余流的转换distinct()8去除重复数值
sorted()8按照自然顺序排序
peek()8一般对元素的内部属性进行调整,类型不发生改变
结束操作(约简操作)max()8最大值
min()8最小值
count()8统计数量
findFirst8找出第一个,返回Optional
findAny8找出任意一个,返回Optional
anyMatch8任意一个匹配,boolean
allMatch8全部匹配,boolean
noneMatch8没有匹配的,boolean
reducereduce(accumulator)8执行累加,返回Optional
reduce(identify, accumulator)8带有幺元数,返回固定值
reduce(identify, accumulator, combiner)8累加器和组合器
收集操作forEach()8遍历所有流元素
toArray([Integer[]::new])8转为类型对象数组。默认为Object数组
collect(Collectors.toList())8转为list
collect(Collectors.toSet())8转为Set
collect(Collectors.toCollection())8转为自定义集合
collect(Collectors.summarizingInt())8转为数学统计对象
映射到表中toMap(key, value)8冲突会报错
toMap(key, value, overload)8指明冲突后value的取值
toMap(key, value, overload / exception, TreeMap::new)8
分组和分区groupingBy()8分组
partitionBy()8分区
下游收集器groupingBy(Person::getGender, Collectors.toSet())8分组结果为Set去重
groupingBy(Person::getGender, Collectors.counting())8分组结果进行计数
groupingBy(Person::getGender, Collectors.summingLong(Person::getId))8分组结果求和
groupingBy(Person::getGender, Collectors.summarizingLong(Person::getId))8分组结果转为数学统计
groupingBy(Person::getGender, Collectors.maxBy(Comparator.comparing(Person::getName)8分组结果求取最大值
groupingBy(Person::getGender, Collectors.minBy(Comparator.comparing(Person::getName))8同上,最小值
groupingBy(Person::getGender, Collectors.collectingAndThen(Collectors.toSet(), Set::size))8先收集在转换
groupingBy(Person::getGender, Collectors.mapping(Person::getName, Collectors.toSet()))8先转换在收集
基本类型流range8获取一定范围内的数据流
rangeClosed8同上,闭区间
of8直接创建数据流
toArray()8转为int[]
sum / average/ min / max8计算结果
summaryStatistics8数学计算
boxed8获得包装器对象Stream<Integer>
Radom.ints()8随机产生数据流,不可分割(无法使用并行流)
并行流parallel()8并行处理
unordered()8不排序

1. 创建Stream

方法名JDK版本备注
of(T... )8
empty()8创建空的Stream流
generate()8生成无限流
iterate()9创建无限流
ofNullable()9类似于Optional ofNullable()
public class MyStreamTest {
    @Test
    public void test01() {
        List<Integer> list = Arrays.asList(1, 2, 3);
        Stream<Integer> stream = list.stream();
        Stream<Integer> stream1 = Stream.of(1, 2, 3);
        Stream<List<Integer>> stream2 = Stream.empty();
        Stream<String> generate = Stream.generate(() -> "Hello World");
        Stream<Double> generate1 = Stream.generate(Math::random);
        Stream<BigInteger> iterate = Stream.iterate(BigInteger.ONE, i -> i.add(BigInteger.ONE));
        // JDK9 优化有限流
        // Stream<BigInteger> iterate2 = Stream.iterate(BigInteger.ONE, i -> i.compareTo(new BigInteger("100")) < 0,i -> i.add(BigInteger.ONE));
        // Stream.ofNullable(); JDK9增强
        generate.forEach(System.out::println);
    }
}

2. 映射和过滤

方法名JDK版本备注
filter()8过滤
map[int double long]()8一一映射
flatMap[int double long]()81、一对多映射

流如果是empty()创建的则不会通过map,如果流中包含null则会通过map

public class MyStreamTest {

    @Test
    public void test05() {
        Stream<String> stream = Stream.of("Hello", "World");
        stream.filter(i -> i.length() > 3)
                        .map(String::toUpperCase)
                        .forEach(System.out::print);

        stream = Stream.of("Hello", "World");
        stream.flatMap(s -> {
                    String[] array = s.split("");
                    return Stream.of(array);
                }).forEach(System.out::println);

        stream = Stream.empty();
        stream.map(i -> {
            System.out.println("不会通过");
            return i;
        });
    }
}

3. 抽取流和组合流

方法名JDK版本备注
limit()8限制输出个数
skip()8跳过前几个,和limit互补
takeWhile()9当满足条件留下
dropWhile()9满足条件丢弃
concat()8连接两个流,静态方法
public class MyStreamTest {
    @Test
    public void test03() {
        Stream<String> stream = Stream.of("Hello", "World");
        stream.limit(2)
                .skip(0)
                .forEach(System.out::println);
        Stream<String> stream1 = Stream.of("Hello", "World");
        Stream<String> stream2 = Stream.of("Hello", "World");
        Stream<String> stream3 = Stream.concat(stream1, stream2);
    }
}

4. 其余流的转换

方法名JDK版本备注
distinct()8去除重复数值
sorted()8按照自然顺序排序
peek()8一般对元素的内部属性进行调整,类型不发生改变
public class MyStreamTest {
    @Test
    public void test04() {
        Stream<String> stream = Stream.of(null, "Hello", "World");
        stream.distinct()
                .sorted(String::compareToIgnoreCase)  // 忽略大小写
                .peek(s -> System.out.println(s.toUpperCase()))
                .forEach(System.out::println);
    }
}

5. 结束操作(约简操作)

方法名JDK版本备注
max()8最大值
min()8最小值
count()8统计数量
findFirst8找出第一个,返回Optional
findAny8找出任意一个,返回Optional
anyMatch8任意一个匹配,boolean
allMatch8全部匹配,boolean
noneMatch8没有匹配的,boolean
public class MyStreamTest {
    public void test05() {
        Stream<Integer> stream = Stream.of(11, 2, 49, 4, 34);
        Optional<Integer> max = stream.max(Comparator.reverseOrder());
        Optional<Integer> min = stream.min(Comparator.naturalOrder());
        long count = stream.count();
        Optional<Integer> first = stream.findFirst();
        Optional<Integer> any = stream.parallel().findAny();
        boolean anyMatch = stream.parallel().anyMatch(integer -> integer > 5);
        boolean allMatch = stream.parallel().allMatch(integer -> integer > 0);
        boolean noneMatch = stream.parallel().noneMatch(i -> i > 100);
    }
}

reduce

方法名JDK版本备注
reduce(accumulator)8执行累加,返回Optional
reduce(identify, accumulator)8带有幺元数,返回固定值
reduce(identify, accumulator, combiner)8累加器和组合器
public class MyStreamTest {
    @Test
    public void test10() {
        Stream<Integer> stream = Stream.of(1, 2, 3);
        Optional<Integer> reduce = stream.reduce((integer, integer2) -> integer + integer2);
        Integer reduce1 = stream.reduce(0, Integer::sum);
        Stream<String> stringStream = Stream.of("Hello", "World");
        Integer reduce2 = stringStream.reduce(0, (total, word) -> total + word.length(), (t1, t2) -> t1 + t2);
    }
}

6. 收集操作

方法名JDK版本备注
forEach()8遍历所有流元素
toArray([Integer[]::new])8转为类型对象数组。默认为Object数组
collect(Collectors.toList())8转为list
collect(Collectors.toSet())8转为Set
collect(Collectors.toCollection())8转为自定义集合
collect(Collectors.summarizingInt())8转为数学统计对象
public class MyStreamTest {
    @Test
    public void test06() {
        Stream<Integer> stream = Stream.of(1, 2, 3);
        stream.forEach(System.out::println);
        Object[] objects = stream.toArray();
        Integer[] array = stream.toArray(Integer[]::new);
        int[] array1 = stream.mapToInt(Integer::intValue).toArray();

        List<Integer> collect = stream.collect(Collectors.toList());
        Set<Integer> collect1 = stream.collect(Collectors.toSet());
        TreeSet<Integer> collect2 = stream.collect(Collectors.toCollection(TreeSet::new));

        IntSummaryStatistics statistics = stream.collect(Collectors.summarizingInt(Integer::intValue));
        statistics.getMin();
        statistics.getMax();
        statistics.getCount();
        statistics.getAverage();
        statistics.getSum();
    }
}

映射到表中

方法名JDK版本备注
toMap(key, value)8冲突会报错
toMap(key, value, overload)8指明冲突后value的取值
toMap(key, value, overload / exception, TreeMap::new)8指定映射表的类型
public class MyStreamTest {
    @Test
    public void test07() {
        Stream<Person> personStream = Stream.of(new Person(1L, "男", "小明"), new Person(2L, "女", "小红"));
        Map<Long, String> collect = personStream.collect(Collectors.toMap(Person::getId, Person::getName));
        Map<Long, Person> map = personStream.collect(Collectors.toMap(Person::getId, Function.identity()));
        Map<Long, Person> map2 = personStream.collect(Collectors.toMap(Person::getId, Function.identity(), (person, person2) -> person));
        TreeMap<Long, Person> map3 = personStream.collect(Collectors.toMap(Person::getId, Function.identity(), (person, person2) -> {
            throw new IllegalStateException();
        }, TreeMap::new));
    }
}

7. 分组和分区

方法名JDK版本备注
groupingBy()8分组
partitionBy()8分区
public class MyStreamTest {
    @Test
    public void test08() {
        Stream<Person> personStream = Stream.of(new Person(1L, "男", "小明"), new Person(2L, "女", "小红"));
        Map<String, List<Person>> collect = personStream.collect(Collectors.groupingBy(Person::getGender));
        Map<Boolean, List<Person>> collect1 = personStream.collect(Collectors.partitioningBy(person -> person.getId() > 1));
    }
}

下游收集器

方法名JDK版本备注
groupingBy(Person::getGender, Collectors.toSet())8分组结果为Set去重
groupingBy(Person::getGender, Collectors.counting())8分组结果进行计数
groupingBy(Person::getGender, Collectors.summingLong(Person::getId))8分组结果求和
groupingBy(Person::getGender, Collectors.summarizingLong(Person::getId))8分组结果转为数学统计
groupingBy(Person::getGender, Collectors.maxBy(Comparator.comparing(Person::getName)8分组结果求取最大值
groupingBy(Person::getGender, Collectors.minBy(Comparator.comparing(Person::getName))8同上,最小值
groupingBy(Person::getGender, Collectors.collectingAndThen(Collectors.toSet(), Set::size))8先收集在转换
groupingBy(Person::getGender, Collectors.mapping(Person::getName, Collectors.toSet()))8先转换在收集

同样适用于partitionBy()

public class MyStreamTest {
    @Test
    public void test09() {
        Stream<Person> personStream = Stream.of(new Person(1L, "男", "小明"), new Person(2L, "女", "小红"));
        Map<String, Set<Person>> collect = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.toSet()));
        Map<String, Long> collect1 = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.counting()));

        Map<String, Long> collect2 = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.summingLong(Person::getId)));
        Map<String, LongSummaryStatistics> collect3 = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.summarizingLong(Person::getId)));

        Map<String, Optional<Person>> collect4 = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.maxBy(Comparator.comparing(Person::getName))));
        Map<String, Optional<Person>> collect5 = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.minBy(Comparator.comparing(Person::getName))));
        // 去重复操作 先收集到Set在统计
        Map<String, Integer> collect6 = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.collectingAndThen(Collectors.toSet(), Set::size)));
        Map<String, Set<String>> collect7 = personStream.collect(Collectors.groupingBy(Person::getGender, Collectors.mapping(Person::getName, Collectors.toSet())));
    }
}

8. 基本类型流

方法名JDK版本备注
range8获取一定范围内的数据流
rangeClosed8同上,闭区间
of8直接创建数据流
toArray()8转为int[]
sum / average/ min / max8计算结果
summaryStatistics8数学计算
boxed8获得包装器对象Stream<Integer>
Radom.ints()8随机产生数据流,不可分割(无法使用并行流)
public class MyStreamTest {
    @Test
    public void test11() {
        IntStream stream = IntStream.of(1, 2, 3, 4);
        IntStream intStream = IntStream.rangeClosed(0, 10);
        int[] ints = stream.toArray();
        int sum = stream.sum();
        IntSummaryStatistics statistics = stream.summaryStatistics();
        long sum1 = statistics.getSum();
        Stream<Integer> boxed = intStream.boxed();

        String str = "Hello World";
        IntStream chars = str.chars();
        IntStream points = str.codePoints();
        List<Character> collect = chars.mapToObj(operand -> (char) operand).collect(Collectors.toList());

        Random random = new Random();
        IntStream stream1 = random.ints(0, 10);
        DoubleStream doubleStream = random.doubles(0, 10);
    }
}

9. 并行流

方法名JDK版本备注
parallel()8并行处理
unordered()8不排序

并行流 只要在终结方法之前处于并行状态,所有的中间操作都会被认定为并行操作,并不是所有的流都可以用来加速操作。

  1. 并行化会带来更大的资源损耗问题
  2. 只有底层的数据源可以被有效分割的时候并行化才有意义 Random.ints()产生的流不可分割,转为使用SplittableRandom.ints()
  3. 并行流使用的线程池可能会由于处理密集操作而其他IO操作被阻塞死
public class MyStreamTest {
    @Test
    public void test12() {
        Stream<String> stringStream = Stream.of("Hello", "World");
        // 无状态 不会处于并发安全问题
        Map<Integer, Long> collect = stringStream.parallel().filter(s -> s.length() > 3).collect(Collectors.groupingBy(String::length, Collectors.counting()));
        // 当对顺序要求不高的时候, 效率更高
        Stream<String> limit = stringStream.parallel().unordered().limit(10);
    }
}

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://quguai.cn/archives/jdkstream