详解JAVA中的OPTIONAL

Java中的Optional是Java8中新增的类,用于解决空指针异常。Optional类通过包装对象的形式,判断对象是否为空,从而避免空指针异常。

详解JAVA中的Optional

Java中的Optional是Java8中新增的类,用于解决空指针异常。Optional类通过包装对象的形式,判断对象是否为空,从而避免空指针异常。

Optional基本概念

Optional的创建

Optional的创建有两种方法:empty()和of(T value)。

当要创建一个空的Optional对象时,可以使用empty方法:

Optional<String> emptyOptional = Optional.empty(); // 创建一个空的Optional对象

当要创建一个非空的Optional对象时,可以使用of方法:

String str = "Hello";
Optional<String> nonEmptyOptional = Optional.of(str); // 创建一个非空的Optional对象

如果使用of方法时,传入的对象为null,则会抛出NullPointerException。

判断Optional是否为空

Optional类提供了isPresent()和isEmpty()两个方法来判断Optional是否为空。

Optional<String> strOptional = Optional.ofNullable("Hello");
if (strOptional.isPresent()) {
    System.out.println(strOptional.get());
}

Optional<String> emptyOptional = Optional.empty();
if (emptyOptional.isEmpty()) {
    System.out.println("This Optional is empty.");
}

获取Optional中的值

Optional类提供了get()方法来获取Optional中的值。如果Optional中的对象为空,调用get()方法会抛出NoSuchElementException。

Optional<String> strOptional = Optional.ofNullable("Hello");
if (strOptional.isPresent()) {
    System.out.println(strOptional.get());
}

Optional<String> emptyOptional = Optional.empty();
try {
    emptyOptional.get();
} catch (NoSuchElementException e) {
    System.out.println("This Optional is empty.");
}

设置默认值

Optional类提供了orElse(T other)和orElseGet(Supplier<? extends T> other)两个方法,用于在Optional为空时返回默认值。

orElse方法返回一个默认值,如果Optional不为空,返回Optional的值;orElseGet方法根据传入的Supplier返回一个默认值。

Optional<String> strOptional = Optional.empty();
String result = strOptional.orElse("Default value");
System.out.println(result); // 输出:Default value

Optional<String> nonEmptyOptional = Optional.of("Non-empty value");
String result2 = nonEmptyOptional.orElse("Default value");
System.out.println(result2); // 输出:Non-empty value

orElse方法在Optional为空时,会返回指定的默认值;orElseGet方法在Optional为空时,会调用Supplier提供默认值。与orElse方法相比,orElseGet方法更适合于获取成本较高的默认值。

Optional<String> strOptional = Optional.empty();
String expensiveDefault = expensiveComputation(); // 模拟计算成本较高的默认值
String result = strOptional.orElseGet(() -> expensiveDefault);
System.out.println(result); // 输出计算得到的默认值

抛出异常

Optional类提供了orElseThrow()方法,用于在Optional为空时,抛出指定的异常。

Optional<String> strOptional = Optional.empty();
strOptional.orElseThrow(IllegalArgumentException::new); // 抛出IllegalArgumentException异常

Optional在业务中的使用

示例一:使用Optional避免空指针异常

假设有一个Person类包含了name和address属性,现在需要根据姓名获取该Person所在的国家。

public class Person {
    private String name;
    private Address address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

public class Address {
    private String country;

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }
}

在传统方式中,如果要获取该Person所在的国家,需要先判断Person和Address对象是否为空,如下所示:

public String getCountryByName(String name) {
    Person person = findPersonByName(name);
    if (person != null) {
        Address address = person.getAddress();
        if (address != null) {
            return address.getCountry();
        }
    }
    return null;
}

如果使用Optional来改写上面的代码,代码更加简洁和安全:

public String getCountryByName(String name) {
    Optional<Person> optionalPerson = Optional.ofNullable(findPersonByName(name));
    return optionalPerson.flatMap(person -> Optional.ofNullable(person.getAddress()))
                         .map(Address::getCountry)
                         .orElse("Unknown");
}

示例二:使用Optional实现接口参数的可选性

假设有一个接口,该接口有一个必传参数和一个可选参数,为了支持可选参数,可以将可选参数包装成Optional类型。

public interface ProductService {
    int getPrice(String productName);
    int getPrice(String productName, int discount);
}

public class ProductServiceImpl implements ProductService {

    private Map<String, Integer> products = new HashMap<>();

    ProductServiceImpl() {
        products.put("phone", 1000);
        products.put("computer", 2000);
        products.put("camera", 3000);
    }

    @Override
    public int getPrice(String productName) {
        return products.getOrDefault(productName, 0);
    }

    @Override
    public int getPrice(String productName, int discount) {
        return Optional.ofNullable(products.get(productName))
                       .map(price -> price * discount / 100)
                       .orElse(products.getOrDefault(productName, 0));
    }
}

在实现getPrice方法时,使用了Optional包装可选参数discount,这样就可以在方法内部判断是否有折扣参数传入,来返回相应的价格。

最佳实践

  1. Optional不是语言特性,而是库特性,因此使用Optional时,尽量避免在类的成员变量中存储Optional类型。在需要返回Optional类型的方法中使用Optional就足够了。
  2. 将Optional看作是一种特殊的容器类型,用来存储可能为空的值。
  3. 可以使用orElse方法和orElseGet方法设置默认值,但应尽量避免调用get()方法,而是使用orElse、orElseGet等方法来获取Optional中的值。
  4. 对于集合类型,可以使用stream()和filter()方法来过滤null值。

结论

Optional类非常适合于编写的API,特别是在公开API时,Optional可以明确属性是否可能为空,从而能够更好地告知使用者。

然而,在很多情况下,使用Optional并不一定会让代码更加优雅,更加简单和清晰。因此,在使用Optional时,需要慎重考虑。

本文标题为:详解JAVA中的OPTIONAL

基础教程推荐