tutorialoverview
本tutorial将详细介绍Java Stream API core concepts and 实践techniques, includingStream creation, in间operation, 终端operation, parallel流etc. in 容. through本tutorial Learning, you willable tousingStream APIwriting更加简洁, high 效 Javacode, 充分利用function式programming 优势.
Stream APIoverview
Stream API is Java 8引入 features, 它providing了一种声明式 方式来processingcollectiondata. Stream API core思想 is 将collectiondata转换 for 流, 然 after through一系列 operation来processing这些data, 最 after 将processing结果收集起来.
Stream 特点
- 声明式: Stream APIusing声明式 方式processingdata, code更加简洁易读.
- function式programming: Stream API基于function式programming思想, usingLambda表达式serving asparameter.
- 链式operation: Stream APIsupport链式operation, 可以将 many 个operation连接 in 一起.
- parallelprocessing: Stream APIproviding了parallel流, 可以方便地forparallelprocessing.
- 惰性求值: Stream APIin in间operation is 惰性求值 , 只 has in 终端operation被调用时才会执行.
- 无副作用: Streamoperation不会modify原始datasources, 而 is 返回一个 new 结果.
Stream creation
in Javain, has many 种方式可以creationStream:
1. from collectioncreationStream
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class StreamCreationExample {
public static void main(String[] args) {
List names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add("David");
// from collectioncreationStream
Stream streamFromList = names.stream();
// from collectioncreationparallelStream
Stream parallelStreamFromList = names.parallelStream();
// usingStream
System.out.println("=== from collectioncreationStream ===");
streamFromList.forEach(System.out::println);
// usingparallelStream
System.out.println("\n=== from collectioncreationparallelStream ===");
parallelStreamFromList.forEach(System.out::println);
}
}
2. from arraycreationStream
import java.util.stream.Stream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.DoubleStream;
public class StreamFromArrayExample {
public static void main(String[] args) {
// from objectarraycreationStream
String[] names = {"Alice", "Bob", "Charlie"};
Stream streamFromArray = Stream.of(names);
// from basicclass型arraycreationStream
int[] numbers = {1, 2, 3, 4, 5};
IntStream intStream = IntStream.of(numbers);
// usingStream.ofmethodcreationStream
Stream streamOf = Stream.of("Alice", "Bob", "Charlie");
// usingStream
System.out.println("=== from objectarraycreationStream ===");
streamFromArray.forEach(System.out::println);
System.out.println("\n=== from basicclass型arraycreationStream ===");
intStream.forEach(System.out::println);
System.out.println("\n=== usingStream.ofmethodcreationStream ===");
streamOf.forEach(System.out::println);
}
}
3. creation空Stream
import java.util.stream.Stream;
public class EmptyStreamExample {
public static void main(String[] args) {
// creation空Stream
Stream emptyStream = Stream.empty();
// checkStream is 否 for 空
System.out.println("空Stream 元素数量: " + emptyStream.count());
}
}
4. usingStream.builder()creationStream
import java.util.stream.Stream;
public class StreambuilderExample {
public static void main(String[] args) {
// usingStream.builder()creationStream
Stream stream = Stream.builder()
.add("Alice")
.add("Bob")
.add("Charlie")
.build();
// usingStream
stream.forEach(System.out::println);
}
}
5. usingStream.generate()creation无限Stream
import java.util.stream.Stream;
public class StreamGenerateExample {
public static void main(String[] args) {
// usingStream.generate()creation无限Stream
Stream infiniteStream = Stream.generate(Math::random);
// 限制Stream big small 并using
System.out.println("=== 生成5个随机数 ===");
infiniteStream.limit(5).forEach(System.out::println);
}
}
6. usingStream.iterate()creation无限Stream
import java.util.stream.Stream;
public class StreamIterateExample {
public static void main(String[] args) {
// usingStream.iterate()creation无限Stream
Stream infiniteStream = Stream.iterate(0, n -> n + 2);
// 限制Stream big small 并using
System.out.println("=== 生成 before 10个偶数 ===");
infiniteStream.limit(10).forEach(System.out::println);
}
}
Stream operationclass型
Stream APIin operation可以分 for 三class:
1. in间operation
in间operation会返回一个 new Stream, 它们 is 惰性求值 , 只 has in 终端operation被调用时才会执行. common in间operationincluding:
- filter: filter元素
- map: 转换元素
- flatMap: 将每个元素转换 for Stream, 然 after 将所 has Streammerge for 一个Stream
- distinct: 去重
- sorted: sort
- peek: 查看元素
- limit: 限制元素数量
- skip: 跳过元素
2. 终端operation
终端operation会触发Stream processing, 并返回一个结果 or 副作用. common 终端operationincluding:
- forEach: 遍历元素
- collect: 收集元素 to collection
- count: 计算元素数量
- sum: 计算元素总 and (仅适用于数值Stream)
- average: 计算元素平均值 (仅适用于数值Stream)
- max: find最 big 元素
- min: find最 small 元素
- findFirst: find第一个元素
- findAny: find任意元素
- anyMatch: check is 否 has 元素匹配条件
- allMatch: check is 否所 has 元素都匹配条件
- noneMatch: check is 否没 has 元素匹配条件
- reduce: 归约operation
3. short 路operation
short 路operation is 指 in 满足一定条件时停止processingStream. common short 路operationincluding:
- limit: 限制元素数量
- findFirst: find第一个元素
- findAny: find任意元素
- anyMatch: check is 否 has 元素匹配条件
- allMatch: check is 否所 has 元素都匹配条件
- noneMatch: check is 否没 has 元素匹配条件
in间operation
1. filteroperation
filteroperation用于filterStreamin 元素, 只保留满足条件 元素.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class FilterExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// filter出偶数
List evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println("原始list: " + numbers);
System.out.println("偶数list: " + evenNumbers);
}
}
2. mapoperation
mapoperation用于转换Streamin 元素, 将每个元素map to 一个 new 元素.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MapExample {
public static void main(String[] args) {
List names = new ArrayList<>();
names.add("alice");
names.add("bob");
names.add("charlie");
// 将每个名字转换 for big 写
List upperCaseNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
// 将每个名字转换 for long 度
List nameLengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println("原始list: " + names);
System.out.println(" big 写list: " + upperCaseNames);
System.out.println("名字 long 度list: " + nameLengths);
}
}
3. flatMapoperation
flatMapoperation用于将每个元素转换 for Stream, 然 after 将所 has Streammerge for 一个Stream.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class FlatMapExample {
public static void main(String[] args) {
List> lists = new ArrayList<>();
List list1 = List.of(1, 2, 3);
List list2 = List.of(4, 5, 6);
List list3 = List.of(7, 8, 9);
lists.add(list1);
lists.add(list2);
lists.add(list3);
// usingflatMap将嵌套list扁平化 for 单个list
List flatList = lists.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println("原始嵌套list: " + lists);
System.out.println("扁平list: " + flatList);
// 另一个例子: 将string分割 for 字符
List words = List.of("hello", "world");
List characters = words.stream()
.flatMap(word -> word.chars().mapToObj(c -> (char) c))
.collect(Collectors.toList());
System.out.println("原始单词list: " + words);
System.out.println("字符list: " + characters);
}
}
4. sortedoperation
sortedoperation用于 for Streamin 元素forsort.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class SortedExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(8);
numbers.add(1);
numbers.add(9);
// 自然sort (升序)
List sortedAsc = numbers.stream()
.sorted()
.collect(Collectors.toList());
// 自定义sort (降序)
List sortedDesc = numbers.stream()
.sorted((a, b) -> b - a)
.collect(Collectors.toList());
System.out.println("原始list: " + numbers);
System.out.println("升序sort: " + sortedAsc);
System.out.println("降序sort: " + sortedDesc);
// for stringsort
List names = List.of("Alice", "Bob", "Charlie", "David");
List sortedNames = names.stream()
.sorted()
.collect(Collectors.toList());
System.out.println("\n原始名字list: " + names);
System.out.println("sort after 名字list: " + sortedNames);
}
}
5. distinctoperation
distinctoperation用于去除Streamin 重复元素.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class DistinctExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(2);
numbers.add(3);
numbers.add(3);
numbers.add(3);
// 去重
List distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("原始list: " + numbers);
System.out.println("去重 after list: " + distinctNumbers);
}
}
6. limit and skipoperation
limitoperation用于限制Streamin 元素数量, skipoperation用于跳过Streamin 元素.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class LimitSkipExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// 限制元素数量 for 5
List limitedNumbers = numbers.stream()
.limit(5)
.collect(Collectors.toList());
// 跳过 before 5个元素
List skippedNumbers = numbers.stream()
.skip(5)
.collect(Collectors.toList());
// 组合usinglimit and skip, 获取第6 to 第8个元素
List rangeNumbers = numbers.stream()
.skip(5)
.limit(3)
.collect(Collectors.toList());
System.out.println("原始list: " + numbers);
System.out.println("限制 after list: " + limitedNumbers);
System.out.println("跳过 before 5个元素 after list: " + skippedNumbers);
System.out.println("第6 to 第8个元素: " + rangeNumbers);
}
}
终端operation
1. forEachoperation
forEachoperation用于遍历Streamin 元素.
import java.util.ArrayList;
import java.util.List;
public class ForEachExample {
public static void main(String[] args) {
List names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
// usingforEach遍历元素
System.out.println("=== usingforEach遍历元素 ===");
names.stream().forEach(System.out::println);
// usingforEachOrdered保持元素顺序 (适用于parallelStream)
System.out.println("\n=== usingforEachOrdered遍历元素 ===");
names.stream().parallel().forEachOrdered(System.out::println);
}
}
2. collectoperation
collectoperation用于将Streamin 元素收集 to collectionin.
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class CollectExample {
public static void main(String[] args) {
List names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add("Bob");
// 收集 to List
List collectedList = names.stream()
.collect(Collectors.toList());
// 收集 to Set (自动去重)
Set collectedSet = names.stream()
.collect(Collectors.toSet());
// 收集 to specificclass型 collection
ArrayList collectedArrayList = names.stream()
.collect(Collectors.toCollection(ArrayList::new));
// 连接string
String joinedNames = names.stream()
.collect(Collectors.joining(", "));
System.out.println("原始list: " + names);
System.out.println("收集 to List: " + collectedList);
System.out.println("收集 to Set: " + collectedSet);
System.out.println("收集 to ArrayList: " + collectedArrayList);
System.out.println("连接string: " + joinedNames);
}
}
3. countoperation
countoperation用于计算Streamin 元素数量.
import java.util.ArrayList;
import java.util.List;
public class CountExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// 计算元素数量
long count = numbers.stream().count();
// 计算偶数数量
long evenCount = numbers.stream()
.filter(n -> n % 2 == 0)
.count();
System.out.println("元素数量: " + count);
System.out.println("偶数数量: " + evenCount);
}
}
4. reduceoperation
reduceoperation用于将Streamin 元素归约 for 单个值.
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ReduceExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
numbers.add(i);
}
// 计算总 and
Optional sumOptional = numbers.stream()
.reduce((a, b) -> a + b);
int sum = sumOptional.orElse(0);
// 计算总 and (带初始值)
int sumWithInitial = numbers.stream()
.reduce(0, (a, b) -> a + b);
// 计算最 big 值
Optional maxOptional = numbers.stream()
.reduce((a, b) -> a > b ? a : b);
int max = maxOptional.orElse(Integer.MIN_VALUE);
// 连接string
List names = List.of("Alice", "Bob", "Charlie");
String concatenatedNames = names.stream()
.reduce("", (a, b) -> a + ", " + b);
// 去除开头 ", "
concatenatedNames = concatenatedNames.substring(2);
System.out.println("numberlist: " + numbers);
System.out.println("总 and : " + sum);
System.out.println("总 and (带初始值) : " + sumWithInitial);
System.out.println("最 big 值: " + max);
System.out.println("\n名字list: " + names);
System.out.println("连接 after : " + concatenatedNames);
}
}
5. findoperation
findFirstoperation用于findStreamin 第一个元素, findAnyoperation用于findStreamin 任意元素.
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class FindExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// find第一个元素
Optional first = numbers.stream().findFirst();
System.out.println("第一个元素: " + first.orElse(-1));
// find第一个偶数
Optional firstEven = numbers.stream()
.filter(n -> n % 2 == 0)
.findFirst();
System.out.println("第一个偶数: " + firstEven.orElse(-1));
// find任意元素 ( in parallelStreamin更 high 效)
Optional any = numbers.stream().parallel().findAny();
System.out.println("任意元素: " + any.orElse(-1));
}
}
6. matchoperation
matchoperation用于checkStreamin 元素 is 否满足specific条件.
import java.util.ArrayList;
import java.util.List;
public class MatchExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// check is 否 has 元素 big 于5
boolean anyGreaterThan5 = numbers.stream()
.anyMatch(n -> n > 5);
System.out.println(" is 否 has 元素 big 于5: " + anyGreaterThan5);
// check is 否所 has 元素都 big 于0
boolean allGreaterThan0 = numbers.stream()
.allMatch(n -> n > 0);
System.out.println(" is 否所 has 元素都 big 于0: " + allGreaterThan0);
// check is 否没 has 元素 big 于10
boolean noneGreaterThan10 = numbers.stream()
.noneMatch(n -> n > 10);
System.out.println(" is 否没 has 元素 big 于10: " + noneGreaterThan10);
}
}
parallel流
parallel流 is Stream APIproviding 一种parallelprocessingdata 方式, 它可以充分利用 many 核processing器 优势, improvingprocessing big 量data efficiency.
creationparallel流
import java.util.ArrayList;
import java.util.List;
public class ParallelStreamExample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
for (int i = 1; i <= 1000000; i++) {
numbers.add(i);
}
// 顺序流
long startTime = System.currentTimeMillis();
long sumSequential = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToLong(Integer::longValue)
.sum();
long endTime = System.currentTimeMillis();
System.out.println("顺序流processing时间: " + (endTime - startTime) + " 毫秒");
System.out.println("偶数总 and : " + sumSequential);
// parallel流
startTime = System.currentTimeMillis();
long sumParallel = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.mapToLong(Integer::longValue)
.sum();
endTime = System.currentTimeMillis();
System.out.println("parallel流processing时间: " + (endTime - startTime) + " 毫秒");
System.out.println("偶数总 and : " + sumParallel);
// 将顺序流转换 for parallel流
startTime = System.currentTimeMillis();
long sumParallelConverted = numbers.stream()
.parallel() // 转换 for parallel流
.filter(n -> n % 2 == 0)
.mapToLong(Integer::longValue)
.sum();
endTime = System.currentTimeMillis();
System.out.println("转换 for parallel流processing时间: " + (endTime - startTime) + " 毫秒");
System.out.println("偶数总 and : " + sumParallelConverted);
}
}
parallel流 Notes
- threadsecurity: parallel流 in processing过程in会using many 个thread, 因此需要确保operation is threadsecurity .
- 共享status: 应避免 in parallel流inmodify共享status, 否则可能会导致data竞争.
- performance考量: parallel流并不总 is 比顺序流 fast , for 于 small data集 or 计算密集型operation, 顺序流可能更 fast .
- sort: parallel流 sortoperation可能比顺序流更 high 效, 因 for 它可以利用parallelsortalgorithms.
- forEachOrdered: in parallel流inusingforEachOrdered可以保持元素 原始顺序, 但会牺牲一些parallelperformance.
实践case
Stream APIimplementation单词statistics
本caseusingStream APIimplementation一个 simple 单词statisticsfunctions, statistics文本in每个单词 出现次数.
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
public class WordCountExample {
public static void main(String[] args) {
String text = "Hello world hello Java Java stream stream API API API";
// 分割文本 for 单词, 转换 for small 写, filter空string, statistics每个单词 出现次数
Map wordCount = Arrays.stream(text.split("\\s+"))
.map(String::toLowerCase)
.filter(word -> !word.isEmpty())
.collect(Collectors.groupingBy(word -> word, Collectors.counting()));
// 打印单词statistics结果
System.out.println("文本: " + text);
System.out.println("单词statistics结果:");
wordCount.forEach((word, count) -> {
System.out.println(word + ": " + count);
});
// 按出现次数sort
System.out.println("\n按出现次数sort:");
wordCount.entrySet().stream()
.sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()))
.forEach(entry -> {
System.out.println(entry.getKey() + ": " + entry.getValue());
});
// find出现次数最 many 单词
System.out.println("\n出现次数最 many 单词:");
wordCount.entrySet().stream()
.max((entry1, entry2) -> entry1.getValue().compareTo(entry2.getValue()))
.ifPresent(entry -> {
System.out.println(entry.getKey() + ": " + entry.getValue());
});
}
}
互动练习
练习1: StreamBasicsoperation
creation一个List
- filter出能被3整除 number
- 将每个number乘以2
- sort (降序)
- 收集 to 一个 new Listin
- 打印结果
练习2: Streamadvancedoperation
creation一个List
- filter出 long 度 big 于3 string
- 将每个string转换 for big 写
- 去重
- 收集 to 一个Setin
- 打印结果
练习3: parallel流
creation一个package含1000000个元素 List
练习4: Stream API and Lambda表达式
creation一个Personclass, package含name and ageproperty. 然 after creation一个List
- filter出年龄 big 于18 人
- 按年龄sort
- 提取每个人 名字
- 收集 to 一个List
in - 打印结果
推荐tutorial
LearningJavalanguage basic语法 and core concepts
MasterJava 面向objectprogramming思想 and 实践
LearningJavacollectionframework using and 原理
MasterJava fileoperation and IO流processing
LearningJava many threadprogramming and concurrentprocessing
MasterJavaexceptionprocessingmechanism and best practices
MasterJava泛型programming core concepts and application
LearningJava Lambda表达式 and function式programming
LearningJavaadvancedcollectionconcepts and 实践techniques
浏览所 has Javatutorial in 容