Skip to content

Optional类

Optional概述

Optional是Java 8引入的容器类,用于优雅地处理空值,避免NullPointerException。

创建Optional

java
import java.util.Optional;

public class CreateOptional {
    public static void main(String[] args) {
        // 创建包含值的Optional
        Optional<String> opt1 = Optional.of("Hello");
        
        // 创建可能为null的Optional
        String str = null;
        Optional<String> opt2 = Optional.ofNullable(str);
        
        // 创建空的Optional
        Optional<String> opt3 = Optional.empty();
    }
}

常用方法

获取值

java
Optional<String> opt = Optional.of("Hello");

// get() - 获取值(为空时抛异常)
String value1 = opt.get();

// orElse() - 为空时返回默认值
String value2 = opt.orElse("Default");

// orElseGet() - 为空时通过Supplier获取
String value3 = opt.orElseGet(() -> "Default");

// orElseThrow() - 为空时抛出自定义异常
String value4 = opt.orElseThrow(() -> new RuntimeException("值为空"));

判断方法

java
Optional<String> opt = Optional.of("Hello");

// 是否有值
boolean hasValue = opt.isPresent();  // true

// 是否为空(Java 11+)
boolean isEmpty = opt.isEmpty();  // false

// 有值时执行操作
opt.ifPresent(value -> System.out.println(value));

// 有值时执行操作,否则执行另一个操作(Java 9+)
opt.ifPresentOrElse(
    value -> System.out.println("值: " + value),
    () -> System.out.println("无值")
);

转换方法

java
Optional<String> opt = Optional.of("Hello");

// map - 转换值
Optional<Integer> length = opt.map(String::length);

// flatMap - 转换值(返回Optional)
Optional<String> upper = opt.flatMap(s -> Optional.of(s.toUpperCase()));

// filter - 过滤
Optional<String> filtered = opt.filter(s -> s.length() > 3);

实战示例

避免空指针

java
// 传统方式
public String getCity(User user) {
    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            String city = address.getCity();
            if (city != null) {
                return city;
            }
        }
    }
    return "未知";
}

// 使用Optional
public String getCityOptional(User user) {
    return Optional.ofNullable(user)
        .map(User::getAddress)
        .map(Address::getCity)
        .orElse("未知");
}

方法返回值

java
public class UserService {
    private Map<Integer, User> users = new HashMap<>();
    
    // 返回Optional,明确表示可能为空
    public Optional<User> findById(Integer id) {
        return Optional.ofNullable(users.get(id));
    }
    
    // 使用
    public static void main(String[] args) {
        UserService service = new UserService();
        
        service.findById(1)
            .ifPresent(user -> System.out.println(user.getName()));
        
        String name = service.findById(1)
            .map(User::getName)
            .orElse("未知用户");
    }
}

集合处理

java
import java.util.*;
import java.util.stream.Collectors;

public class OptionalCollection {
    public static void main(String[] args) {
        List<Optional<String>> optionals = Arrays.asList(
            Optional.of("A"),
            Optional.empty(),
            Optional.of("B"),
            Optional.empty(),
            Optional.of("C")
        );
        
        // 过滤掉空值
        List<String> values = optionals.stream()
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect(Collectors.toList());
        // [A, B, C]
        
        // Java 9+ 使用Optional::stream
        List<String> values2 = optionals.stream()
            .flatMap(Optional::stream)
            .collect(Collectors.toList());
    }
}

配置处理

java
public class Config {
    private Properties props = new Properties();
    
    public Optional<String> getString(String key) {
        return Optional.ofNullable(props.getProperty(key));
    }
    
    public Optional<Integer> getInt(String key) {
        return getString(key).map(Integer::parseInt);
    }
    
    public Optional<Boolean> getBoolean(String key) {
        return getString(key).map(Boolean::parseBoolean);
    }
}

// 使用
Config config = new Config();
int timeout = config.getInt("timeout").orElse(30);
boolean debug = config.getBoolean("debug").orElse(false);

异常处理

java
public class ExceptionHandling {
    // 将可能抛异常的操作包装为Optional
    public static Optional<Integer> parseInt(String s) {
        try {
            return Optional.of(Integer.parseInt(s));
        } catch (NumberFormatException e) {
            return Optional.empty();
        }
    }
    
    public static void main(String[] args) {
        int value = parseInt("123").orElse(0);
        System.out.println(value);  // 123
        
        int invalid = parseInt("abc").orElse(0);
        System.out.println(invalid);  // 0
    }
}

Java 9+ 新增方法

or()

java
Optional<String> opt = Optional.empty();

// 为空时返回另一个Optional
Optional<String> result = opt.or(() -> Optional.of("Default"));
System.out.println(result);  // Optional[Default]

ifPresentOrElse()

java
Optional<String> opt = Optional.of("Hello");

opt.ifPresentOrElse(
    value -> System.out.println("值: " + value),
    () -> System.out.println("无值")
);

stream()

java
Optional<String> opt = Optional.of("Hello");

// 转换为Stream
Stream<String> stream = opt.stream();

// 在Stream中使用
List<String> list = Stream.of(
    Optional.of("A"),
    Optional.empty(),
    Optional.of("B")
).flatMap(Optional::stream).collect(Collectors.toList());
// [A, B]

最佳实践

1. 不要用Optional作为字段

java
// 不推荐
public class User {
    private Optional<String> name;  // 不推荐
}

// 推荐
public class User {
    private String name;  // 可以为null
}

2. 不要用Optional作为方法参数

java
// 不推荐
public void setName(Optional<String> name) { }

// 推荐
public void setName(String name) { }
public void setName(String name, String defaultValue) { }

3. 用于返回值

java
// 推荐:明确表示可能返回空
public Optional<User> findById(Integer id) {
    return Optional.ofNullable(userMap.get(id));
}

4. 避免直接调用get()

java
Optional<String> opt = Optional.ofNullable(getString());

// 不推荐
if (opt.isPresent()) {
    String value = opt.get();  // 多余的检查
}

// 推荐
opt.ifPresent(value -> process(value));
String value = opt.orElse("default");

5. 选择合适的orElse方法

java
// orElse - 默认值已确定
String value1 = opt.orElse("default");

// orElseGet - 默认值需要计算
String value2 = opt.orElseGet(() -> expensiveComputation());

// orElseThrow - 需要抛出异常
String value3 = opt.orElseThrow(() -> new NotFoundException());

Optional vs null

场景nullOptional
语义不明确明确表示可能为空
类型安全运行时NPE编译时检查
链式调用需要大量if流畅的链式调用
性能无开销有轻微开销
序列化支持不支持