Java 8引入的Stream API为集合数据的处理提供了更简洁高效的方式,其中collect方法是终端操作的核心,能够将流中的元素按照指定规则收集为各类集合或自定义结果。通过collect方法,我们可以灵活地将流转换为List、Set、Map等常见集合类型,满足不同的业务需求。
Stream.collect方法的基本作用
collect方法是Stream接口的终端操作,调用后会触发流的执行并返回最终结果。它接收一个Collector接口的实现作为参数,该参数定义了元素收集的具体规则,包括元素的累积、最终转换等逻辑。Java在java.util.stream.Collectors类中提供了大量预定义的Collector实现,覆盖了大部分常见的收集场景。
将流收集为List集合
将流收集为List是最常用的场景之一,直接使用Collectors.toList()即可实现。该方法会将流中的所有元素收集到一个新的List实例中,默认返回的是ArrayList,具体实现可能随JDK版本略有差异,但不需要开发者关心底层细节。
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamCollectToList {
public static void main(String[] args) {
// 创建一个包含字符串的流
Stream<String> stream = Stream.of("apple", "banana", "cherry", "apple");
// 使用collect方法将流收集为List
List<String> resultList = stream.collect(Collectors.toList());
// 输出结果
System.out.println(resultList); // 输出:[apple, banana, cherry, apple]
}
}
将流收集为Set集合
如果需要收集后的集合自动去重,可以使用Collectors.toSet()将流收集为Set集合。Set集合的特性会保证其中的元素不重复,因此如果流中存在重复元素,收集后只会保留一个。
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamCollectToSet {
public static void main(String[] args) {
Stream<String> stream = Stream.of("apple", "banana", "cherry", "apple");
// 使用collect方法将流收集为Set,自动去重
Set<String> resultSet = stream.collect(Collectors.toSet());
System.out.println(resultSet); // 输出:[banana, cherry, apple] 顺序不固定
}
}
将流收集为指定类型的集合
默认的toList和toSet返回的集合类型是JDK预设的,如果需要指定具体的集合实现类,比如LinkedList或者TreeSet,可以使用Collectors.toCollection()方法,传入对应的集合构造器即可。
import java.util.LinkedList;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamCollectToSpecifiedCollection {
public static void main(String[] args) {
Stream<String> stream1 = Stream.of("apple", "banana", "cherry");
// 收集为LinkedList
LinkedList<String> linkedList = stream1.collect(Collectors.toCollection(LinkedList::new));
System.out.println(linkedList.getClass()); // 输出:class java.util.LinkedList
Stream<String> stream2 = Stream.of("apple", "banana", "cherry");
// 收集为TreeSet,自动排序
TreeSet<String> treeSet = stream2.collect(Collectors.toCollection(TreeSet::new));
System.out.println(treeSet); // 输出:[apple, banana, cherry] 按字典序排序
}
}
将流收集为Map集合
将流收集为Map需要使用Collectors.toMap()方法,该方法需要传入两个函数,分别定义键和值的映射规则。如果流中存在重复的键,还需要传入第三个参数定义键冲突的解决策略,否则会抛出IllegalStateException。
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamCollectToMap {
public static void main(String[] args) {
// 流元素为字符串,键为字符串长度,值为字符串本身
Stream<String> stream = Stream.of("a", "bb", "ccc", "dd");
// 处理键冲突:如果有重复长度,保留后面的元素
Map<Integer, String> resultMap = stream.collect(Collectors.toMap(
String::length, // 键:字符串长度
str -> str, // 值:字符串本身
(oldVal, newVal) -> newVal // 键冲突时保留新值
));
System.out.println(resultMap); // 输出:{1=a, 2=dd, 3=ccc}
}
}
注意事项
- collect方法是终端操作,调用后流就会被消费,无法再次使用。
- 使用toMap收集时,如果键可能为null,需要处理null值情况,否则会抛出NullPointerException。
- 并行流场景下,收集的集合需要保证线程安全,不过Collectors提供的收集器已经对并行场景做了适配,无需额外处理。
- 如果需要自定义收集逻辑,可以实现
Collector接口,或者使用Collectors.collectingAndThen()对收集结果做二次转换。