JDK8 Lambda表达式实战指南
目录
- 一、Lambda表达式概述
- 二、函数式接口详解
- 三、Lambda语法与使用
- 四、方法引用
- 五、Stream API实战
- 六、Optional避免空指针
- 七、Lambda在Spring中的应用
- 八、Lambda性能优化
- 九、实战案例
- 十、最佳实践
- 总结
一、Lambda表达式概述
1.1 什么是Lambda表达式
Lambda表达式是JDK 8引入的一种新特性,它允许我们将函数作为方法参数传递,或者将代码作为数据处理。Lambda表达式本质上是一个匿名函数,可以使代码更加简洁和易读。
传统Java编程模型:
+------------------+
| 面向对象编程 | 一切都是对象
+------------------+
↓
+------------------+
| 匿名内部类 | 冗长的语法
+------------------+
JDK 8 新特性:
+------------------+
| Lambda表达式 | 函数式编程
+------------------+
↓
+------------------+
| 简洁、优雅 | 代码即数据
+------------------+
1.2 为什么需要Lambda
传统方式的痛点:
// 传统方式:使用匿名内部类
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
Lambda方式:
// Lambda方式:简洁明了
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
// 甚至可以更简洁
Collections.sort(names, String::compareTo);
1.3 Lambda的优势
| 优势 | 说明 | 示例场景 |
|---|---|---|
| 简洁性 | 减少样板代码 | 集合遍历、排序 |
| 可读性 | 代码意图更清晰 | Stream流式操作 |
| 函数式编程 | 支持函数式编程范式 | 高阶函数、闭包 |
| 并行处理 | 轻松实现并行计算 | 大数据处理 |
| 延迟执行 | 按需计算,提高性能 | Stream惰性求值 |
二、函数式接口详解
2.1 什么是函数式接口
函数式接口(Functional Interface)是只有一个抽象方法的接口,可以使用@FunctionalInterface注解标记。
package com.example.lambda;
/**
* 函数式接口示例
*/
@FunctionalInterface
interface Calculator {
// 只有一个抽象方法
int calculate(int a, int b);
// 可以有default方法
default void print() {
System.out.println("This is a calculator");
}
// 可以有static方法
static void info() {
System.out.println("Calculator interface");
}
}
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
// Lambda表达式实现函数式接口
Calculator add = (a, b) -> a + b;
Calculator subtract = (a, b) -> a - b;
Calculator multiply = (a, b) -> a * b;
Calculator divide = (a, b) -> a / b;
System.out.println("10 + 5 = " + add.calculate(10, 5));
System.out.println("10 - 5 = " + subtract.calculate(10, 5));
System.out.println("10 * 5 = " + multiply.calculate(10, 5));
System.out.println("10 / 5 = " + divide.calculate(10, 5));
}
}
2.2 JDK内置函数式接口
JDK 8在java.util.function包中提供了大量内置函数式接口:
package com.example.lambda;
import java.util.function.*;
/**
* JDK内置函数式接口演示
*/
public class BuiltInFunctionalInterface {
public static void main(String[] args) {
// 1. Predicate<T> - 断言型接口,接受参数返回boolean
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println("4是偶数: " + isEven.test(4));
System.out.println("5是偶数: " + isEven.test(5));
// 2. Consumer<T> - 消费型接口,接受参数无返回值
Consumer<String> printer = str -> System.out.println("打印: " + str);
printer.accept("Hello Lambda");
// 3. Function<T, R> - 函数型接口,接受参数返回结果
Function<String, Integer> strLength = str -> str.length();
System.out.println("字符串长度: " + strLength.apply("Hello"));
// 4. Supplier<T> - 供给型接口,无参数返回结果
Supplier<Double> randomSupplier = () -> Math.random();
System.out.println("随机数: " + randomSupplier.get());
// 5. BiFunction<T, U, R> - 双参数函数型接口
BiFunction<Integer, Integer, Integer> power = (base, exp) ->
(int) Math.pow(base, exp);
System.out.println("2^3 = " + power.apply(2, 3));
// 6. UnaryOperator<T> - 一元操作符(Function<T,T>的特例)
UnaryOperator<Integer> square = x -> x * x;
System.out.println("5的平方: " + square.apply(5));
// 7. BinaryOperator<T> - 二元操作符(BiFunction<T,T,T>的特例)
BinaryOperator<Integer> max = (a, b) -> a > b ? a : b;
System.out.println("最大值: " + max.apply(10, 20));
}
}
2.3 函数式接口分类
+---------------------------+-------------------+------------------+
| 接口类型 | 方法签名 | 用途 |
+---------------------------+-------------------+------------------+
| Predicate<T> | T -> boolean | 条件判断 |
| Consumer<T> | T -> void | 消费数据 |
| Function<T,R> | T -> R | 类型转换 |
| Supplier<T> | () -> T | 生产数据 |
| BiFunction<T,U,R> | (T,U) -> R | 双参数转换 |
| UnaryOperator<T> | T -> T | 一元操作 |
| BinaryOperator<T> | (T,T) -> T | 二元操作 |
+---------------------------+-------------------+------------------+
基本类型特化版本:
IntPredicate, LongPredicate, DoublePredicate
IntConsumer, LongConsumer, DoubleConsumer
IntFunction, LongFunction, DoubleFunction
IntSupplier, LongSupplier, DoubleSupplier
IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator
IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator
三、Lambda语法与使用
3.1 Lambda表达式语法
package com.example.lambda;
import java.util.function.Function;
/**
* Lambda表达式语法详解
*/
public class LambdaSyntaxDemo {
public static void main(String[] args) {
// === 语法格式1: 无参数,无返回值 ===
Runnable r1 = () -> System.out.println("Hello Lambda");
r1.run();
// === 语法格式2: 有一个参数,无返回值 ===
// 单个参数可以省略小括号
java.util.function.Consumer<String> con1 = (str) -> System.out.println(str);
java.util.function.Consumer<String> con2 = str -> System.out.println(str);
con2.accept("Single parameter");
// === 语法格式3: 有多个参数,无返回值 ===
java.util.function.BiConsumer<String, Integer> biCon =
(name, age) -> System.out.println(name + " is " + age + " years old");
biCon.accept("Alice", 25);
// === 语法格式4: 有参数,有返回值 ===
// 单条语句可以省略大括号和return
java.util.function.Function<Integer, Integer> func1 = (x) -> x * x;
java.util.function.Function<Integer, Integer> func2 = x -> x * x;
System.out.println("5的平方: " + func2.apply(5));
// === 语法格式5: 多条语句,需要大括号和return ===
Function<Integer, Integer> factorial = n -> {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
};
System.out.println("5的阶乘: " + factorial.apply(5));
// === 语法格式6: Lambda体只有一条语句,返回值可以省略return ===
java.util.Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
// === 语法格式7: Lambda参数类型可以省略(类型推断) ===
java.util.Comparator<String> com2 = (String s1, String s2) -> s1.compareTo(s2);
java.util.Comparator<String> com3 = (s1, s2) -> s1.compareTo(s2); // 类型推断
// === 完整示例对比 ===
demonstrateSyntaxEvolution();
}
/**
* 演示Lambda语法演进
*/
private static void demonstrateSyntaxEvolution() {
System.out.println("\n=== Lambda语法演进 ===");
// 1. 完整写法
java.util.function.BinaryOperator<Integer> op1 =
(Integer a, Integer b) -> { return a + b; };
// 2. 省略参数类型
java.util.function.BinaryOperator<Integer> op2 =
(a, b) -> { return a + b; };
// 3. 省略大括号和return
java.util.function.BinaryOperator<Integer> op3 = (a, b) -> a + b;
System.out.println("10 + 20 = " + op3.apply(10, 20));
}
}
3.2 变量捕获
package com.example.lambda;
/**
* Lambda表达式变量捕获
*/
public class VariableCaptureDemo {
// 实例变量
private String instanceVar = "Instance Variable";
// 静态变量
private static String staticVar = "Static Variable";
public static void main(String[] args) {
new VariableCaptureDemo().test();
}
public void test() {
// 局部变量(effectively final)
String localVar = "Local Variable";
// localVar = "Modified"; // 取消注释会导致编译错误
int localNum = 100;
// Lambda可以访问:
// 1. 静态变量
// 2. 实例变量
// 3. effectively final的局部变量
Runnable r = () -> {
System.out.println("静态变量: " + staticVar);
System.out.println("实例变量: " + instanceVar);
System.out.println("局部变量: " + localVar);
System.out.println("局部数字: " + localNum);
// 可以修改实例变量和静态变量
// staticVar = "Modified Static"; // 可以
// instanceVar = "Modified Instance"; // 可以
// 不能修改局部变量
// localVar = "Modified Local"; // 编译错误
// localNum = 200; // 编译错误
};
r.run();
// effectively final示例
demonstrateEffectivelyFinal();
}
/**
* effectively final演示
*/
private void demonstrateEffectivelyFinal() {
System.out.println("\n=== Effectively Final ===");
// 虽然没有final关键字,但实际上是final的
int value = 10;
// Lambda使用了value,所以value变成effectively final
Runnable r = () -> System.out.println("Value: " + value);
// value = 20; // 这行代码会导致编译错误
r.run();
}
}
四、方法引用
4.1 方法引用语法
方法引用是Lambda表达式的简化写法,使用::操作符。
package com.example.lambda;
import java.util.*;
import java.util.function.*;
/**
* 方法引用详解
*/
public class MethodReferenceDemo {
public static void main(String[] args) {
// === 1. 静态方法引用: 类名::静态方法名 ===
// Lambda写法
Function<Double, Double> sqrt1 = x -> Math.sqrt(x);
// 方法引用写法
Function<Double, Double> sqrt2 = Math::sqrt;
System.out.println("√16 = " + sqrt2.apply(16.0));
// 静态方法引用示例
BiFunction<Integer, Integer, Integer> max = Math::max;
System.out.println("Max(10, 20) = " + max.apply(10, 20));
// === 2. 实例方法引用: 对象::实例方法名 ===
String str = "Hello Lambda";
// Lambda写法
Supplier<Integer> len1 = () -> str.length();
// 方法引用写法
Supplier<Integer> len2 = str::length;
System.out.println("字符串长度: " + len2.get());
// 实例方法引用示例
Consumer<String> printer = System.out::println;
printer.accept("Method Reference");
// === 3. 类名::实例方法名 ===
// 特殊情况:第一个参数作为方法的调用者
// Lambda写法
BiFunction<String, String, Integer> compare1 =
(s1, s2) -> s1.compareTo(s2);
// 方法引用写法
BiFunction<String, String, Integer> compare2 = String::compareTo;
System.out.println("字符串比较: " + compare2.apply("abc", "xyz"));
// === 4. 构造器引用: 类名::new ===
// Lambda写法
Supplier<List<String>> list1 = () -> new ArrayList<>();
// 构造器引用写法
Supplier<List<String>> list2 = ArrayList::new;
List<String> myList = list2.get();
myList.add("Item1");
System.out.println("列表: " + myList);
// 带参数的构造器引用
Function<Integer, int[]> arrayCreator = int[]::new;
int[] arr = arrayCreator.apply(5);
System.out.println("数组长度: " + arr.length);
// 演示完整示例
demonstrateMethodReference();
}
/**
* 方法引用完整示例
*/
private static void demonstrateMethodReference() {
System.out.println("\n=== 方法引用实战 ===");
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 1. 使用方法引用遍历
System.out.println("遍历列表:");
names.forEach(System.out::println);
// 2. 使用方法引用排序
names.sort(String::compareTo);
System.out.println("排序后: " + names);
// 3. 使用方法引用转换
List<Integer> lengths = new ArrayList<>();
names.forEach(name -> lengths.add(name.length()));
System.out.println("名字长度: " + lengths);
}
}
/**
* 用户类 - 演示构造器引用
*/
class User {
private String name;
private int age;
public User() {
this.name = "Unknown";
this.age = 0;
}
public User(String name) {
this.name = name;
this.age = 0;
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
}
/**
* 构造器引用演示
*/
class ConstructorReferenceDemo {
public static void main(String[] args) {
// 无参构造器引用
Supplier<User> userSupplier = User::new;
User user1 = userSupplier.get();
System.out.println("无参构造: " + user1);
// 一参数构造器引用
Function<String, User> userFactory1 = User::new;
User user2 = userFactory1.apply("Alice");
System.out.println("一参数构造: " + user2);
// 二参数构造器引用
BiFunction<String, Integer, User> userFactory2 = User::new;
User user3 = userFactory2.apply("Bob", 25);
System.out.println("二参数构造: " + user3);
}
}
五、Stream API实战
5.1 Stream基础操作
package com.example.lambda.stream;
import java.util.*;
import java.util.stream.*;
/**
* Stream API基础操作
*/
public class StreamBasicDemo {
public static void main(String[] args) {
// === 1. 创建Stream ===
// 从集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();
// 从数组创建
String[] array = {"x", "y", "z"};
Stream<String> stream2 = Arrays.stream(array);
// 使用Stream.of()
Stream<String> stream3 = Stream.of("1", "2", "3");
// 无限流
Stream<Integer> stream4 = Stream.iterate(0, n -> n + 2).limit(10);
Stream<Double> stream5 = Stream.generate(Math::random).limit(5);
// === 2. 中间操作(返回Stream,可以链式调用) ===
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// filter - 过滤
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println("偶数: " + evenNumbers);
// map - 映射转换
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println("平方: " + squares);
// flatMap - 扁平化映射
List<String> words = Arrays.asList("Hello", "World");
List<String> chars = words.stream()
.flatMap(word -> Arrays.stream(word.split("")))
.collect(Collectors.toList());
System.out.println("字符: " + chars);
// distinct - 去重
List<Integer> distinctNums = Arrays.asList(1, 2, 2, 3, 3, 4)
.stream()
.distinct()
.collect(Collectors.toList());
System.out.println("去重: " + distinctNums);
// sorted - 排序
List<Integer> sorted = numbers.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
System.out.println("降序: " + sorted);
// limit - 限制数量
List<Integer> limited = numbers.stream()
.limit(5)
.collect(Collectors.toList());
System.out.println("前5个: " + limited);
// skip - 跳过
List<Integer> skipped = numbers.stream()
.skip(5)
.collect(Collectors.toList());
System.out.println("跳过5个: " + skipped);
// peek - 查看(用于调试)
List<Integer> peeked = numbers.stream()
.peek(n -> System.out.println("处理: " + n))
.filter(n -> n > 5)
.collect(Collectors.toList());
// === 3. 终端操作(触发流的执行) ===
// forEach - 遍历
System.out.println("\nforEach遍历:");
numbers.stream().forEach(System.out::println);
// count - 计数
long count = numbers.stream().filter(n -> n > 5).count();
System.out.println("大于5的数量: " + count);
// max/min - 最大值/最小值
Optional<Integer> max = numbers.stream().max(Integer::compareTo);
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
System.out.println("最大值: " + max.orElse(0));
System.out.println("最小值: " + min.orElse(0));
// findFirst/findAny - 查找
Optional<Integer> first = numbers.stream().filter(n -> n > 5).findFirst();
System.out.println("第一个大于5的数: " + first.orElse(0));
// anyMatch/allMatch/noneMatch - 匹配
boolean anyMatch = numbers.stream().anyMatch(n -> n > 5);
boolean allMatch = numbers.stream().allMatch(n -> n > 0);
boolean noneMatch = numbers.stream().noneMatch(n -> n < 0);
System.out.println("存在大于5: " + anyMatch);
System.out.println("全部大于0: " + allMatch);
System.out.println("不存在小于0: " + noneMatch);
// reduce - 归约
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
System.out.println("求和: " + sum.orElse(0));
Integer sum2 = numbers.stream().reduce(0, (a, b) -> a + b);
System.out.println("求和(带初始值): " + sum2);
// collect - 收集
String joined = numbers.stream()
.map(String::valueOf)
.collect(Collectors.joining(", "));
System.out.println("拼接: " + joined);
}
}
5.2 Stream高级应用
package com.example.lambda.stream;
import java.util.*;
import java.util.stream.*;
/**
* Stream高级应用 - 模拟电商场景
*/
public class StreamAdvancedDemo {
public static void main(String[] args) {
// 模拟商品数据
List<Product> products = Arrays.asList(
new Product(1L, "iPhone 15", "电子产品", 5999.0, 100),
new Product(2L, "MacBook Pro", "电子产品", 12999.0, 50),
new Product(3L, "AirPods", "电子产品", 1299.0, 200),
new Product(4L, "Nike鞋", "服装", 899.0, 150),
new Product(5L, "Adidas T恤", "服装", 299.0, 300),
new Product(6L, "Java编程思想", "图书", 99.0, 500),
new Product(7L, "Effective Java", "图书", 79.0, 400)
);
System.out.println("=== 1. 基础查询 ===");
// 查找价格大于1000的商品
List<Product> expensiveProducts = products.stream()
.filter(p -> p.getPrice() > 1000)
.collect(Collectors.toList());
System.out.println("高价商品: " + expensiveProducts.size() + "个");
expensiveProducts.forEach(System.out::println);
System.out.println("\n=== 2. 分组统计 ===");
// 按类别分组
Map<String, List<Product>> groupByCategory = products.stream()
.collect(Collectors.groupingBy(Product::getCategory));
System.out.println("按类别分组:");
groupByCategory.forEach((category, list) -> {
System.out.println(category + ": " + list.size() + "个");
});
// 按价格区间分组
Map<String, List<Product>> groupByPriceRange = products.stream()
.collect(Collectors.groupingBy(p -> {
if (p.getPrice() < 100) return "低价";
else if (p.getPrice() < 1000) return "中价";
else return "高价";
}));
System.out.println("\n按价格分组:");
groupByPriceRange.forEach((range, list) -> {
System.out.println(range + ": " + list.size() + "个");
});
System.out.println("\n=== 3. 聚合统计 ===");
// 统计每个类别的总库存
Map<String, Integer> stockByCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.summingInt(Product::getStock)
));
System.out.println("各类别库存:");
stockByCategory.forEach((category, stock) -> {
System.out.println(category + ": " + stock);
});
// 统计每个类别的平均价格
Map<String, Double> avgPriceByCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.averagingDouble(Product::getPrice)
));
System.out.println("\n各类别平均价格:");
avgPriceByCategory.forEach((category, avg) -> {
System.out.printf("%s: %.2f元\n", category, avg);
});
// 使用summaryStatistics获取统计信息
DoubleSummaryStatistics priceStats = products.stream()
.collect(Collectors.summarizingDouble(Product::getPrice));
System.out.println("\n价格统计:");
System.out.println("总数: " + priceStats.getCount());
System.out.printf("总和: %.2f\n", priceStats.getSum());
System.out.printf("平均值: %.2f\n", priceStats.getAverage());
System.out.printf("最小值: %.2f\n", priceStats.getMin());
System.out.printf("最大值: %.2f\n", priceStats.getMax());
System.out.println("\n=== 4. 排序与Top N ===");
// 价格最高的3个商品
List<Product> top3Expensive = products.stream()
.sorted(Comparator.comparing(Product::getPrice).reversed())
.limit(3)
.collect(Collectors.toList());
System.out.println("价格Top 3:");
top3Expensive.forEach(p -> System.out.println(p.getName() + ": " + p.getPrice()));
// 库存最多的商品
Optional<Product> maxStock = products.stream()
.max(Comparator.comparing(Product::getStock));
maxStock.ifPresent(p -> System.out.println("\n库存最多: " + p));
System.out.println("\n=== 5. 复杂查询 ===");
// 查找电子产品中价格第二高的商品
Optional<Product> secondExpensive = products.stream()
.filter(p -> "电子产品".equals(p.getCategory()))
.sorted(Comparator.comparing(Product::getPrice).reversed())
.skip(1)
.findFirst();
secondExpensive.ifPresent(p ->
System.out.println("电子产品价格第二: " + p.getName() + " - " + p.getPrice()));
// 计算总库存价值
double totalValue = products.stream()
.mapToDouble(p -> p.getPrice() * p.getStock())
.sum();
System.out.printf("\n总库存价值: %.2f元\n", totalValue);
// 使用partitioningBy进行分区(二分)
Map<Boolean, List<Product>> partitioned = products.stream()
.collect(Collectors.partitioningBy(p -> p.getPrice() > 1000));
System.out.println("\n分区(>1000):");
System.out.println("高价: " + partitioned.get(true).size() + "个");
System.out.println("低价: " + partitioned.get(false).size() + "个");
}
}
/**
* 商品实体类
*/
class Product {
private Long id;
private String name;
private String category;
private Double price;
private Integer stock;
public Product(Long id, String name, String category, Double price, Integer stock) {
this.id = id;
this.name = name;
this.category = category;
this.price = price;
this.stock = stock;
}
// Getters
public Long getId() { return id; }
public String getName() { return name; }
public String getCategory() { return category; }
public Double getPrice() { return price; }
public Integer getStock() { return stock; }
@Override
public String toString() {
return String.format("Product{name='%s', category='%s', price=%.2f, stock=%d}",
name, category, price, stock);
}
}
5.3 并行Stream
package com.example.lambda.stream;
import java.util.*;
import java.util.stream.*;
/**
* 并行Stream演示
*/
public class ParallelStreamDemo {
public static void main(String[] args) {
int size = 10_000_000;
List<Integer> numbers = IntStream.rangeClosed(1, size)
.boxed()
.collect(Collectors.toList());
// === 串行Stream ===
long start1 = System.currentTimeMillis();
long sum1 = numbers.stream()
.mapToLong(Integer::longValue)
.sum();
long end1 = System.currentTimeMillis();
System.out.println("串行Stream求和: " + sum1);
System.out.println("耗时: " + (end1 - start1) + "ms");
// === 并行Stream ===
long start2 = System.currentTimeMillis();
long sum2 = numbers.parallelStream()
.mapToLong(Integer::longValue)
.sum();
long end2 = System.currentTimeMillis();
System.out.println("\n并行Stream求和: " + sum2);
System.out.println("耗时: " + (end2 - start2) + "ms");
// === 什么时候使用并行Stream ===
System.out.println("\n=== 并行Stream使用建议 ===");
System.out.println("✓ 适合使用并行Stream:");
System.out.println(" 1. 数据量大(通常>10000)");
System.out.println(" 2. 操作是CPU密集型");
System.out.println(" 3. 操作无状态且相互独立");
System.out.println("\n✗ 不适合使用并行Stream:");
System.out.println(" 1. 数据量小");
System.out.println(" 2. 操作是IO密集型");
System.out.println(" 3. 操作有依赖关系");
System.out.println(" 4. 需要保持顺序");
}
}
六、Optional避免空指针
6.1 Optional基础
package com.example.lambda.optional;
import java.util.*;
/**
* Optional使用详解
*/
public class OptionalDemo {
public static void main(String[] args) {
// === 1. 创建Optional ===
// 创建空Optional
Optional<String> empty = Optional.empty();
// 创建非空Optional(值不能为null)
Optional<String> notEmpty = Optional.of("Hello");
// 创建可能为空的Optional(值可以为null)
Optional<String> nullable = Optional.ofNullable(null);
Optional<String> nullable2 = Optional.ofNullable("World");
// === 2. 判断是否有值 ===
System.out.println("empty.isPresent(): " + empty.isPresent());
System.out.println("notEmpty.isPresent(): " + notEmpty.isPresent());
// Java 11+
// System.out.println("empty.isEmpty(): " + empty.isEmpty());
// === 3. 获取值 ===
// get() - 如果为空会抛出NoSuchElementException
try {
String value = notEmpty.get();
System.out.println("Value: " + value);
// String emptyValue = empty.get(); // 抛出异常
} catch (NoSuchElementException e) {
System.out.println("获取空Optional会抛异常");
}
// orElse() - 为空返回默认值
String value1 = empty.orElse("Default");
System.out.println("orElse: " + value1);
// orElseGet() - 为空执行Supplier
String value2 = empty.orElseGet(() -> "Generated Default");
System.out.println("orElseGet: " + value2);
// orElseThrow() - 为空抛出异常
try {
String value3 = empty.orElseThrow(() ->
new IllegalArgumentException("值为空"));
} catch (IllegalArgumentException e) {
System.out.println("orElseThrow: " + e.getMessage());
}
// === 4. 条件执行 ===
// ifPresent() - 有值时执行
notEmpty.ifPresent(v -> System.out.println("ifPresent: " + v));
empty.ifPresent(v -> System.out.println("不会执行"));
// === 5. 转换与过滤 ===
// map() - 转换值
Optional<Integer> length = notEmpty.map(String::length);
System.out.println("字符串长度: " + length.orElse(0));
// flatMap() - 扁平化转换
Optional<String> upper = notEmpty.flatMap(s ->
Optional.of(s.toUpperCase()));
System.out.println("转大写: " + upper.orElse(""));
// filter() - 过滤
Optional<String> filtered = notEmpty.filter(s -> s.length() > 3);
System.out.println("过滤后: " + filtered.orElse("太短了"));
// === 6. 实战示例 ===
demonstrateRealWorld();
}
/**
* 实战示例:用户信息查询
*/
private static void demonstrateRealWorld() {
System.out.println("\n=== Optional实战示例 ===");
// 传统写法
User user1 = findUserById(1L);
if (user1 != null) {
String email = user1.getEmail();
if (email != null) {
System.out.println("Email: " + email.toUpperCase());
}
}
// Optional写法
findUserByIdOptional(1L)
.map(User::getEmail)
.map(String::toUpperCase)
.ifPresent(email -> System.out.println("Email: " + email));
// 链式调用
String emailOrDefault = findUserByIdOptional(2L)
.map(User::getEmail)
.filter(email -> email.contains("@"))
.orElse("no-email@example.com");
System.out.println("邮箱或默认值: " + emailOrDefault);
}
// 传统方法
private static User findUserById(Long id) {
if (id == 1L) {
return new User(1L, "Alice", "alice@example.com");
}
return null;
}
// Optional方法
private static Optional<User> findUserByIdOptional(Long id) {
if (id == 1L) {
return Optional.of(new User(1L, "Alice", "alice@example.com"));
}
return Optional.empty();
}
}
/**
* 用户类
*/
class User {
private Long id;
private String name;
private String email;
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public Long getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
七、Lambda在Spring中的应用
7.1 Spring事件处理
package com.example.lambda.spring;
import java.util.*;
import java.util.function.*;
/**
* 模拟Spring中Lambda的应用
*/
public class SpringLambdaDemo {
public static void main(String[] args) {
// === 1. RestTemplate with Lambda (Spring 4.3+) ===
System.out.println("=== RestTemplate示例 ===");
// 传统方式
// ResponseEntity<String> response = restTemplate.execute(
// url, HttpMethod.GET, null, new ResponseExtractor<ResponseEntity<String>>() {
// @Override
// public ResponseEntity<String> extractData(ClientHttpResponse response) {
// // ...
// }
// }
// );
// Lambda方式
// ResponseEntity<String> response = restTemplate.execute(
// url, HttpMethod.GET, null,
// response -> new ResponseEntity<>(response.getBody(), HttpStatus.OK)
// );
// === 2. TransactionTemplate with Lambda ===
System.out.println("=== 事务模板示例 ===");
TransactionTemplate txTemplate = new TransactionTemplate();
// 有返回值的事务
String result = txTemplate.execute(status -> {
// 执行数据库操作
System.out.println(" 执行数据库操作...");
return "success";
});
System.out.println("事务结果: " + result);
// 无返回值的事务
txTemplate.executeWithoutResult(status -> {
System.out.println(" 执行数据库操作(无返回值)...");
// 可以回滚
// status.setRollbackOnly();
});
// === 3. JdbcTemplate with Lambda ===
System.out.println("\n=== JdbcTemplate示例 ===");
JdbcTemplate jdbcTemplate = new JdbcTemplate();
// 查询单个对象
User user = jdbcTemplate.queryForObject(
"SELECT * FROM user WHERE id = ?",
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")
),
1L
);
System.out.println("查询结果: " + user);
// 查询列表
List<User> users = jdbcTemplate.query(
"SELECT * FROM user",
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")
)
);
System.out.println("用户列表: " + users.size() + "个");
// === 4. Stream式的Repository查询 ===
System.out.println("\n=== Repository Stream查询 ===");
UserRepository userRepo = new UserRepository();
// 使用Stream处理查询结果
userRepo.findAll()
.stream()
.filter(u -> u.getEmail().contains("example"))
.map(User::getName)
.forEach(System.out::println);
// 方法引用
userRepo.findAll()
.forEach(System.out::println);
}
}
/**
* 模拟TransactionTemplate
*/
class TransactionTemplate {
public <T> T execute(Function<TransactionStatus, T> action) {
TransactionStatus status = new TransactionStatus();
try {
return action.apply(status);
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
}
public void executeWithoutResult(Consumer<TransactionStatus> action) {
TransactionStatus status = new TransactionStatus();
try {
action.accept(status);
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
}
}
class TransactionStatus {
private boolean rollbackOnly = false;
public void setRollbackOnly() {
this.rollbackOnly = true;
}
public boolean isRollbackOnly() {
return rollbackOnly;
}
}
/**
* 模拟JdbcTemplate
*/
class JdbcTemplate {
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) {
// 模拟数据库查询
MockResultSet rs = new MockResultSet();
rs.addData("id", 1L);
rs.addData("name", "Alice");
rs.addData("email", "alice@example.com");
return rowMapper.mapRow(rs, 0);
}
public <T> List<T> query(String sql, RowMapper<T> rowMapper) {
List<T> result = new ArrayList<>();
// 模拟多条记录
for (int i = 1; i <= 3; i++) {
MockResultSet rs = new MockResultSet();
rs.addData("id", (long) i);
rs.addData("name", "User" + i);
rs.addData("email", "user" + i + "@example.com");
result.add(rowMapper.mapRow(rs, i - 1));
}
return result;
}
}
@FunctionalInterface
interface RowMapper<T> {
T mapRow(MockResultSet rs, int rowNum);
}
/**
* 模拟ResultSet
*/
class MockResultSet {
private Map<String, Object> data = new HashMap<>();
public void addData(String column, Object value) {
data.put(column, value);
}
public Long getLong(String column) {
return (Long) data.get(column);
}
public String getString(String column) {
return (String) data.get(column);
}
}
/**
* 模拟Repository
*/
class UserRepository {
public List<User> findAll() {
return Arrays.asList(
new User(1L, "Alice", "alice@example.com"),
new User(2L, "Bob", "bob@example.com"),
new User(3L, "Charlie", "charlie@test.com")
);
}
}
八、Lambda性能优化
8.1 性能对比测试
package com.example.lambda.performance;
import java.util.*;
import java.util.stream.*;
/**
* Lambda性能测试
*/
public class PerformanceTest {
private static final int SIZE = 1_000_000;
private static final int ITERATIONS = 10;
public static void main(String[] args) {
List<Integer> numbers = IntStream.range(0, SIZE)
.boxed()
.collect(Collectors.toList());
System.out.println("=== 性能测试(数据量: " + SIZE + ") ===\n");
// 测试1: 传统for循环 vs Stream
testTraditionalVsStream(numbers);
// 测试2: Stream vs 并行Stream
testStreamVsParallelStream(numbers);
// 测试3: 方法引用 vs Lambda
testMethodReferenceVsLambda(numbers);
// 性能优化建议
printOptimizationTips();
}
/**
* 测试1: 传统循环 vs Stream
*/
private static void testTraditionalVsStream(List<Integer> numbers) {
System.out.println("=== 测试1: 传统for vs Stream ===");
// 传统for循环
long start1 = System.currentTimeMillis();
long sum1 = 0;
for (Integer num : numbers) {
if (num % 2 == 0) {
sum1 += num;
}
}
long end1 = System.currentTimeMillis();
System.out.println("传统for循环: " + sum1);
System.out.println("耗时: " + (end1 - start1) + "ms");
// Stream
long start2 = System.currentTimeMillis();
long sum2 = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToLong(Integer::longValue)
.sum();
long end2 = System.currentTimeMillis();
System.out.println("\nStream: " + sum2);
System.out.println("耗时: " + (end2 - start2) + "ms");
System.out.println("结论: 简单操作,传统for更快\n");
}
/**
* 测试2: Stream vs 并行Stream
*/
private static void testStreamVsParallelStream(List<Integer> numbers) {
System.out.println("=== 测试2: Stream vs 并行Stream ===");
// 串行Stream
long start1 = System.currentTimeMillis();
long sum1 = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToLong(n -> heavyComputation(n))
.sum();
long end1 = System.currentTimeMillis();
System.out.println("串行Stream: " + sum1);
System.out.println("耗时: " + (end1 - start1) + "ms");
// 并行Stream
long start2 = System.currentTimeMillis();
long sum2 = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.mapToLong(n -> heavyComputation(n))
.sum();
long end2 = System.currentTimeMillis();
System.out.println("\n并行Stream: " + sum2);
System.out.println("耗时: " + (end2 - start2) + "ms");
System.out.println("结论: CPU密集型操作,并行Stream更快\n");
}
/**
* 测试3: 方法引用 vs Lambda
*/
private static void testMethodReferenceVsLambda(List<Integer> numbers) {
System.out.println("=== 测试3: 方法引用 vs Lambda ===");
// Lambda
long start1 = System.currentTimeMillis();
long count1 = numbers.stream()
.map(n -> String.valueOf(n))
.count();
long end1 = System.currentTimeMillis();
System.out.println("Lambda: " + count1);
System.out.println("耗时: " + (end1 - start1) + "ms");
// 方法引用
long start2 = System.currentTimeMillis();
long count2 = numbers.stream()
.map(String::valueOf)
.count();
long end2 = System.currentTimeMillis();
System.out.println("\n方法引用: " + count2);
System.out.println("耗时: " + (end2 - start2) + "ms");
System.out.println("结论: 性能基本相同,推荐用方法引用(更简洁)\n");
}
/**
* 模拟重计算
*/
private static long heavyComputation(int n) {
long result = n;
for (int i = 0; i < 100; i++) {
result = result * 2 / 2;
}
return result;
}
/**
* 性能优化建议
*/
private static void printOptimizationTips() {
System.out.println("=== Lambda性能优化建议 ===\n");
System.out.println("1. 数据量小(<1000)时,使用传统for循环");
System.out.println("2. 数据量大且CPU密集型,使用并行Stream");
System.out.println("3. IO密集型操作,不要使用并行Stream");
System.out.println("4. 使用基本类型Stream(IntStream等)避免装箱");
System.out.println("5. 避免在Stream中修改外部变量");
System.out.println("6. 合理使用方法引用,代码更简洁");
System.out.println("7. Stream操作尽量无状态");
System.out.println("8. 避免过度使用Stream(简单循环用for)");
}
}
8.2 性能优化实践
package com.example.lambda.performance;
import java.util.*;
import java.util.stream.*;
/**
* Lambda性能优化实践
*/
public class OptimizationPractice {
public static void main(String[] args) {
// === 优化1: 使用基本类型Stream ===
System.out.println("=== 优化1: 避免装箱拆箱 ===");
// ❌ 不好的写法
long sum1 = IntStream.range(0, 1000000)
.boxed() // 装箱
.collect(Collectors.summingInt(Integer::intValue)); // 拆箱
// ✅ 好的写法
long sum2 = IntStream.range(0, 1000000)
.sum(); // 直接操作基本类型
System.out.println("使用基本类型Stream,避免装箱拆箱开销\n");
// === 优化2: 使用并行Stream的时机 ===
System.out.println("=== 优化2: 合理使用并行Stream ===");
List<Integer> largeList = IntStream.range(0, 10000000)
.boxed()
.collect(Collectors.toList());
// ✅ 适合并行: 数据量大,CPU密集型
long result = largeList.parallelStream()
.mapToInt(n -> n * n)
.sum();
System.out.println("大数据量 + CPU密集型 = 使用并行Stream\n");
// === 优化3: 短路操作 ===
System.out.println("=== 优化3: 利用短路操作 ===");
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// ✅ 使用anyMatch(短路)
boolean hasEven = numbers.stream()
.peek(n -> System.out.println("处理: " + n))
.anyMatch(n -> n % 2 == 0); // 找到第一个就停止
System.out.println("找到偶数: " + hasEven);
System.out.println("只处理了前2个元素\n");
// === 优化4: 避免多次Stream操作 ===
System.out.println("=== 优化4: 合并Stream操作 ===");
List<String> words = Arrays.asList("Hello", "World", "Java", "Lambda");
// ❌ 不好的写法: 多次遍历
long count1 = words.stream().count();
long length1 = words.stream().mapToInt(String::length).sum();
// ✅ 好的写法: 一次遍历
IntSummaryStatistics stats = words.stream()
.collect(Collectors.summarizingInt(String::length));
System.out.println("数量: " + stats.getCount());
System.out.println("总长度: " + stats.getSum());
System.out.println("一次遍历完成多个统计\n");
// === 优化5: 使用collect而非reduce ===
System.out.println("=== 优化5: 选择合适的终端操作 ===");
// ❌ 不够优化
String joined1 = words.stream()
.reduce("", (a, b) -> a + b + ",");
// ✅ 更优化
String joined2 = words.stream()
.collect(Collectors.joining(","));
System.out.println("使用专门的Collectors更高效: " + joined2);
}
}
九、实战案例
9.1 日志分析系统
package com.example.lambda.practice;
import java.time.*;
import java.util.*;
import java.util.stream.*;
/**
* 实战案例: 日志分析系统
*/
public class LogAnalyzer {
public static void main(String[] args) {
// 模拟日志数据
List<LogEntry> logs = generateLogs();
System.out.println("=== 日志分析系统 ===");
System.out.println("总日志数: " + logs.size() + "\n");
// 分析1: 按日志级别统计
Map<LogLevel, Long> countByLevel = logs.stream()
.collect(Collectors.groupingBy(
LogEntry::getLevel,
Collectors.counting()
));
System.out.println("按级别统计:");
countByLevel.forEach((level, count) ->
System.out.println(" " + level + ": " + count));
// 分析2: 查找所有ERROR日志
List<LogEntry> errors = logs.stream()
.filter(log -> log.getLevel() == LogLevel.ERROR)
.collect(Collectors.toList());
System.out.println("\nERROR日志:");
errors.forEach(log -> System.out.println(" " + log));
// 分析3: 统计每个模块的日志数
Map<String, Long> countByModule = logs.stream()
.collect(Collectors.groupingBy(
LogEntry::getModule,
Collectors.counting()
));
System.out.println("\n按模块统计:");
countByModule.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEach(entry ->
System.out.println(" " + entry.getKey() + ": " + entry.getValue()));
// 分析4: 查找最近1小时的WARN和ERROR日志
LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
List<LogEntry> recentCritical = logs.stream()
.filter(log -> log.getTimestamp().isAfter(oneHourAgo))
.filter(log -> log.getLevel() == LogLevel.WARN ||
log.getLevel() == LogLevel.ERROR)
.sorted(Comparator.comparing(LogEntry::getTimestamp).reversed())
.collect(Collectors.toList());
System.out.println("\n最近1小时的严重日志数: " + recentCritical.size());
// 分析5: 统计错误消息的Top 3
Map<String, Long> errorMessages = logs.stream()
.filter(log -> log.getLevel() == LogLevel.ERROR)
.collect(Collectors.groupingBy(
LogEntry::getMessage,
Collectors.counting()
));
System.out.println("\nTop 3错误消息:");
errorMessages.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(3)
.forEach(entry ->
System.out.println(" " + entry.getValue() + "次: " + entry.getKey()));
}
/**
* 生成模拟日志
*/
private static List<LogEntry> generateLogs() {
List<LogEntry> logs = new ArrayList<>();
Random random = new Random();
String[] modules = {"UserService", "OrderService", "PaymentService", "NotificationService"};
String[] messages = {
"操作成功",
"数据库连接失败",
"网络超时",
"参数验证失败",
"权限不足"
};
LogLevel[] levels = LogLevel.values();
for (int i = 0; i < 1000; i++) {
logs.add(new LogEntry(
LocalDateTime.now().minusMinutes(random.nextInt(180)),
levels[random.nextInt(levels.length)],
modules[random.nextInt(modules.length)],
messages[random.nextInt(messages.length)]
));
}
return logs;
}
}
/**
* 日志级别
*/
enum LogLevel {
DEBUG, INFO, WARN, ERROR
}
/**
* 日志实体
*/
class LogEntry {
private LocalDateTime timestamp;
private LogLevel level;
private String module;
private String message;
public LogEntry(LocalDateTime timestamp, LogLevel level, String module, String message) {
this.timestamp = timestamp;
this.level = level;
this.module = module;
this.message = message;
}
public LocalDateTime getTimestamp() { return timestamp; }
public LogLevel getLevel() { return level; }
public String getModule() { return module; }
public String getMessage() { return message; }
@Override
public String toString() {
return String.format("[%s] [%s] %s - %s",
timestamp, level, module, message);
}
}
9.2 数据清洗与转换
package com.example.lambda.practice;
import java.util.*;
import java.util.stream.*;
/**
* 实战案例: 数据清洗与转换
*/
public class DataCleaning {
public static void main(String[] args) {
// 原始脏数据
List<String> rawData = Arrays.asList(
"1,Alice,25,alice@example.com",
"2,Bob,30,bob@example.com",
"3,,28,", // 缺失数据
"4,Charlie,invalid,charlie@example.com", // 无效数据
"5,David,35,david@invalid", // 无效邮箱
"6,Eve,22,eve@example.com",
"7,Frank,40,frank@example.com",
",Grace,33,grace@example.com" // 缺失ID
);
System.out.println("=== 数据清洗与转换 ===");
System.out.println("原始数据: " + rawData.size() + "条\n");
// 数据清洗流程
List<Person> cleanedData = rawData.stream()
// 步骤1: 过滤空行
.filter(line -> line != null && !line.trim().isEmpty())
// 步骤2: 转换为Person对象
.map(DataCleaning::parsePerson)
// 步骤3: 过滤转换失败的数据
.filter(Optional::isPresent)
.map(Optional::get)
// 步骤4: 验证数据有效性
.filter(DataCleaning::isValid)
// 步骤5: 数据标准化
.map(DataCleaning::normalize)
// 收集结果
.collect(Collectors.toList());
System.out.println("清洗后数据: " + cleanedData.size() + "条\n");
// 输出清洗后的数据
cleanedData.forEach(System.out::println);
// 数据统计
System.out.println("\n=== 数据统计 ===");
DoubleSummaryStatistics ageStats = cleanedData.stream()
.collect(Collectors.summarizingDouble(Person::getAge));
System.out.printf("年龄统计: 平均%.1f, 最小%d, 最大%d\n",
ageStats.getAverage(),
(int) ageStats.getMin(),
(int) ageStats.getMax());
// 按年龄分组
Map<String, List<Person>> groupByAge = cleanedData.stream()
.collect(Collectors.groupingBy(p -> {
if (p.getAge() < 25) return "青年";
else if (p.getAge() < 35) return "中年";
else return "中老年";
}));
System.out.println("\n按年龄分组:");
groupByAge.forEach((group, list) ->
System.out.println(" " + group + ": " + list.size() + "人"));
}
/**
* 解析Person对象
*/
private static Optional<Person> parsePerson(String line) {
try {
String[] parts = line.split(",");
if (parts.length != 4) {
return Optional.empty();
}
Long id = Long.parseLong(parts[0].trim());
String name = parts[1].trim();
int age = Integer.parseInt(parts[2].trim());
String email = parts[3].trim();
return Optional.of(new Person(id, name, age, email));
} catch (Exception e) {
return Optional.empty();
}
}
/**
* 验证数据有效性
*/
private static boolean isValid(Person person) {
// ID不为空
if (person.getId() == null || person.getId() <= 0) {
return false;
}
// 姓名不为空
if (person.getName() == null || person.getName().isEmpty()) {
return false;
}
// 年龄合理
if (person.getAge() < 0 || person.getAge() > 150) {
return false;
}
// 邮箱格式
if (person.getEmail() == null ||
!person.getEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
return false;
}
return true;
}
/**
* 数据标准化
*/
private static Person normalize(Person person) {
// 姓名首字母大写
String normalizedName = person.getName().substring(0, 1).toUpperCase() +
person.getName().substring(1).toLowerCase();
// 邮箱转小写
String normalizedEmail = person.getEmail().toLowerCase();
return new Person(person.getId(), normalizedName, person.getAge(), normalizedEmail);
}
}
/**
* Person实体
*/
class Person {
private Long id;
private String name;
private int age;
private String email;
public Person(Long id, String name, int age, String email) {
this.id = id;
this.name = name;
this.age = age;
this.email = email;
}
public Long getId() { return id; }
public String getName() { return name; }
public int getAge() { return age; }
public String getEmail() { return email; }
@Override
public String toString() {
return String.format("Person{id=%d, name='%s', age=%d, email='%s'}",
id, name, age, email);
}
}
十、最佳实践
10.1 Lambda使用建议
+---------------------------+-----------------------------------+
| 场景 | 建议 |
+---------------------------+-----------------------------------+
| 简单逻辑 | 使用Lambda |
| 复杂逻辑(>3行) | 抽取为方法,使用方法引用 |
| 需要重用 | 定义为方法或变量 |
| 需要注释说明 | 使用普通方法 |
| 性能敏感 | 避免过度使用,考虑传统for |
| 并行处理 | 数据量大(>10000)时使用并行Stream |
| 异常处理 | 包装为运行时异常 |
| 类型推断 | 优先让编译器推断类型 |
+---------------------------+-----------------------------------+
10.2 常见陷阱
package com.example.lambda.best;
import java.util.*;
import java.util.stream.*;
/**
* Lambda常见陷阱与解决方案
*/
public class CommonPitfalls {
public static void main(String[] args) {
// === 陷阱1: 在Lambda中修改外部变量 ===
System.out.println("=== 陷阱1: 修改外部变量 ===");
// ❌ 错误: 不能修改外部局部变量
// int sum = 0;
// Arrays.asList(1, 2, 3).forEach(n -> sum += n); // 编译错误
// ✅ 解决方案1: 使用Stream的reduce
int sum = Arrays.asList(1, 2, 3).stream()
.reduce(0, Integer::sum);
System.out.println("使用reduce: " + sum);
// ✅ 解决方案2: 使用可变容器
List<Integer> sumHolder = new ArrayList<>();
sumHolder.add(0);
Arrays.asList(1, 2, 3).forEach(n -> sumHolder.set(0, sumHolder.get(0) + n));
System.out.println("使用容器: " + sumHolder.get(0));
// === 陷阱2: Stream被消费后不能重复使用 ===
System.out.println("\n=== 陷阱2: Stream重复使用 ===");
// ❌ 错误
// Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
// stream.forEach(System.out::println);
// stream.forEach(System.out::println); // 运行时错误
// ✅ 解决方案: 重新创建Stream
List<Integer> list = Arrays.asList(1, 2, 3);
list.stream().forEach(System.out::println);
list.stream().forEach(System.out::println); // OK
// === 陷阱3: 并行Stream的线程安全问题 ===
System.out.println("\n=== 陷阱3: 并行Stream线程安全 ===");
// ❌ 错误: 使用非线程安全的集合
List<Integer> unsafeList = new ArrayList<>();
IntStream.range(0, 1000).parallel()
.forEach(unsafeList::add); // 可能丢失数据
System.out.println("非线程安全: " + unsafeList.size()); // 可能<1000
// ✅ 解决方案: 使用collect
List<Integer> safeList = IntStream.range(0, 1000).parallel()
.boxed()
.collect(Collectors.toList());
System.out.println("线程安全: " + safeList.size()); // 总是1000
// === 陷阱4: 装箱拆箱性能损耗 ===
System.out.println("\n=== 陷阱4: 装箱拆箱 ===");
// ❌ 性能低下
long sum1 = IntStream.range(0, 1000000)
.boxed() // 装箱
.collect(Collectors.summingInt(Integer::intValue)); // 拆箱
// ✅ 性能优化
long sum2 = IntStream.range(0, 1000000)
.sum(); // 直接操作基本类型
System.out.println("使用基本类型Stream性能更好");
// === 陷阱5: 过度使用Stream ===
System.out.println("\n=== 陷阱5: 过度使用 ===");
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// ❌ 不必要的复杂
int first = numbers.stream()
.findFirst()
.orElse(0);
// ✅ 简单直接
int first2 = numbers.isEmpty() ? 0 : numbers.get(0);
System.out.println("简单操作不要过度使用Stream");
}
}
总结
核心知识点回顾
本文深入探讨了JDK 8 Lambda表达式,主要内容包括:
-
Lambda基础
- Lambda表达式语法与使用
- 函数式接口(@FunctionalInterface)
- JDK内置函数式接口
-
方法引用
- 静态方法引用
- 实例方法引用
- 构造器引用
-
Stream API
- Stream创建与操作
- 中间操作与终端操作
- 并行Stream
-
Optional
- 避免空指针异常
- 函数式编程风格
-
实战应用
- Spring框架中的Lambda
- 日志分析系统
- 数据清洗与转换
-
性能优化
- 性能对比测试
- 优化建议与最佳实践
Lambda表达式对比
| 维度 | 传统方式 | Lambda方式 |
|---|---|---|
| 代码量 | 多 | 少 |
| 可读性 | 一般 | 好 |
| 性能 | 优(简单操作) | 优(复杂操作) |
| 调试 | 容易 | 较难 |
| 适用场景 | 简单循环 | 数据处理、流式操作 |
使用建议
何时使用Lambda:
✓ 集合遍历、过滤、转换
✓ 事件处理、回调函数
✓ 函数式编程场景
✓ 代码简洁性要求高
何时避免Lambda:
✗ 简单的单次循环
✗ 需要详细调试
✗ 复杂的业务逻辑(>5行)
✗ 性能极度敏感的代码