← 返回首页

Java Optional详解

📂 java ⏱ 3 min 482 words

Java Optional详解

什么是Optional

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

创建Optional

public class OptionalCreation {
    public static void main(String[] args) {
        // of:非null值
        Optional<String> name = Optional.of("Alice");

        // ofNullable:可能为null
        Optional<String> nullable = Optional.ofNullable(getName());

        // empty:空Optional
        Optional<String> empty = Optional.empty();
    }

    private static String getName() {
        return Math.random() > 0.5 ? "Bob" : null;
    }
}

基本使用

public class OptionalBasic {
    public static void main(String[] args) {
        Optional<String> name = Optional.of("Alice");

        // isPresent:判断是否有值
        if (name.isPresent()) {
            System.out.println(name.get());
        }

        // ifPresent:有值时执行操作
        name.ifPresent(n -> System.out.println("名字: " + n));

        // orElse:提供默认值
        String result = name.orElse("Unknown");

        // orElseGet:延迟计算默认值
        String result2 = name.orElseGet(() -> computeDefault());

        // orElseThrow:抛出异常
        String result3 = name.orElseThrow(() ->
            new RuntimeException("名字不能为空")
        );

        // stream:转换为流
        List<String> list = name.stream().toList();
    }

    private static String computeDefault() {
        System.out.println("计算默认值");
        return "Default";
    }
}

转换操作

public class OptionalTransform {
    public static void main(String[] args) {
        Optional<String> name = Optional.of("Alice");

        // map:转换值
        Optional<Integer> length = name.map(String::length);
        System.out.println(length.orElse(0));  // 5

        // flatMap:扁平化转换
        Optional<String> upper = name.flatMap(n ->
            Optional.of(n.toUpperCase())
        );
        System.out.println(upper.orElse(""));  // ALICE

        // filter:过滤
        Optional<String> filtered = name.filter(n -> n.length() > 3);
        System.out.println(filtered.isPresent());  // true

        Optional<String> notFiltered = name.filter(n -> n.length() > 10);
        System.out.println(notFiltered.isPresent());  // false
    }
}

Optional链式操作

public class OptionalChain {
    public static void main(String[] args) {
        User user = new User("Alice", new Address("北京"));

        // 链式获取嵌套值
        String city = Optional.ofNullable(user)
            .map(User::getAddress)
            .map(Address::getCity)
            .orElse("未知");

        System.out.println(city);  // 北京

        // 复杂链式操作
        String result = Optional.ofNullable(user)
            .filter(u -> u.getAge() > 18)
            .map(User::getName)
            .map(String::toUpperCase)
            .orElse("GUEST");
    }
}

实际应用场景

方法返回值

public class UserService {
    private Map<Integer, User> userMap = new HashMap<>();

    // 使用Optional替代null
    public Optional<User> findUser(int id) {
        return Optional.ofNullable(userMap.get(id));
    }

    public Optional<String> getUserName(int id) {
        return findUser(id)
            .map(User::getName);
    }

    public Optional<String> getUserCity(int id) {
        return findUser(id)
            .map(User::getAddress)
            .map(Address::getCity);
    }
}

// 调用
UserService service = new UserService();
String city = service.getUserCity(1)
    .orElse("未知城市");

配置管理

public class Config {
    private String databaseUrl;
    private String cacheUrl;

    public Optional<String> getDatabaseUrl() {
        return Optional.ofNullable(databaseUrl);
    }

    public Optional<String> getCacheUrl() {
        return Optional.ofNullable(cacheUrl);
    }
}

// 使用
Config config = new Config();
String url = config.getDatabaseUrl()
    .orElse("jdbc:mysql://localhost:3306/default");

Optional与集合

public class OptionalCollection {
    public static <T> List<T> flatten(List<Optional<T>> optionals) {
        return optionals.stream()
            .filter(Optional::isPresent)
            .map(Optional::get)
            .toList();
    }

    public static <T> Optional<T> findFirst(List<T> list, Predicate<T> predicate) {
        return list.stream()
            .filter(predicate)
            .findFirst();
    }

    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5);

        Optional<Integer> first = findFirst(numbers, n -> n > 3);
        first.ifPresent(n -> System.out.println("找到: " + n));
    }
}

Optional作为参数

// 不推荐:Optional作为参数
public void process(Optional<String> value) {
    value.ifPresent(this::handle);
}

// 推荐:Optional作为返回值
public Optional<String> getValue() {
    return Optional.ofNullable(computeValue());
}

常见错误

public class OptionalMistakes {
    public static void main(String[] args) {
        Optional<String> name = Optional.of("Alice");

        // 错误1:直接调用get()前检查isPresent()
        if (name.isPresent()) {
            System.out.println(name.get()); // 不如直接用ifPresent
        }

        // 错误2:Optional作为类字段
        // private Optional<String> value; // 不推荐

        // 错误3:Optional作为方法参数
        // public void process(Optional<String> param); // 不推荐

        // 正确:链式操作
        name.map(String::toUpperCase)
            .ifPresent(System.out::println);

        // 正确:提供默认值
        String result = name.orElse("default");
    }
}

Optional性能考虑

public class OptionalPerformance {
    // Optional有轻微的内存开销,不要用于频繁创建的场景
    // 对于基本类型,使用OptionalInt/OptionalLong/OptionalDouble

    public void demo() {
        OptionalInt intOpt = OptionalInt.of(42);
        OptionalDouble doubleOpt = OptionalDouble.of(3.14);
        OptionalLong longOpt = OptionalLong.of(100L);
    }
}

总结

Optional是避免NullPointerException的优雅方案。正确使用map、flatMap、orElse等方法,可以让代码更加简洁和安全。记住Optional主要用于方法返回值,不要作为参数或字段使用。