一文搞定Lambda表达式,Stream流,方法引用,Optional(JDK8新特性)
1.Lambda表达式
Lambda 表达式是一种匿名函数(没有名字的函数),可以作为方法参数传递,用于简化函数式接口(Functional Interface)的实现。简单来说,要用Lambda表达式,前提是必有函数式接口。
函数式接口:有且仅有一个抽象方法的接口(可用
@FunctionalInterface注解标注)
语法格式如下:
(parameters) -> statements 参数 -> 业务代码 或者如下的格式,适用于多行
(parameters) -> { statements; }
演示代码如下:
//传统匿名函数写法 Runnable是一个函数式接口
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
//Lambda表达式写法
Runnable r = () -> System.out.println("Hello");
应用场景如下:
1. 集合操作(配合 Stream API)
List<String> list = Arrays.asList("apple", "banana", "cherry");
// 过滤包含 "a" 的字符串并计数
long count = list.stream()
.filter(s -> s.contains("a"))
.count();
// 转大写并收集
List<String> upper = list.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
2. 线程任务
new Thread(() -> {
System.out.println("Running in thread: " + Thread.currentThread().getName());
}).start();
3. 事件监听(GUI / 回调)
button.addActionListener(e -> System.out.println("Button clicked!"));
4. 自定义函数式接口
@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
}
MathOperation add = (a, b) -> a + b;
MathOperation multiply = (a, b) -> a * b;
优点:
代码简洁,可读性强,支持函数式编程
缺点:
不能修改外部局部变量,调试困难
四大核心内置函数式接口
| 接口 | 名称 | 抽象方法 | 作用 | 入参 | 返回值 |
|---|---|---|---|---|---|
| Consumer | 消费者 | void accept(T t) | 消费数据,只处理不返回 | 有 T | 无返回值 void |
| Supplier | 生产者 | T get() | 生产数据,无参返回对象 | 无参数 | 返回 T |
| Predicate | 断言 / 判断 | boolean test(T t) | 条件判断,返回布尔 | 有 T | boolean |
| Function | 函数 / 转换器 | R apply(T t) | 类型转换,T 转 R | 有 T | 返回 R |
2.方法引用
方法引用(Method Reference)是 Java 8 引入的一种简洁语法,用于直接引用已有方法,而无需编写完整的 Lambda 表达式,可以理解他是方法引用的简化版本。如果 Lambda 只是调用一个已存在的方法,那就直接使用方法引用更方便。
1. 静态方法引用
List<Integer> numbers = Arrays.asList(-3, -1, 2, 5);
// Lambda 写法
List<Integer> abs1 = numbers.stream()
.map(x -> Math.abs(x))
.collect(Collectors.toList());
// 方法引用(更简洁)
List<Integer> abs2 = numbers.stream()
.map(Math::abs) // ← 直接引用 Math.abs()
.collect(Collectors.toList());
2. 特定对象的实例方法
String prefix = "Hello ";
List<String> names = Arrays.asList("Alice", "Bob");
// Lambda:每个名字都拼接到 prefix 后
List<String> greetings1 = names.stream()
.map(name -> prefix.concat(name))
.collect(Collectors.toList());
// 方法引用:固定使用 prefix 对象的 concat 方法
List<String> greetings2 = names.stream()
.map(prefix::concat) // ← prefix 是外部变量
.collect(Collectors.toList());
3. 任意对象的实例方法
这是我们日常开发过程中用到最多的一种模式
List<String> words = Arrays.asList("apple", "Banana", "cherry");
// Lambda
List<String> upper1 = words.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toList());
// 方法引用
List<String> upper2 = words.stream()
.map(String::toUpperCase) // ← 每个字符串自己调用 toUpperCase()
.collect(Collectors.toList());
// 其他例子
orderList.stream().map(Order::getName) // 每个 Order 调用 getName()
users.stream().filter(User::isActive) // 每个 User 调用 isActive()
构造器方法引用再开发中引用很少,基本没怎么用过,这里不做多余阐述。
3.Stream流
Stream API 是 JDK 8 引入的革命性特性,它让 Java 首次具备了声明式、函数式处理集合数据的能力。
3.1Stream API 的核心优点
表格
| 优点 | 说明 |
|---|---|
|
1. 声明式编程 |
你只描述“要什么”(filter、map、group),不写“怎么做”(for 循环、if 判断) |
| 2. 链式调用 | 多个操作可流畅串联:list.stream().filter(...).map(...).collect(...) |
| 3. 惰性求值(Lazy Evaluation) | 中间操作(如 filter、map)不立即执行,直到终端操作(如 collect、count)触发 |
| 4. 并行处理简单 | 只需 .parallelStream() 或 .parallel(),自动利用多核 CPU(但需谨慎!) |
| 5. 减少样板代码 | 替代大量 for + if + add 的模板代码 |
| 6. 类型安全 & 编译时检查 | 比传统循环更少出错(如索引越界) |
3.2Stream 操作
- 中间操作(懒加载,不执行):filter、map、sorted、distinct、limit
- 终端操作(触发执行,关闭流):collect、forEach、count、max、min、anyMatch
3.2.1. 过滤(filter)
// 获取所有已支付的订单
List<Order> paidOrders = orders.stream()
.filter(order -> "PAID".equals(order.getStatus()))
.collect(Collectors.toList());
3.2 2. 映射转换(map / flatMap)
// 提取所有商品名称
List<String> productNames = products.stream()
.map(Product::getName)
.collect(Collectors.toList());
// 展平:每个用户有多个收货地址 → 所有地址列表
List<Address> allAddresses = users.stream()
.flatMap(user -> user.getAddresses().stream())
.collect(Collectors.toList());
3.3 3. 去重(distinct)
// 获取所有不重复的商品分类
List<String> categories = products.stream()
.map(Product::getCategory)
.distinct()
.collect(Collectors.toList());
3.3.4. 排序(sorted)
// 按订单金额降序
List<Order> sortedOrders = orders.stream()
.sorted(Comparator.comparing(Order::getAmount).reversed())
.collect(Collectors.toList());
3.3.5. 聚合统计(count / sum / max / min / average)
// 订单总数、总金额、平均金额
long count = orders.stream().count();
double total = orders.stream().mapToDouble(Order::getAmount).sum();
OptionalDouble avg = orders.stream().mapToDouble(Order::getAmount).average();
3.3.6. 分组(groupingBy)
// 按店铺分组订单
Map<Long, List<Order>> ordersByShop = orders.stream()
.collect(Collectors.groupingBy(Order::getShopId));
// 按状态分组 + 统计每组数量
Map<String, Long> statusCount = orders.stream()
.collect(Collectors.groupingBy(Order::getStatus, Collectors.counting()));
3.3.7. 分区(partitioningBy)
// 将商品分为“库存充足”和“缺货”两类
Map<Boolean, List<Product>> stockPartition = products.stream()
.collect(Collectors.partitioningBy(p -> p.getStock() > 0));
3.3.8. 转为其他集合类型
// 转 Set(自动去重)
Set<String> skuSet = products.stream()
.map(Product::getSku)
.collect(Collectors.toSet());
// 转 Map(key=ID, value=对象)
Map<Long, Product> productMap = products.stream()
.collect(Collectors.toMap(Product::getId, Function.identity()));
3.3. 9. 处理数组
String[] arr = {"a", "b", "c"};
List<String> list = Arrays.stream(arr)
.filter(s -> !s.equals("b"))
.collect(Collectors.toList());
3.3.10. 查找(findAny / findFirst)
// 找一个 VIP 用户
Optional<User> vipUser = users.stream()
.filter(User::isVip)
.findAny(); // 并行流用 findAny 更高效
4.Optional
Optional<T> 是 Java 8 引入的一个容器类(wrapper class),用于显式表达“一个值可能存在,也可能不存在” 的语义。它的核心目标不是“替代 null”,而是让空值处理更安全、更清晰、更具声明性。
常用方法如下:
创建 Optional
| 方法 | 说明 |
|---|---|
Optional.of(T value) |
创建非空 Optional(value 不能为 null) |
Optional.ofNullable(T value) |
最常用! value 可为 null,自动转为 empty |
Optional.empty() |
创建空 Optional |
判断是否存在值
| 方法 | 说明 |
|---|---|
boolean isPresent() |
有值返回 true |
void ifPresent(Consumer<T> action) |
有值则执行操作(推荐替代 if 判断) |
安全获取值
| 方法 | 说明 |
|---|---|
T orElse(T other) |
有值返回值,否则返回默认值 |
T orElseGet(Supplier<T> supplier) |
懒加载默认值(仅在需要时计算) |
T orElseThrow(Supplier<X> exceptionSupplier) |
为空时抛出自定义异常 |
我们先来看一下下面这段代码
public String getUserName(User user) {
return user.getName().toUpperCase();
}
这个方法很明显的有以下问题:
user可能为nulluser.getName()可能返回null- 调用方不知道是否可能为
null,容易出错
那让我们来看看这个Optional是怎么做的
public Optional<String> getUserName(User user) {
return Optional.ofNullable(user)
.map(User::getName)
.map(String::toUpperCase);
}
//调用如下:
String name = getUserName(user).orElse("匿名用户");
// 仅当你 100% 确定 user 和 name 都不为 null
String name = getUserName(user).get(); // ⚠️ 如果为空会抛 NoSuchElementException!
4.1Optional 的 5 大场景
4.1.1:方法返回值可能为空
public Optional<Product> findProductByName(String name) {
Product p = productDao.findByName(name);
return Optional.ofNullable(p);
}
// 调用方必须处理“找不到”的情况
productService.findProductByName("iPhone")
.ifPresent(p -> order.setPrice(p.getPrice()));
适用于:DAO 查询、缓存查找、配置读取等可能无结果的操作。
4.1.2:多层嵌套对象的安全访问
// 传统写法(啰嗦)
if (user != null) {
Address addr = user.getAddress();
if (addr != null) {
String city = addr.getCity();
if (city != null) {
return city.toUpperCase();
}
}
}
// Optional 写法(清晰)
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.map(String::toUpperCase)
.orElse("未知城市");
适用于:用户资料、订单地址、JSON 解析等深度嵌套结构。
4.1.3:Stream 流中的终端操作
List<Order> orders = ...;
// findFirst(), max(), min(), reduce() 等返回 Optional
Optional<Order> firstOrder = orders.stream().findFirst();
Optional<Order> mostExpensive = orders.stream()
.max(Comparator.comparing(Order::getMoney));
// 安全处理
mostExpensive.ifPresent(order -> sendVIPCoupon(order));
这是 Optional 最自然的使用场景,无需额外包装。
4.1.4:提供默认值或抛异常(比 if-else 更函数式)
String name = Optional.ofNullable(inputName)
.filter(n -> n.length() > 2)
.orElse("匿名用户");
// 或抛异常
User user = Optional.ofNullable(findUser(id))
.orElseThrow(() -> new UserNotFoundException("ID=" + id));
📌 比
if (x == null) x = default;更简洁、可链式组合。
4.1.5:函数式编程中的“空安全”组合
// 将多个可能为空的操作组合起来
public Optional<Invoice> generateInvoice(Long orderId) {
return findOrder(orderId) // Optional<Order>
.filter(Order::isValid)
.flatMap(this::calculateTax) // 返回 Optional<Invoice>
.map(this::applyDiscount);
}
最后有一句话来形容就是:
如果这个方法可能返回 null,并且调用方需要显式处理‘没有结果’的情况,那就返回 Optional。
更多推荐




所有评论(0)