Java Optional详解:优雅处理空值
Java Optional详解:优雅处理空值
概述
Optional是Java 8引入的容器类,用于表示一个值可能存在或不存在。Optional可以帮助避免NullPointerException,使代码更优雅、更可读。
1. 创建Optional
import java.util.Optional;
public class OptionalCreationExample {
public static void main(String[] args) {
// 1. Optional.of():值不能为null
Optional<String> name = Optional.of("Alice");
System.out.println("Of: " + name);
// Optional.of(null); // 抛出NullPointerException
// 2. Optional.ofNullable():值可以为null
Optional<String> nullName = Optional.ofNullable(null);
System.out.println("OfNullable: " + nullName);
Optional<String> nonNullName = Optional.ofNullable("Bob");
System.out.println("OfNullable: " + nonNullName);
// 3. Optional.empty():空Optional
Optional<String> empty = Optional.empty();
System.out.println("Empty: " + empty);
// 4. Optional类的布尔方法
System.out.println("name.isPresent(): " + name.isPresent());
System.out.println("nullName.isPresent(): " + nullName.isPresent());
System.out.println("empty.isPresent(): " + empty.isPresent());
}
}
2. 使用Optional
import java.util.Optional;
public class OptionalUsageExample {
public static void main(String[] args) {
Optional<String> name = Optional.of("Alice");
Optional<String> nullName = Optional.ofNullable(null);
// 1. get():获取值(如果不存在会抛出异常)
String value = name.get();
System.out.println("Get: " + value);
// 2. orElse():值不存在时返回默认值
String value2 = nullName.orElse("Unknown");
System.out.println("OrElse: " + value2);
// 3. orElseGet():值不存在时调用Supplier获取默认值
String value3 = nullName.orElseGet(() -> "Default");
System.out.println("OrElseGet: " + value3);
// 4. orElseThrow():值不存在时抛出异常
try {
String value4 = nullName.orElseThrow(() ->
new RuntimeException("值不存在"));
} catch (RuntimeException e) {
System.out.println("OrElseThrow: " + e.getMessage());
}
// 5. ifPresent():值存在时执行操作
name.ifPresent(n -> System.out.println("IfPresent: " + n));
nullName.ifPresent(n -> System.out.println("This won't print"));
// 6. ifPresentOrElse():值存在时执行一个操作,不存在时执行另一个操作
name.ifPresentOrElse(
n -> System.out.println("Found: " + n),
() -> System.out.println("Not found")
);
nullName.ifPresentOrElse(
n -> System.out.println("Found: " + n),
() -> System.out.println("Not found")
);
}
}
3. Optional转换操作
import java.util.Optional;
public class OptionalTransformExample {
public static void main(String[] args) {
Optional<String> name = Optional.of("Alice");
Optional<String> nullName = Optional.ofNullable(null);
// 1. map():转换值
Optional<Integer> nameLength = name.map(String::length);
System.out.println("Map: " + nameLength.orElse(0));
Optional<Integer> nullNameLength = nullName.map(String::length);
System.out.println("Map null: " + nullNameLength.orElse(0));
// 2. flatMap():转换为Optional
Optional<String> upperCase = name.flatMap(n -> Optional.of(n.toUpperCase()));
System.out.println("FlatMap: " + upperCase.orElse(""));
// 3. filter():过滤
Optional<String> filtered = name.filter(n -> n.startsWith("A"));
System.out.println("Filter: " + filtered.orElse(""));
Optional<String> notFiltered = name.filter(n -> n.startsWith("B"));
System.out.println("Filter not match: " + notFiltered.orElse(""));
// 4. or():提供替代Optional(Java 9+)
Optional<String> alternative = nullName.or(() -> Optional.of("Alternative"));
System.out.println("Or: " + alternative.orElse(""));
// 5. stream():转换为Stream(Java 9+)
name.stream().forEach(n -> System.out.println("Stream: " + n));
nullName.stream().forEach(n -> System.out.println("This won't print"));
}
}
4. Optional与方法
import java.util.Optional;
public class OptionalWithMethods {
// 返回Optional的方法
public static Optional<String> findName(int id) {
if (id == 1) {
return Optional.of("Alice");
} else if (id == 2) {
return Optional.of("Bob");
} else {
return Optional.empty();
}
}
// 使用Optional的方法
public static void processName(int id) {
findName(id)
.map(String::toUpperCase)
.ifPresent(name -> System.out.println("Name: " + name));
}
public static void main(String[] args) {
processName(1); // 输出: Name: ALICE
processName(2); // 输出: Name: BOB
processName(3); // 无输出
}
}
5. Optional最佳实践
import java.util.Optional;
public class OptionalBestPractices {
// 1. 不要用Optional作为字段
// 错误做法
// public class Person {
// private Optional<String> name; // 不推荐
// }
// 正确做法
public static class Person {
private String name;
public Person(String name) {
this.name = name;
}
public Optional<String> getName() {
return Optional.ofNullable(name);
}
}
// 2. 不要用Optional.get()而不检查
public static void badPractice(Optional<String> name) {
// String value = name.get(); // 危险!可能抛出异常
}
// 3. 使用orElseThrow()而不是get()
public static void goodPractice(Optional<String> name) {
String value = name.orElseThrow(() ->
new RuntimeException("Name not found"));
}
// 4. 使用链式操作
public static void chainOperations(Optional<Person> person) {
person
.map(Person::getName)
.flatMap(name -> name)
.map(String::toUpperCase)
.ifPresent(name -> System.out.println("Name: " + name));
}
public static void main(String[] args) {
// 使用示例
Optional<Person> person = Optional.of(new Person("Alice"));
chainOperations(person);
Optional<Person> nullPerson = Optional.empty();
chainOperations(nullPerson);
}
}
6. 实际应用示例
用户查找服务
import java.util.Optional;
public class UserService {
// 模拟数据库
private static final Map<Long, User> database = new HashMap<>();
static {
database.put(1L, new User(1L, "Alice", "alice@example.com"));
database.put(2L, new User(2L, "Bob", "bob@example.com"));
}
public Optional<User> findById(Long id) {
return Optional.ofNullable(database.get(id));
}
public Optional<String> findEmailById(Long id) {
return findById(id)
.map(User::getEmail);
}
public Optional<String> findNameById(Long id) {
return findById(id)
.map(User::getName)
.filter(name -> !name.isEmpty());
}
public User findUserOrDefault(Long id, String defaultName) {
return findById(id)
.orElse(new User(id, defaultName, "unknown@example.com"));
}
}
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; }
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "', email='" + email + "'}";
}
}
// 测试
public class UserServiceTest {
public static void main(String[] args) {
UserService service = new UserService();
// 查找用户
Optional<User> user = service.findById(1L);
user.ifPresent(System.out::println);
// 查找邮箱
Optional<String> email = service.findEmailById(1L);
email.ifPresent(e -> System.out.println("Email: " + e));
// 查找不存在的用户
Optional<User> nonExistent = service.findById(999L);
nonExistent.ifPresentOrElse(
u -> System.out.println("Found: " + u),
() -> System.out.println("User not found")
);
// 使用默认值
User defaultUser = service.findUserOrDefault(999L, "Guest");
System.out.println("Default user: " + defaultUser);
}
}
7. 常见陷阱
import java.util.Optional;
public class OptionalPitfalls {
public static void main(String[] args) {
// 1. 不要用Optional作为参数
// 错误做法
// public void process(Optional<String> name) { }
// 正确做法
public void process(String name) {
Optional.ofNullable(name)
.ifPresent(this::doProcess);
}
// 2. 不要创建Optional的集合
// 错误做法
// List<Optional<String>> list = new ArrayList<>();
// 正确做法
// List<String> list = new ArrayList<>();
// 3. 不要序列化Optional
// Optional不是Serializable的
// 4. 不要用Optional包装基本类型
// 错误做法
// Optional<int> number = Optional.of(5);
// 正确做法
Optional<Integer> number = Optional.of(5);
}
private void doProcess(String name) {
System.out.println("Processing: " + name);
}
}
8. 最佳实践总结
- 方法返回Optional:当方法可能返回null时,返回Optional
- 不要用Optional作为字段:Optional应该用于方法返回值
- 使用链式操作:利用map、flatMap、filter等方法
- 提供默认值:使用orElse、orElseGet、orElseThrow
- 避免Optional.get():除非已经检查了isPresent()
总结
Optional是Java 8引入的重要特性,它帮助我们优雅地处理空值。通过Optional,可以避免NullPointerException,使代码更安全、更可读。掌握Optional的使用方法和最佳实践,是现代Java编程的重要技能。