本文目录导读:

我来为您详细讲解Java 8的Optional类,包括概念、核心用法、实战案例和最佳实践。
Optional概述
Optional是一个容器对象,用于包含可能为空的值,它提供了一种更优雅的方式来处理空值,避免NullPointerException。
基础使用案例
1 创建Optional对象
import java.util.Optional;
public class CreateOptionalExample {
public static void main(String[] args) {
// 1. 创建包含值的Optional
Optional<String> name = Optional.of("张三");
System.out.println("name: " + name); // Optional[张三]
// 2. 创建空的Optional
Optional<String> empty = Optional.empty();
System.out.println("empty: " + empty); // Optional.empty
// 3. 创建可能为空的Optional
String nullable = null;
Optional<String> optional = Optional.ofNullable(nullable);
System.out.println("optional: " + optional); // Optional.empty
// 注意:Optional.of()不能传null
try {
Optional.of(null);
} catch (NullPointerException e) {
System.out.println("Optional.of(null) 抛出 NullPointerException");
}
}
}
2 检查值是否存在
import java.util.Optional;
public class CheckValueExample {
public static void main(String[] args) {
Optional<String> name = Optional.of("李四");
Optional<String> empty = Optional.empty();
// isPresent() - 检查是否有值
System.out.println("name.isPresent(): " + name.isPresent()); // true
System.out.println("empty.isPresent(): " + empty.isPresent()); // false
// isEmpty() - Java 11+ 检查是否为空
// System.out.println("empty.isEmpty(): " + empty.isEmpty()); // true
// ifPresent() - 如果有值则执行操作
name.ifPresent(value -> System.out.println("值存在: " + value));
empty.ifPresent(value -> System.out.println("永远不会执行"));
}
}
获取值的案例
1 各种获取值的方式
import java.util.NoSuchElementException;
import java.util.Optional;
public class GetValueExample {
public static void main(String[] args) {
Optional<String> name = Optional.of("王五");
Optional<String> empty = Optional.empty();
// 1. get() - 如果值不存在会抛异常(不推荐使用)
System.out.println("get(): " + name.get()); // 王五
try {
empty.get();
} catch (NoSuchElementException e) {
System.out.println("empty.get() 抛出 NoSuchElementException");
}
// 2. orElse() - 如果值不存在返回默认值(推荐)
System.out.println("orElse: " + empty.orElse("默认值")); // 默认值
// 3. orElseGet() - 如果值不存在,通过Supplier提供默认值
System.out.println("orElseGet: " + empty.orElseGet(() -> "懒加载默认值"));
// 4. orElseThrow() - 如果值不存在抛出指定异常
try {
empty.orElseThrow(() -> new IllegalArgumentException("值不存在"));
} catch (IllegalArgumentException e) {
System.out.println("抛出自定义异常: " + e.getMessage());
}
// 5. orElseThrow() 无参数版本(Java 10+)
try {
empty.orElseThrow();
} catch (NoSuchElementException e) {
System.out.println("抛出默认 NoSuchElementException");
}
}
}
实战案例
1 用户信息查询系统
import java.util.Optional;
public class UserService {
// 用户数据模拟
private static final User[] USERS = {
new User(1L, "张三", "zhangsan@example.com", "北京"),
new User(2L, "李四", null, "上海"),
new User(3L, "王五", "wangwu@example.com", null)
};
// 查询用户(传统方式 vs Optional方式)
public static Optional<User> findUserById(Long id) {
for (User user : USERS) {
if (user.getId().equals(id)) {
return Optional.ofNullable(user);
}
}
return Optional.empty();
}
// 获取用户邮箱(安全获取,不抛异常)
public String getUserEmail(Long userId) {
return findUserById(userId)
.map(User::getEmail)
.orElse("无邮箱信息");
}
// 获取用户城市(链式操作)
public String getUserCity(Long userId) {
return findUserById(userId)
.map(User::getCity)
.filter(city -> city.length() > 0)
.orElse("未知城市");
}
// 复杂业务:发送邮件
public void sendEmailToUser(Long userId) {
findUserById(userId)
.filter(user -> user.getEmail() != null)
.map(User::getEmail)
.ifPresentOrElse(
email -> System.out.println("发送邮件到: " + email),
() -> System.out.println("用户无邮箱,无法发送")
);
}
// 用户类
static class User {
private Long id;
private String name;
private String email;
private String city;
public User(Long id, String name, String email, String city) {
this.id = id;
this.name = name;
this.email = email;
this.city = city;
}
public Long getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
public String getCity() { return city; }
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "'}";
}
}
public static void main(String[] args) {
UserService service = new UserService();
// 测试各种场景
System.out.println("=== 用户邮箱查询 ===");
System.out.println("用户1邮箱: " + service.getUserEmail(1L)); // 有邮箱
System.out.println("用户2邮箱: " + service.getUserEmail(2L)); // 无邮箱
System.out.println("用户99邮箱: " + service.getUserEmail(99L)); // 不存在
System.out.println("\n=== 用户城市查询 ===");
System.out.println("用户1城市: " + service.getUserCity(1L));
System.out.println("用户3城市: " + service.getUserCity(3L)); // 城市为null
System.out.println("用户99城市: " + service.getUserCity(99L)); // 用户不存在
System.out.println("\n=== 发送邮件测试 ===");
service.sendEmailToUser(1L); // 有邮箱
service.sendEmailToUser(2L); // 无邮箱
service.sendEmailToUser(99L); // 用户不存在
}
}
2 配置管理系统
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class ConfigManager {
private static final Map<String, String> CONFIG = new HashMap<>();
static {
CONFIG.put("app.name", "MyApp");
CONFIG.put("app.version", "1.0.0");
CONFIG.put("app.port", "8080");
}
// 获取配置项
public Optional<String> getConfig(String key) {
return Optional.ofNullable(CONFIG.get(key));
}
// 获取数值类型配置
public Optional<Integer> getIntegerConfig(String key) {
return getConfig(key)
.map(value -> {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return null;
}
});
}
// 获取端口(带默认值)
public int getPort() {
return getIntegerConfig("app.port")
.filter(port -> port > 0 && port < 65536)
.orElse(8080);
}
public static void main(String[] args) {
ConfigManager config = new ConfigManager();
System.out.println("应用名称: " + config.getConfig("app.name").orElse("未设置"));
System.out.println("应用端口: " + config.getPort());
System.out.println("最大连接数: " +
config.getIntegerConfig("max.connections").orElse(100));
// 链式配置读取
String databaseUrl = config.getConfig("database.url")
.orElseGet(() -> "jdbc:mysql://localhost:3306/default");
System.out.println("数据库URL: " + databaseUrl);
}
}
3 复杂的流式处理
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class OptionalStreamExample {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("张三", 8000, "技术部"),
new Employee("李四", 6000, "市场部"),
new Employee("王五", null, "技术部"),
new Employee("赵六", 15000, "管理部"),
new Employee("钱七", 12000, null)
);
// 1. 过滤出有薪水的员工,并计算总薪水
double totalSalary = employees.stream()
.map(Employee::getSalary)
.filter(Optional::isPresent)
.mapToDouble(Optional::get)
.sum();
System.out.println("总薪水: " + totalSalary);
// 2. 使用flatMap处理Optional
double totalSalary2 = employees.stream()
.map(Employee::getSalary)
.flatMap(Optional::stream)
.mapToDouble(Double::doubleValue)
.sum();
System.out.println("总薪水(flatMap): " + totalSalary2);
// 3. 获取所有有部门名称的员工
List<String> departments = employees.stream()
.map(Employee::getDepartment)
.flatMap(Optional::stream)
.distinct()
.collect(Collectors.toList());
System.out.println("存在部门: " + departments);
// 4. 查找薪水最高的员工
Employee highestPaid = employees.stream()
.filter(emp -> emp.getSalary().isPresent())
.max((e1, e2) -> e1.getSalary().orElse(0.0)
.compareTo(e2.getSalary().orElse(0.0)))
.orElse(null);
System.out.println("最高薪员工: " + highestPaid);
}
static class Employee {
private String name;
private Double salary;
private String department;
public Employee(String name, Double salary, String department) {
this.name = name;
this.salary = salary;
this.department = department;
}
public String getName() { return name; }
public Optional<Double> getSalary() {
return Optional.ofNullable(salary);
}
public Optional<String> getDepartment() {
return Optional.ofNullable(department);
}
@Override
public String toString() {
return "Employee{" + name + ", " +
(salary != null ? salary : "无") + "}";
}
}
}
Optional最佳实践
1 应该避免的做法
public class OptionalAntiPatterns {
// 反模式1:使用isPresent()和get()(没有发挥Optional的优势)
public String badPractice1(Optional<String> optional) {
if (optional.isPresent()) {
return optional.get();
}
return "default";
}
// 反模式2:作为方法参数(应使用重载或明确的null检查)
public void badPractice2(Optional<String> name) {
// 不推荐在参数中使用Optional
}
// 反模式3:作为类的字段(序列化问题)
static class BadEntity {
private Optional<String> name; // 不应该这样做
}
// 反模式4:在方法链中过度使用Optional
public String badPractice4(String value) {
return Optional.ofNullable(value)
.map(String::trim)
.map(String::toUpperCase)
.orElse("");
}
// 反模式的替代方案
public String goodPractice(String value) {
// 直接用if判断,代码更清晰
if (value == null || value.trim().isEmpty()) {
return "";
}
return value.trim().toUpperCase();
}
// 反模式5:用Optional包装已经可能为null的返回值
public static class UserRepository {
// 错误示范
public Optional<User> findByIdBad(Long id) {
User user = databaseQuery(id); // 这里的user已经可能为null
return Optional.ofNullable(user);
}
// 正确方式:如果数据库的方法本身返回Optional
public Optional<User> findByIdGood(Long id) {
// 如果数据库查询API返回Optional,直接返回
return databaseQueryOptional(id);
}
private User databaseQuery(Long id) { return null; }
private Optional<User> databaseQueryOptional(Long id) {
return Optional.empty();
}
}
}
2 正确的使用模式
import java.util.Optional;
public class OptionalBestPractices {
// 最佳实践1:返回值使用Optional(明确表达可能为空)
public Optional<String> findUserName(Long userId) {
// 假设从数据库查询
String name = queryDatabase(userId);
return Optional.ofNullable(name);
}
// 最佳实践2:使用orElseThrow处理必须存在的值
public String getRequiredConfig(String key) {
return Optional.ofNullable(System.getProperty(key))
.orElseThrow(() -> new IllegalStateException("必须配置: " + key));
}
// 最佳实践3:链式转换和过滤
public String transformValue(Optional<String> input) {
return input
.map(String::trim)
.filter(s -> !s.isEmpty())
.orElse("default");
}
// 最佳实践4:使用flatMap避免嵌套Optional
public Optional<String> getNestedValue(Optional<Wrapper> wrapper) {
return wrapper.flatMap(Wrapper::getValue);
}
// 最佳实践5:ifPresentOrElse处理存在和不存在的情况
public void processOptional(Optional<String> optional) {
optional.ifPresentOrElse(
value -> System.out.println("处理: " + value),
() -> System.out.println("值为空时的处理")
);
}
private String queryDatabase(Long id) {
return null; // 模拟不存在的用户
}
static class Wrapper {
private String value;
public Optional<String> getValue() {
return Optional.ofNullable(value);
}
}
public static void main(String[] args) {
OptionalBestPractices example = new OptionalBestPractices();
example.processOptional(Optional.of("测试"));
example.processOptional(Optional.empty());
}
}
实际项目中的综合案例
import java.util.*;
public class OrderService {
// 订单状态
enum OrderStatus {
PENDING, PAID, SHIPPED, DELIVERED, CANCELLED
}
static class Address {
private String street;
private String city;
public Address(String street, String city) {
this.street = street;
this.city = city;
}
public String getStreet() { return street; }
public String getCity() { return city; }
@Override
public String toString() {
return street + ", " + city;
}
}
static class Customer {
private Long id;
private String name;
private Address address; // 可能为null
public Customer(Long id, String name, Address address) {
this.id = id;
this.name = name;
this.address = address;
}
public Long getId() { return id; }
public String getName() { return name; }
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
}
static class Order {
private String orderId;
private Customer customer;
private double amount;
private OrderStatus status;
private Date deliveryDate; // 可能为null
public Order(String orderId, Customer customer, double amount,
OrderStatus status, Date deliveryDate) {
this.orderId = orderId;
this.customer = customer;
this.amount = amount;
this.status = status;
this.deliveryDate = deliveryDate;
}
public String getOrderId() { return orderId; }
public Optional<Customer> getCustomer() {
return Optional.ofNullable(customer);
}
public double getAmount() { return amount; }
public Optional<OrderStatus> getStatus() {
return Optional.ofNullable(status);
}
public Optional<Date> getDeliveryDate() {
return Optional.ofNullable(deliveryDate);
}
}
private List<Order> orders = new ArrayList<>();
public OrderService() {
// 初始化测试数据
Customer customer1 = new Customer(1L, "张三",
new Address("中关村大街1号", "北京"));
Customer customer2 = new Customer(2L, "李四", null);
orders.add(new Order("ORD001", customer1, 1999.00,
OrderStatus.DELIVERED, new Date()));
orders.add(new Order("ORD002", customer2, 399.00,
OrderStatus.PAID, null));
orders.add(new Order("ORD003", null, 899.00,
OrderStatus.PENDING, new Date()));
}
// 根据订单号查找订单
public Optional<Order> findOrderById(String orderId) {
return orders.stream()
.filter(order -> order.getOrderId().equals(orderId))
.findFirst();
}
// 获取订单的交付地址
public String getDeliveryAddress(String orderId) {
return findOrderById(orderId)
.flatMap(Order::getCustomer)
.flatMap(Customer::getAddress)
.map(Address::toString)
.orElse("无交付地址");
}
// 检查订单是否可取消
public boolean isOrderCancellable(String orderId) {
return findOrderById(orderId)
.map(Order::getStatus)
.flatMap(status -> status)
.map(status -> status == OrderStatus.PENDING ||
status == OrderStatus.PAID)
.orElse(false);
}
// 发送订单通知
public void sendOrderNotification(String orderId) {
Optional<Order> order = findOrderById(orderId);
order.ifPresentOrElse(
ord -> {
String customerName = ord.getCustomer()
.map(Customer::getName)
.orElse("未知客户");
System.out.println("发送订单通知给: " + customerName);
ord.getDeliveryDate().ifPresent(
date -> System.out.println("预计交付: " + date)
);
},
() -> System.out.println("订单不存在: " + orderId)
);
}
// 统计所有有交付日期的订单总额
public double calculateDeliveredAmount() {
return orders.stream()
.filter(order -> order.getStatus()
.map(s -> s == OrderStatus.DELIVERED)
.orElse(false))
.filter(order -> order.getDeliveryDate().isPresent())
.mapToDouble(Order::getAmount)
.sum();
}
public static void main(String[] args) {
OrderService service = new OrderService();
System.out.println("=== 订单地址查询 ===");
System.out.println("ORD001地址: " + service.getDeliveryAddress("ORD001"));
System.out.println("ORD002地址: " + service.getDeliveryAddress("ORD002"));
System.out.println("ORD003地址: " + service.getDeliveryAddress("ORD003"));
System.out.println("ORD999地址: " + service.getDeliveryAddress("ORD999"));
System.out.println("\n=== 订单取消检查 ===");
System.out.println("ORD001可取消: " + service.isOrderCancellable("ORD001"));
System.out.println("ORD002可取消: " + service.isOrderCancellable("ORD002"));
System.out.println("ORD003可取消: " + service.isOrderCancellable("ORD003"));
System.out.println("\n=== 发送通知 ===");
service.sendOrderNotification("ORD001");
service.sendOrderNotification("ORD002");
service.sendOrderNotification("ORD999");
System.out.println("\n=== 统计 ===");
System.out.println("已交付订单总额: " + service.calculateDeliveredAmount());
}
}
Optional核心方法总结
| 方法 | 说明 | 返回值 |
|---|---|---|
empty() |
创建空Optional | Optional<T> |
of(value) |
创建包含非null值的Optional | Optional<T> |
ofNullable(value) |
创建可能为null的Optional | Optional<T> |
isPresent() |
判断是否有值 | boolean |
ifPresent(consumer) |
如果有值则执行操作 | void |
ifPresentOrElse(consumer, runnable) |
有值/无值分别执行 | void |
get() |
获取值(无值抛异常) | T |
orElse(default) |
获取值或返回默认值 | T |
orElseGet(supplier) |
获取值或计算默认值 | T |
orElseThrow(exception) |
获取值或抛异常 | T |
map(mapper) |
转换值 | Optional<U> |
flatMap(mapper) |
转换值(不嵌套) | Optional<U> |
filter(predicate) |
过滤值 | Optional<T> |
stream() |
转换为流(Java 9+) | Stream<T> |
这个案例覆盖了Optional在实际开发中的主要使用场景,使用Optional可以让代码更安全、更清晰,但也要注意避免过度使用,在合适的场景下使用Optional是提升代码质量的好方法。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播