11.toCollection:将流中的元素收集到给定的集合类型中。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collection<String> collectedNames = names.stream()
.collect(Collectors.toCollection(ArrayList::new));
System.out.println(collectedNames); // 输出: [Alice, Bob, Charlie]
12.groupingByConcurrent:类似于 groupingBy
,但使用并发映射来存储结果,适用于并行流。
List<Person> people = ...;
ConcurrentMap<String, List<Person>> genderMap = people.parallelStream()
.collect(Collectors.groupingByConcurrent(Person::getGender));
13.partitioningBy:根据给定的谓词对流中的元素进行分区,结果是一个包含两个列表的映射,一个列表包含满足谓词的元素,另一个包含不满足的元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Map<Boolean, List<Integer>> partitionedNumbers = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println(partitionedNumbers); // 输出: {false=[1, 3, 5], true=[2, 4]}
14.mapping:对流中的元素应用一个给定的函数,并将结果收集到一个新的容器中。这通常与其他收集器一起使用。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
.collect(Collectors.mapping(String::length, Collectors.toList()));
System.out.println(nameLengths); // 输出: [5, 3, 7]
15.Collectors.of
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class CustomCollectorExample {
public static void main(String[] args) {
List<Person> people = List.of(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// 使用自定义收集器
List<Person> collectedPeople = people.stream()
.collect(customPersonListCollector());
System.out.println(collectedPeople);
}
// 自定义收集器
public static Collector<Person, ?, List<Person>> customPersonListCollector() {
return Collector.of(
// 供应商:创建一个空的列表作为初始容器
ArrayList::new,
// 累加器:将元素添加到列表中,并在添加前打印
(list, person) -> {
System.out.println("Adding: " + person);
list.add(person);
},
// 合并器(可选):并行流中合并两个列表
(left, right) -> {
left.addAll(right);
return left;
},
// 完成器(可选):转换最终容器为所需类型,这里直接返回列表
Function.identity()
);
}
}
在这个示例中,customPersonListCollector
方法返回一个 Collector
实例,该实例配置了自定义的初始容器(使用 ArrayList::new
创建的列表)、累加器(将元素添加到列表并打印)、合并器(用于并行流中合并两个列表)和完成器(直接返回列表)。
运行这个程序时,你会看到每个 Person
对象在添加到列表中之前都被打印出来,最后打印出整个收集到的 Person
列表。
注意,虽然在这个简单的例子中我们没有利用并行流(即没有创建竞争条件),但在使用自定义收集器与并行流时,需要确保你的合并器是线程安全的。在上面的例子中,ArrayList
的 addAll
方法是线程安全的,因为它在内部进行了适当的同步(尽管在单个线程环境中这不是必需的)。然而,在更复杂的情况下,你可能需要更仔细地管理线程安全。
16.collectingAndThen
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectingAndThenExample {
public static void main(String[] args) {
List<String> strings = Arrays.asList("apple", "banana", "cherry");
// 使用 collectingAndThen 来收集并转换结果
String concatenatedString = strings.stream()
.collect(Collectors.collectingAndThen(
// 第一个参数是现有的收集器,这里我们收集到一个列表中
Collectors.toList(),
// 第二个参数是一个完成函数,它接受收集到的结果(这里是List<String>),并返回一个新的结果
// 在这里,我们使用String.join来连接列表中的所有字符串
list -> String.join(", ", list)
));
System.out.println(concatenatedString); // 输出: apple, banana, cherry
}
}
在这个示例中,collectingAndThen
方法接受两个参数:
-
第一个参数是一个
Collector
,它定义了如何收集流中的元素。在这个例子中,我们使用Collectors.toList()
来收集元素到一个List
中。 -
第二个参数是一个函数,它接收收集器的结果(在这个例子中是
List<String>
),并返回一个新的结果。在这个例子中,我们传递了一个 lambda 表达式,它使用String.join
方法将列表中的所有字符串连接成一个单独的字符串,每个字符串之间用逗号加空格分隔。
collectingAndThen
方法非常适合于在收集过程之后对结果进行简单转换的场景,而无需创建全新的收集器。