Java入门到精通-31 Lambda与Stream
·
🟠 31 Lambda与Stream
📅 更新于 2026年6月 | ✍️ 原创文章,转载请注明出处
1. Lambda表达式
1.1 什么是Lambda
Lambda 是 Java 8 引入的匿名函数写法,让代码更简洁。
// 传统写法
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};
// Lambda写法
Comparator<String> comp = (a, b) -> a.length() - b.length();
// 更简洁
Comparator<String> comp = Comparator.comparingInt(String::length);
1.2 Lambda语法
(参数列表) -> { 方法体 }
| 形式 | 示例 | 说明 |
|---|---|---|
| 无参数 | () -> System.out.println("hi") | 空括号 |
| 单参数 | x -> x * 2 | 可省略括号 |
| 多参数 | (x, y) -> x + y | 必须有括号 |
| 多行体 | (x) -> { ... return x; } | 需要大括号和return |
| 单表达式 | x -> x + 1 | 自动返回,无需return |
1.3 变量作用域
public void test() {
int num = 10; // effectively final
Runnable r = () -> {
// num = 20; ❌ 不能修改
System.out.println(num); // ✅ 可以读取
};
}
规则:Lambda 只能访问 final 或 effectively final 的局部变量。
2. 函数式接口
2.1 定义
函数式接口:只有一个抽象方法的接口,用 @FunctionalInterface 注解标记。
@FunctionalInterface
public interface MyFunction<T, R> {
R apply(T t);
// 可以有默认方法
default void show() {
System.out.println("default method");
}
}
2.2 内置函数式接口
| 接口 | 方法 | 用途 | 示例 |
|---|---|---|---|
Function<T,R> | R apply(T) | 类型转换 | String::length |
Predicate<T> | boolean test(T) | 条件判断 | s -> s.isEmpty() |
Consumer<T> | void accept(T) | 消费数据 | System.out::println |
Supplier<T> | T get() | 生产数据 | () -> new ArrayList<>() |
UnaryOperator<T> | T apply(T) | 一元操作 | s -> s.toUpperCase() |
BinaryOperator<T> | T apply(T,T) | 二元操作 | Integer::sum |
BiFunction<T,U,R> | R apply(T,U) | 双参数转换 | (a,b) -> a + b |
BiPredicate<T,U> | boolean test(T,U) | 双参数判断 | (a,b) -> a > b |
2.3 带类型的函数式接口(基本类型优化)
| 接口 | 对应泛型 | 用途 |
|---|---|---|
IntFunction<R> | Function<Integer,R> | int参数 |
IntPredicate | Predicate<Integer> | int判断 |
IntConsumer | Consumer<Integer> | int消费 |
IntSupplier | Supplier<Integer> | int生产 |
LongFunction<R> | Function<Long,R> | long参数 |
DoubleFunction<R> | Function<Double,R> | double参数 |
3. 方法引用
3.1 四种形式
| 类型 | 语法 | Lambda等价 |
|---|---|---|
| 静态方法 | ClassName::staticMethod | (args) -> ClassName.staticMethod(args) |
| 实例方法 | instance::method | (args) -> instance.method(args) |
| 对象方法 | ClassName::method | (obj, args) -> obj.method(args) |
| 构造方法 | ClassName::new | (args) -> new ClassName(args) |
3.2 示例
// 静态方法引用
Function<String, Integer> parseInt = Integer::parseInt;
// 等价于: s -> Integer.parseInt(s)
// 实例方法引用
String str = "Hello";
Supplier<Integer> len = str::length;
// 等价于: () -> str.length()
// 对象方法引用(类名)
Function<String, String> upper = String::toUpperCase;
// 等价于: s -> s.toUpperCase()
// 构造方法引用
Supplier<ArrayList<String>> listFactory = ArrayList::new;
// 等价于: () -> new ArrayList<>()
Function<Integer, int[]> arrayFactory = int[]::new;
// 等价于: n -> new int[n]
4. Stream API
4.1 什么是Stream
Stream 是对集合数据的函数式操作管道,不修改原数据。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 传统写法
List<String> result = new ArrayList<>();
for (String name : names) {
if (name.length() > 3) {
result.add(name.toUpperCase());
}
}
Collections.sort(result);
// Stream写法
List<String> result = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
4.2 创建Stream
// 从集合
Stream<String> s1 = list.stream();
Stream<String> s2 = list.parallelStream();
// 从数组
Stream<Integer> s3 = Arrays.stream(new Integer[]{1, 2, 3});
// 直接创建
Stream<String> s4 = Stream.of("a", "b", "c");
// 生成
Stream<Integer> s5 = Stream.iterate(0, n -> n + 1); // 无限流
Stream<Double> s6 = Stream.generate(Math::random); // 无限流
// 基本类型流
IntStream is = IntStream.range(1, 10); // 1-9
IntStream is2 = IntStream.rangeClosed(1, 10); // 1-10
4.3 中间操作(惰性求值)
| 操作 | 方法 | 说明 |
|---|---|---|
| 过滤 | filter(Predicate) | 保留满足条件的元素 |
| 映射 | map(Function) | 转换每个元素 |
| 扁平化 | flatMap(Function) | 一对多映射并展平 |
| 去重 | distinct() | 按equals去重 |
| 排序 | sorted() | 自然排序 |
| 排序 | sorted(Comparator) | 自定义排序 |
| 截取 | limit(long) | 取前n个 |
| 跳过 | skip(long) | 跳过前n个 |
| 窥视 | peek(Consumer) | 查看每个元素(调试用) |
4.4 终端操作
| 操作 | 方法 | 返回类型 |
|---|---|---|
| 遍历 | forEach(Consumer) | void |
| 转集合 | collect(Collectors.toList()) | List |
| 转集合 | collect(Collectors.toSet()) | Set |
| 转集合 | collect(Collectors.toMap(...)) | Map |
| 数组 | toArray() | Object[] |
| 计数 | count() | long |
| 求和 | sum() / reduce(0, Integer::sum) | int |
| 最大 | max(Comparator) | Optional |
| 最小 | min(Comparator) | Optional |
| 匹配 | anyMatch(Predicate) | boolean |
| 匹配 | allMatch(Predicate) | boolean |
| 匹配 | noneMatch(Predicate) | boolean |
| 查找 | findFirst() | Optional |
| 查找 | findAny() | Optional |
| 归约 | reduce(BinaryOperator) | Optional |
5. Stream高级操作
5.1 Collectors 工具类
// 分组
Map<Integer, List<String>> grouped = list.stream()
.collect(Collectors.groupingBy(String::length));
// 分组计数
Map<Integer, Long> countByLen = list.stream()
.collect(Collectors.groupingBy(String::length, Collectors.counting()));
// 分区(true/false两组)
Map<Boolean, List<String>> partitioned = list.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 3));
// 连接字符串
String joined = list.stream()
.collect(Collectors.joining(", ", "[", "]"));
// 输出: [Alice, Bob, Charlie]
// 统计
IntSummaryStatistics stats = intStream.summaryStatistics();
System.out.println("平均: " + stats.getAverage());
System.out.println("最大: " + stats.getMax());
System.out.println("最小: " + stats.getMin());
System.out.println("总和: " + stats.getSum());
System.out.println("数量: " + stats.getCount());
5.2 flatMap 示例
// 一对多映射并展平
List<List<Integer>> nested = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5),
Arrays.asList(6, 7, 8, 9)
);
List<Integer> flat = nested.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
// 结果: [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 拆分单词
List<String> sentences = Arrays.asList("Hello World", "Java Stream");
List<String> words = sentences.stream()
.flatMap(s -> Arrays.stream(s.split(" ")))
.collect(Collectors.toList());
// 结果: [Hello, World, Java, Stream]
5.3 reduce 归约
// 求和
int sum = IntStream.rangeClosed(1, 100)
.reduce(0, Integer::sum);
// 结果: 5050
// 求最大值
int max = IntStream.of(3, 1, 4, 1, 5, 9)
.reduce(Integer::max)
.orElse(0);
// 结果: 9
// 字符串拼接
String result = Stream.of("A", "B", "C")
.reduce("", (a, b) -> a.isEmpty() ? b : a + "," + b);
// 结果: A,B,C
6. 并行流
6.1 基本使用
// 串行流
long count1 = list.stream()
.filter(s -> s.length() > 3)
.count();
// 并行流
long count2 = list.parallelStream()
.filter(s -> s.length() > 3)
.count();
6.2 注意事项
| 事项 | 说明 |
|---|---|
| 线程安全 | 操作必须是无状态的 |
| 顺序 | 并行流不保证顺序,如需顺序用 forEachOrdered |
| 数据量 | 小数据量并行反而更慢(线程开销) |
| 适用场景 | CPU密集型、大数据量 |
| 不适用 | 涉及IO、需要顺序、小数据集 |
// 错误示例:共享可变状态
List<String> result = new ArrayList<>();
list.parallelStream()
.filter(s -> s.length() > 3)
.forEach(s -> result.add(s)); // ❌ 线程不安全!
// 正确做法
List<String> result = list.parallelStream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList()); // ✅ collect是线程安全的
7. 实战案例
7.1 案例:学生信息处理
@Data
class Student {
private String name;
private int age;
private double score;
private String city;
}
public class StreamDemo {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Alice", 20, 92.5, "北京"),
new Student("Bob", 22, 78.0, "上海"),
new Student("Charlie", 21, 85.5, "北京"),
new Student("David", 23, 96.0, "广州"),
new Student("Eve", 20, 88.5, "上海")
);
// 1. 按城市分组
Map<String, List<Student>> byCity = students.stream()
.collect(Collectors.groupingBy(Student::getCity));
// 2. 各城市平均分
Map<String, Double> avgByCity = students.stream()
.collect(Collectors.groupingBy(
Student::getCity,
Collectors.averagingDouble(Student::getScore)
));
// 3. 成绩前3名
List<String> top3 = students.stream()
.sorted(Comparator.comparingDouble(Student::getScore).reversed())
.limit(3)
.map(Student::getName)
.collect(Collectors.toList());
// 4. 是否有不及格学生
boolean hasFailed = students.stream()
.anyMatch(s -> s.getScore() < 60);
// 5. 统计信息
DoubleSummaryStatistics stats = students.stream()
.mapToDouble(Student::getScore)
.summaryStatistics();
System.out.println("按城市分组: " + byCity);
System.out.println("各城市平均分: " + avgByCity);
System.out.println("前3名: " + top3);
System.out.println("有不及格: " + hasFailed);
System.out.println("最高分: " + stats.getMax());
System.out.println("平均分: " + stats.getAverage());
}
}
8. 总结
| 特性 | 说明 |
|---|---|
| Lambda | 匿名函数,简化代码 |
| 函数式接口 | 只有一个抽象方法的接口 |
| 方法引用 | 更简洁的Lambda写法 |
| Stream | 集合的函数式操作管道 |
| 惰性求值 | 中间操作不执行,终端操作才触发 |
| 并行流 | 大数据量下利用多核CPU |
💬 你觉得Lambda和Stream让代码更易读还是更难读?在什么场景下你会优先使用Stream?
📌 下一篇我们将学习 Optional与Java新API,告别空指针异常!
📚 参考资料
更多推荐
所有评论(0)