693 字
2 分钟
Java Stream API详解
Stream API是Java 8里我最喜欢的新特性之一,它让Java从命令式编程迈向了函数式编程的大门。刚开始用的时候觉得filter、map、reduce这些操作很陌生,但一旦上手了,写集合处理代码简直停不下来——太优雅了。
Java Stream API详解
Stream是什么?
Stream就是一个数据流处理管道。它不是数据结构,不存数据,只是对数据源(集合、数组等)进行一系列操作。
几个关键点:
- 中间操作是惰性的:不执行终端操作,中间操作不会触发
- Stream只能消费一次:用完就关闭了,不能重复使用
- 不修改数据源:Stream操作不会修改原始集合
创建Stream
// 从集合List<String> list = Arrays.asList("a", "b", "c");Stream<String> stream = list.stream();Stream<String> parallelStream = list.parallelStream(); // 并行流
// 从数组String[] array = {"a", "b", "c"};Stream<String> arrayStream = Arrays.stream(array);
// 直接创建Stream<String> ofStream = Stream.of("a", "b", "c");Stream<Double> randomStream = Stream.generate(Math::random); // 无限流Stream<Integer> evenStream = Stream.iterate(0, n -> n + 2); // 无限流
// 限制无限流的大小randomStream.limit(5).forEach(System.out::println);
// 从文件try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) { lines.forEach(System.out::println);}中间操作(返回Stream,可链式调用)
filter —— 筛选
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");List<String> filtered = names.stream() .filter(name -> name.length() > 3) .collect(Collectors.toList());// 结果: [Alice, Charlie, David]map —— 映射(转换)
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");List<Integer> nameLengths = names.stream() .map(String::length) .collect(Collectors.toList());// 结果: [5, 3, 7]flatMap —— 扁平化映射
把嵌套结构拍平——比如List<List
List<List<String>> lists = Arrays.asList( Arrays.asList("a", "b"), Arrays.asList("c", "d"), Arrays.asList("e", "f"));List<String> flattened = lists.stream() .flatMap(List::stream) .collect(Collectors.toList());// 结果: [a, b, c, d, e, f]distinct —— 去重
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 4, 5, 4);List<Integer> distinct = numbers.stream() .distinct() .collect(Collectors.toList());// 结果: [1, 2, 3, 4, 5]sorted —— 排序
List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);List<Integer> sorted = numbers.stream() .sorted() .collect(Collectors.toList());// 结果: [1, 2, 3, 4, 5]
// 自定义排序List<String> names = Arrays.asList("Alice", "Bob", "Charlie");List<String> desc = names.stream() .sorted((s1, s2) -> s2.compareTo(s1)) .collect(Collectors.toList());// 结果: [Charlie, Bob, Alice]peek —— 调试用
想在流处理过程中看一眼中间结果,用peek:
List<Integer> result = numbers.stream() .peek(n -> System.out.println("处理前: " + n)) .map(n -> n * 2) .peek(n -> System.out.println("处理后: " + n)) .collect(Collectors.toList());limit 和 skip
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> first5 = numbers.stream().limit(5).collect(Collectors.toList());// 结果: [1, 2, 3, 4, 5]
List<Integer> after5 = numbers.stream().skip(5).collect(Collectors.toList());// 结果: [6, 7, 8, 9, 10]终端操作(触发计算,返回结果)
forEach —— 遍历
names.stream().forEach(System.out::println);collect —— 收集到集合
List<String> list = names.stream() .filter(name -> name.length() > 3) .collect(Collectors.toList());
Set<String> set = names.stream() .collect(Collectors.toSet());
Map<String, Integer> map = names.stream() .collect(Collectors.toMap(name -> name, String::length));
// 指定具体的集合类型LinkedList<String> linkedList = names.stream() .collect(Collectors.toCollection(LinkedList::new));reduce —— 归约
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 求和Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);// 或指定初始值int sumWithInit = numbers.stream().reduce(0, Integer::sum);
// 求最大值Optional<Integer> max = numbers.stream().reduce(Integer::max);
// 字符串连接String joined = names.stream().collect(Collectors.joining(", "));// 结果: Alice, Bob, Charliecount —— 计数
long count = names.stream() .filter(name -> name.length() > 3) .count();匹配操作
// anyMatch:有任何一个满足就返回trueboolean hasBob = names.stream().anyMatch(name -> name.equals("Bob"));
// allMatch:所有都满足才返回trueboolean allPositive = numbers.stream().allMatch(n -> n > 0);
// noneMatch:没有满足的返回trueboolean noneNegative = numbers.stream().noneMatch(n -> n < 0);查找操作
Optional<String> first = names.stream().findFirst();Optional<String> any = names.stream().findAny(); // 并行流时更高效
// 处理OptionalString result = first.orElse("默认值");first.ifPresent(System.out::println);min / max
Optional<Integer> min = numbers.stream().min(Integer::compare);Optional<Integer> max = numbers.stream().max(Integer::compare);分组和分区
groupingBy —— 分组
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// 按名字长度分组Map<Integer, List<String>> byLength = names.stream() .collect(Collectors.groupingBy(String::length));// 结果: {3=[Bob, Eve], 5=[Alice, David], 7=[Charlie]}
// 分组后统计数量Map<Integer, Long> countByLength = names.stream() .collect(Collectors.groupingBy(String::length, Collectors.counting()));// 结果: {3=2, 5=2, 7=1}partitioningBy —— 分区(true/false)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);Map<Boolean, List<Integer>> partitioned = numbers.stream() .collect(Collectors.partitioningBy(n -> n % 2 == 0));// 结果: {false=[1, 3, 5, 7, 9], true=[2, 4, 6, 8, 10]}并行Stream
数据量大、计算密集型任务可以用并行流提升性能:
// 并行求和int sum = numbers.parallelStream() .reduce(0, Integer::sum);注意:
- 并行流不保证处理顺序
- 操作必须无副作用、线程安全
- 小数据集用并行流反而更慢(线程切换有开销)
- 默认线程数 = CPU核心数
实战贴士
- Stream不能重复使用:存到变量里想用两次,第二次调用就抛
IllegalStateException了。每次用都从数据源重新创建。 - 注意副作用:不要在Stream操作里修改外部变量,用
collect代替forEach+add。 - 选择合适的短路操作:
anyMatch、findFirst这些操作找到结果就停止遍历,比filter+count效率高。 - 并行流不是银弹:数据量小的时候串行更快,IO密集型任务也不适合并行流。
- 调试用peek:想看一眼Stream中间处理结果,用
peek(System.out::println)。
常见坑
- Stream重复使用:
stream.filter(...); stream.map(...);第二次调用会抛异常。正确做法是链式调用。 - forEach里修改外部变量:
list.stream().forEach(x -> result.add(x))在多线程下有并发问题。用collect。 - 并行流顺序问题:
parallelStream().forEach()不保证顺序,要保证顺序用forEachOrdered()。 - 无限流没limit:
Stream.generate(Math::random)不加limit会无限生成下去,内存撑爆。
分享
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时
相关文章 智能推荐
1
Java NIO详解
Java NIO的Selector模型让我第一次感受到了单线程处理万级连接的魅力。相比传统IO的阻塞读写,Channel加Buffer的组合简直是为高性能网络编程量身定做。
2
Java注解详解
Java 刚学Java时觉得注解不就是几个@符号嘛,后来用Spring Boot才发现注解能玩出这么多花样——从编译检查到运行时注入,注解远不止看起来那么简单。
3
Java集合框架详解
Java Java集合框架的源码翻来覆去看了好几遍,每次看都有新收获。从ArrayList到ConcurrentHashMap,每个集合背后都有精妙的设计思想。
4
Java IO操作详解
Java Java的IO体系虽然庞大,但掌握了装饰器模式再看InputStream和Reader的继承关系,一切都豁然开朗了。
5
Java异常处理详解
Java try-catch是Java最基础的异常处理手段,但什么时候该用受检异常、什么时候该抛RuntimeException,这中间有不少门道值得琢磨。






