详解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,这样就可以在方法内部判断是否有折扣参数传入,来返回相应的价格。
最佳实践
- Optional不是语言特性,而是库特性,因此使用Optional时,尽量避免在类的成员变量中存储Optional类型。在需要返回Optional类型的方法中使用Optional就足够了。
- 将Optional看作是一种特殊的容器类型,用来存储可能为空的值。
- 可以使用orElse方法和orElseGet方法设置默认值,但应尽量避免调用get()方法,而是使用orElse、orElseGet等方法来获取Optional中的值。
- 对于集合类型,可以使用stream()和filter()方法来过滤null值。
结论
Optional类非常适合于编写的API,特别是在公开API时,Optional可以明确属性是否可能为空,从而能够更好地告知使用者。
然而,在很多情况下,使用Optional并不一定会让代码更加优雅,更加简单和清晰。因此,在使用Optional时,需要慎重考虑。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解JAVA中的OPTIONAL - Python技术站