Stream

Stream::max(intInteger的不同)

1
2
3
4
5
int intArr[] = new int[]{1, 2, 3};
Arrays.stream(intArr).max().getAsInt();

Integer integerArr[] = new Integer[]{1, 2, 3};
Arrays.stream(integerArr).max(Integer::compareTo).get();

Stream中 intInteger 互相转换

mapToObj: int -> Integer

三种方式:mapToObj(Integer::valueOf), mapToObj(i->Integer.valueOf(i)), mapToObj(i->i)

1
2
3
// int数组转换成Integer列表
int nums = new int[]{1, 2, 3};
List<Integer> list = Arrays.stream(nums).mapToObj(Integer::valueOf).collect(Collectors.toList());

mapToInt: Integer -> int

三种方式:mapToInt(Integer::intValue), mapToInt(i->(int)i), mapToInt(i->i)

1
2
3
4
5
// Integer列表转换成int数组
int[] nums = l.stream().mapToInt(i -> i).toArray();
// Integer列表进行stream求和等操作
list.stream().mapToInt(Integer::intValue).sum();
list.stream().mapToInt(i->i).sum();

创建Stream

  • 从数组创建
1
2
3
Integer[] arr = {1, 3, 2, 5, 4};
Stream<Integer> arrStream = Arrays.stream(arr);
// Stream<Integer> arrStream = Stream.of(arr);
  • 从集合创建
1
2
List<Integer> list = Arrays.asList(arr);
Stream<Integer> listStream = list.stream();

生成器Stream::generate和迭代器Stream::iterate

1
2
3
4
5
6
// 随机数生成器,输出5个随机数
Stream<Double> generate = Stream.generate(Math::random);
generate.limit(5).forEach((a)-> System.out.println("a = " + a));
// 自然数迭代器,输出0、1、2、3、4
Stream<Integer> iterate = Stream.iterate(0, (a) -> a + 1);
iterate.limit(5).forEach((a)-> System.out.println("a = " + a));

过滤器filter(func)

1
2
3
// list = [1, 3, 2, 5, 4]
list.stream().filter((a) -> a < 5).forEach(System.out::print); // 1324
System.out.println();

映射map

  • map(func)
1
2
3
Stream<Stream<Integer>> mapResult = list.stream().map((a) -> Stream.of(new Integer[]{a, a}));
mapResult.forEach((a)->{ a.forEach(System.out::print); }); // 1133225544
System.out.println();
  • flatmap(func)
1
2
3
4
// flatMap可以降维
Stream<Integer> flatMapResult = list.stream().flatMap((a) -> Stream.of(new Integer[]{a, a}));
flatMapResult.forEach(System.out::print); // 1133225544
System.out.println();

去重distinct()

对原集合排序(产生一个新集合)sort(func || Comparator):

子流和组合流

  • limit(n):提取前n个
  • skip(n):去掉前n个
  • concat(Stream, Stream):拼接两个Stream
  • peek(func):提取Stream当前元素,进行其它操作(例如打印)

聚合(聚合是终止操作,之后不可以进行其它流的操作)(forEach也是终止操作)

  • count:获取流的大小
  • (以下函数返回Optional类型,因为可能为null)
  • max():获取流的最大值
  • min():获取流的最小值
  • findFirst(func->boolean):找到第一个符合条件的值
  • findAny(func->boolean):将流分成很多组,并行找到第一个符合条件的值
  • 自定义聚合reduce

reduce(identity, accumulator, combiner)

1
2
3
4
5
6
7
8
9
List<Integer> l = Arrays.asList(1,2,3);
Integer reduce = l.stream().reduce(0, (r, a) -> r + a);
System.out.println("reduce = " + reduce);
// 如果是IntStream则没有全参的reduce方法,只有两个参数的reduce方法
Integer reduce2 = l.stream().reduce(0, (r, a) -> r + a, (r1,r2)->r1+r2);
System.out.println("reduce2 = " + reduce2);
// 只有accumulator参数时,返回结果是optional类型
Integer reduce3 = l.stream().reduce((r, a) -> r + a).get();
System.out.println("reduce3 = " + reduce3);

Optional类型

  • isPresent():是否存在
  • isPresent(func):如果存在,进行func操作
  • get():获取值
  • orElse(x):如果存在,获取值;如果不存在,获取默认值x
1
2
3
4
5
6
Optional<Integer> max = list.stream().max(Integer::compare);
max.ifPresent(System.out::println); // 5
System.out.println("max.isPresent() = " + max.isPresent()); // max.isPresent() = true
System.out.println("max.get() = " + max.get()); // max.get() = 5
Optional<Integer> empty = Optional.empty();
System.out.println("empty.orElse(-1) = " + empty.orElse(-1)); // empty.orElse(-1) = -1

收集collect

  • 将流收集到集合中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 收集到List集合的3种方法
List<Integer> collect = list.stream().collect(Collectors.toList());
List<Integer> collect1 = list.stream().collect(ArrayList::new, ArrayList::add, ArrayList::addAll); // 可以指定具体集合类型
List<Integer> collect2 = list.stream().collect(Collectors.toCollection(ArrayList::new)); // 可以指定具体集合类型
// 收集到Map集合
Map<Integer, Integer> collect5 = list.stream().collect(Collectors.toMap((a) -> a.hashCode(), (a) -> a.intValue()));
System.out.println("collect5 = " + collect5); // collect5 = {1=1, 2=2, 3=3, 4=4, 5=5}
// Map集合需要解决重复键值的问题,如下所示
// Locale.getAvailableLocales()得到每个国家使用的语言环境信息
// 获取每个国家默认语言对应的翻译
Map<String, String> collect6 = Stream.of(Locale.getAvailableLocales()).collect(Collectors.toMap(
(l) -> l.getDisplayLanguage(), // 获取当前国家的默认语言(用中文显示,因为本地环境是中文)
(l) -> l.getDisplayLanguage(l), // // 获取当前国家的默认语言(用该默认语言显示显示)
(oldValue, newValue) -> oldValue // 重复键值处理函数,返回旧值
));
System.out.println("collect6 = " + collect6); // collect6 = {土耳其文=Türkçe, =, 意大利文=italiano, 冰岛文=íslenska...}

// 获取每个国家使用的语言
Map<String, Set<String>> collect7 = Stream.of(Locale.getAvailableLocales()).collect(Collectors.toMap(
(l) -> l.getDisplayCountry(), // 获取当前国家的名称
(l) -> Collections.singleton(l.getDisplayLanguage()), // Collections.singleton将Object转化成包含一个Object的set集合
(oldValue, newValue) -> { // 重复键值处理函数,加入到set集合中
Set<String> set = new HashSet(oldValue);
set.addAll(newValue);
return set;
}
));
System.out.println("collect7 = " + collect7); // collect7 = {泰国=[泰文], 巴西=[葡萄牙文], =[, 土耳其文, 意大利文...}
  • Collector的Join操作(类似python的join)
1
2
String collect3 = list.stream().map(String::valueOf).collect(Collectors.joining(", "));
System.out.println("collect3 = " + collect3); // collect3 = 1, 3, 2, 5, 4
  • Summary
1
2
3
4
IntSummaryStatistics collect4 = list.stream().collect(Collectors.summarizingInt(Integer::valueOf));
System.out.println("collect4 = " + collect4); // collect4 = IntSummaryStatistics{count=5, sum=15, min=1, average=3.000000, max=5}
System.out.println("collect4.getSum() = " + collect4.getSum()); // collect4.getSum() = 15
System.out.println("collect4.getAverage() = " + collect4.getAverage()); // collect4.getAverage() = 3.0

分组和分片

  • GroupingBy
1
2
3
4
5
6
// 根据国家分组
Map<String, List<Locale>> collect8 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.groupingBy(Locale::getCountry));
System.out.println("collect8 = " + collect8);
// collect8 = {=[, bg, it, ko, uk, lv, pt, sk, ga, et, sv, cs, el, hu, in, be, es, tr, hr, lt, sq, fr, ja, is, de, en, ca, sl, fi, mk, sr__#Latn, th, ar, ru, ms, hi, nl, vi, sr, mt, da, ro, no, pl, iw, zh], DE=[de_DE], PR=[es_PR], HK=[zh_HK], TW=[zh_TW]...}
System.out.println("collect8.get(\"CH\") = " + collect8.get("CH")); // collect8.get("CH") = [fr_CH, de_CH, it_CH]
  • 当分组是两类(Boolean)时,使用PartitionBy会更快
1
2
3
4
// 根据是否使用英语分组
Map<Boolean, List<Locale>> collect9 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.partitioningBy(l -> l.getLanguage().equals("en")));
System.out.println("collect9 = " + collect9); // collect9 = {false=[, ar_AE, ar_JO...], true=[...]}

DownStream收集器,对分组结果产生的map的value类型进行处理

  • GroupingBy和PartitioningBy产生的结果的默认value值类型时List,进行downstream处理,自定义value类型
1
2
3
4
5
6
7
8
// 根据国家分组, 转换成set类型
Map<String, Set<Locale>> collect10 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.groupingBy(Locale::getCountry, Collectors.toSet()));
System.out.println("collect10 = " + collect10); // collect10 = {=[, in, sl, v...], ...}
// 根据国家分组,进行count数量统计
Map<String, Long> collect11 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.groupingBy(Locale::getCountry, Collectors.counting()));
System.out.println("collect11 = " + collect11); // collect11 = {=46, DE=1, PR=1, HK=1, TW=1,...}
  • groupingBy+mapping可以实现collect(Collectors.toMap())的作用
1
2
3
4
5
// 获取每个国家使用的语言
Map<String, Set<String>> collect13 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.groupingBy(Locale::getDisplayCountry,
Collectors.mapping(Locale::getDisplayLanguage, Collectors.toSet())));
System.out.println("collect13 = " + collect13); // collect13 = {泰国=[泰文], 巴西=[葡萄牙文], =[, 土耳其文, 意大利文...}
  • groupingBy+mapping+自定义value类型
1
2
3
4
5
6
7
// 根据国家分组,并在每个国家中获取名称最长的语言
Map<String, Optional<String>> collect12 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.groupingBy(Locale::getCountry,
Collectors.mapping(Locale::getLanguage,
Collectors.maxBy(Comparator.comparing(String::length)))
));
System.out.println("collect12 = " + collect12); // collect12 = {=Optional[bg], DE=Optional[de], ...}
  • groupingBy+reducing(分组聚合)
1
2
3
4
5
6
7
8
9
10
11
// 根据国家分组,获取每个国家使用的所有语言的聚合
Map<String, String> collect14 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.groupingBy(Locale::getDisplayCountry,
Collectors.reducing("", Locale::getDisplayLanguage,
(result, a) -> result = result.length() == 0 ? a : result + "+" + a)));
System.out.println("collect14 = " + collect14); // collect14 = {泰国=泰文+泰文, 巴西=葡萄牙文,...}
// 也可以通过groupingBy+mapping实现
Map<String, String> collect15 = Stream.of(Locale.getAvailableLocales()).collect(
Collectors.groupingBy(Locale::getDisplayCountry,
Collectors.mapping(Locale::getDisplayLanguage, Collectors.joining("+"))));
System.out.println("collect15 = " + collect15); // collect15 = {泰国=泰文+泰文, 巴西=葡萄牙文,...}

对一些原生类型提供专门接口

  • IntStream(short、char、byte、boolean、int)、LongStream(long)、DoubleStream(float、double)
1
2
3
4
5
6
7
8
9
10
11
int[] arr = {1, 3, 2, 5, 4};
IntStream stream = Arrays.stream(arr);

IntStream intStream = IntStream.range(0, 10);
intStream.forEach(System.out::print); // 0123456789
Stream<Integer> integerStream = IntStream.range(0, 10).boxed();
ArrayList<Integer> collect = integerStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
System.out.println("collect = " + collect); // collect = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
IntSummaryStatistics summary = IntStream.range(0, 10).boxed().collect(
Collectors.summarizingInt(Integer::valueOf));
System.out.println("summary = " + summary); // summary = IntSummaryStatistics{count=10, sum=45, min=0, average=4.500000, max=9}

并行

1
2
3
4
5
6
7
8
IntStream.range(0, 10).boxed().parallel().limit(5).forEach(System.out::print);  // 20413
System.out.println();
IntStream.range(0, 10).boxed().unordered().limit(5).forEach(System.out::print); // 01234
System.out.println();
IntStream.range(0, 10).boxed().parallel().unordered().limit(5).forEach(System.out::print); // 24013
System.out.println();
IntStream.range(0, 10).boxed().unordered().parallel().limit(5).forEach(System.out::print); // 24013
System.out.println();