Bootstrap

深入解析 Java Optional:避免 NPE 的最佳实践与代码示例

Optional<T> 是 Java 8 引入的一个容器类,用于避免 NullPointerException(NPE),并鼓励更优雅的代码风格。它提供了多种方法来处理可能为空的值。以下是一些深入学习 Optional 的代码示例:


1. 创建 Optional

import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        Optional<String> optional1 = Optional.of("Hello, Java!"); // 不能为 null
        Optional<String> optional2 = Optional.ofNullable(null);  // 可以为 null
        Optional<String> optional3 = Optional.empty();           // 空 Optional

        System.out.println(optional1);
        System.out.println(optional2);
        System.out.println(optional3);
    }
}

2. 判断 Optional 是否有值

public class OptionalCheck {
    public static void main(String[] args) {
        Optional<String> optional = Optional.ofNullable("Java Optional");

        if (optional.isPresent()) {
            System.out.println("Value: " + optional.get());
        }

        optional.ifPresent(value -> System.out.println("Using ifPresent: " + value));
    }
}

推荐使用 ifPresent() 代替 isPresent(),这样可以避免手动 get() 取值时可能的 NPE。


3. 使用 orElse()orElseGet()

public class OptionalOrElse {
    public static void main(String[] args) {
        String nullValue = null;

        String result1 = Optional.ofNullable(nullValue).orElse("Default Value");
        String result2 = Optional.ofNullable(nullValue).orElseGet(() -> "Computed Value");

        System.out.println(result1);
        System.out.println(result2);
    }
}
  • orElse() 始终会计算默认值,即使 Optional 有值。
  • orElseGet() 只有在 Optional 为空时才会计算默认值

4. 使用 orElseThrow() 抛异常

public class OptionalOrElseThrow {
    public static void main(String[] args) {
        try {
            String value = Optional.ofNullable(null)
                .orElseThrow(() -> new IllegalArgumentException("Value is missing"));
            System.out.println(value);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

如果 Optional 为空,就会抛出指定异常。


5. 使用 map() 处理 Optional

public class OptionalMap {
    public static void main(String[] args) {
        Optional<String> optional = Optional.of("java optional");

        Optional<Integer> lengthOptional = optional.map(String::length);
        lengthOptional.ifPresent(length -> System.out.println("Length: " + length));
    }
}

map() 用于对 Optional 中的值进行转换。


6. 使用 flatMap() 处理嵌套 Optional

import java.util.Optional;

public class OptionalFlatMap {
    public static void main(String[] args) {
        Optional<Optional<String>> nestedOptional = Optional.of(Optional.of("Nested Optional"));

        Optional<String> flatMapped = nestedOptional.flatMap(opt -> opt);
        flatMapped.ifPresent(System.out::println);
    }
}

如果 map() 返回的是 Optional,那么会得到嵌套 Optional<Optional<T>>,使用 flatMap() 可以去除嵌套。


7. 过滤 Optional 值

public class OptionalFilter {
    public static void main(String[] args) {
        Optional<String> optional = Optional.of("Hello Java");

        optional.filter(value -> value.startsWith("Hello"))
                .ifPresent(System.out::println);
        
        optional.filter(value -> value.startsWith("World"))
                .ifPresentOrElse(System.out::println, 
                    () -> System.out.println("Filter condition not met"));
    }
}

filter() 允许对 Optional 值进行条件筛选。


8. 应用场景:避免 NPE

class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }
}

public class OptionalUsage {
    public static void main(String[] args) {
        User user = new User(null);

        String username = user.getName().orElse("Anonymous");
        System.out.println(username);
    }
}

这里 getName() 返回 Optional<String>,调用方可以优雅地处理 null,避免 NullPointerException


9. 组合多个 Optional

public class OptionalCombination {
    public static void main(String[] args) {
        Optional<String> first = Optional.of("First");
        Optional<String> second = Optional.empty();

        String result = first.or(() -> second).orElse("Default");
        System.out.println(result);
    }
}

or() 允许你在多个 Optional 之间取第一个有值的。


总结:

  1. 创建 Optional

    • Optional.of(value): 不能为 null
    • Optional.ofNullable(value): 允许 null
    • Optional.empty(): 创建空 Optional
  2. 判断是否有值

    • isPresent()(不推荐)
    • ifPresent(Consumer)
  3. 获取值

    • get()(不推荐)
    • orElse(defaultValue)
    • orElseGet(Supplier)
    • orElseThrow(Supplier<Throwable>)
  4. 转换值

    • map(Function<T, R>)
    • flatMap(Function<T, Optional<R>>)
    • filter(Predicate)
  5. 组合 Optional

    • or(Supplier<Optional<T>>)
    • orElse() / orElseGet()

这样,你可以在 Java 项目中更优雅地处理 null,减少 NPE 发生的可能性。🚀

;