Java Stream collect()方法示例

时间:2020-02-23 14:34:31  来源:igfitidea点击:

Java Stream collect()对流的元素执行可变的约简操作。
这是终端操作。

什么是可变归约运算?

可变还原操作处理流元素,然后将其累积到可变结果容器中。
处理完元素后,合并功能将合并所有结果容器以创建结果。

Java Stream collect()方法签名

Java Stream collect()方法有两种变体。

  • <R> R收集(供应商<R>供应商,BiConsumer <R 、?超级T>累加器,BiConsumer <R,R>组合器)
  • <R,A> R收集器(Collector <?super T,A,R>收集器)

收集器是一个接口,为供应商,累加器和组合器对象提供包装。
当我们利用Collectors类提供内置的Collector实现时,第二种方法很有用。

collect()函数的三个参数是:

  • 供应商:创建新的可变结果容器的函数。
    对于并行执行,可以多次调用此函数,并且每次必须返回一个新值。

  • 累加器是一种无状态函数,必须将元素折叠到结果容器中。

  • 组合器是一个无状态函数,它接受两个部分结果容器并将其合并,这些容器必须与累加器功能兼容。

流collect()方法示例

我们来看一些Stream.collect()方法的示例。

1.串联字符串列表

假设您要连接字符串列表以创建新字符串。
我们可以使用Stream collect()函数执行可变的约简操作并连接列表元素。

List<String> vowels = List.of("a", "e", "i", "o", "u");

//sequential stream - nothing to combine
StringBuilder result = vowels.stream().collect(StringBuilder::new, (x, y) -> x.append(y),
		(a, b) -> a.append(",").append(b));
System.out.println(result.toString());

//parallel stream - combiner is combining partial results
StringBuilder result1 = vowels.parallelStream().collect(StringBuilder::new, (x, y) -> x.append(y),
		(a, b) -> a.append(",").append(b));
System.out.println(result1.toString());

输出:

aeiou
a,e,i,o,u
  • 供应商函数在每次调用中都返回一个新的StringBuilder对象。

  • 累加器功能将列表字符串元素附加到StringBuilder实例。

  • 合并器功能正在合并StringBuilder实例。
    实例彼此之间用逗号合并。

  • 在第一种情况下,我们有一个顺序的元素流。
    因此,它们被一个接一个地处理,并且只有一个StringBuilder实例。
    没有使用合并器功能。
    这就是为什么产生的输出是" aeiou"的原因。

  • 在第二种情况下,我们有并行的字符串流。
    因此,元素是并行处理的,并且组合器函数正在合并StringBuilder的多个实例。
    因此,产生的输出为" a,e,i,o,u"。

  • 如果流源是按顺序排序的,例如List,则collect()方法将在处理时保持顺序。
    如果流源是无序的(例如Set),则collect()方法在每次调用中会产生不同的结果。

如果要串联字符串列表,我们可以使用方法引用来减少代码大小。

String result2 = vowels.parallelStream()
		.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
		.toString();

2.使用collectors类将collect()流传输到列表

Collector类提供了Collector接口的许多有用的实现。
让我们看一个示例,其中我们将过滤整数列表以仅选择偶数整数。
Stream filter()是一个中间操作,返回一个流。
因此,我们将使用collect()函数从此流中创建列表。

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
		
List<Integer> evenNumbers = numbers.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
System.out.println(evenNumbers);  //[2, 4, 6]

Collectors.toList()返回一个Collector实现,该实现将输入元素累积到新的List中。

3.流collect()到集合

我们可以使用Collectors.toSet()将流元素收集到一个新的Set中。

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

Set<Integer> oddNumbers = numbers.parallelStream().filter(x -> x % 2 != 0).collect(Collectors.toSet());
System.out.println(oddNumbers); //[1, 3, 5]

3.流collect()到Map

我们可以使用Collectors.toMap()函数将流元素收集到Map中。
此方法接受两个用于映射键的参数和Map中的对应值。

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

Map<Integer, String> mapOddNumbers = numbers.parallelStream().filter(x -> x % 2 != 0)
		.collect(Collectors.toMap(Function.identity(), x -> String.valueOf(x)));
System.out.println(mapOddNumbers); //{1=1, 3=3, 5=5}

4.收集器join()示例

我们可以使用Collectors join()方法来获取Collector,该Collector以遭遇顺序连接输入流CharSequence元素。
我们可以使用它来连接字符串流,StringBuffer或者StringBuilder。

jshell> String value = Stream.of("a", "b", "c").collect(Collectors.joining());
value ==> "abc"

jshell> String valueCSV = Stream.of("a", "b", "c").collect(Collectors.joining(","));
valueCSV ==> "a,b,c"

jshell> String valueCSVLikeArray = Stream.of("a", "b", "c").collect(Collectors.joining(",", "{", "}"));
valueCSVLikeArray ==> "{a,b,c}"

jshell> String valueObject = Stream.of("1", new StringBuffer("2"), new StringBuilder("3")).collect(Collectors.joining());
valueObject ==> "123"