Optional类主要解决空指针异常NullPointerException。
Optional 类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
创建Optional 对象
1. 声明一个空的Optional
通过静态工厂方法Optional.empty(),创建一个空的Optional 对象
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
比如:
Optional<Car> optCar = Optional.empty();
2. 依据一个非空值创建Optional
使用静态工厂方法Optional.of(T),依据一个非空值创建一个Optional对象:
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
比如:
Optional<Car> optCar = Optional.of(car);
如果car是一个null,这段代码会立即抛出一个NullPointerException.
3. 可接受null的Optional
使用静态工厂方法Optional.ofNullable(T),可以创建一个允许null值的Optional 对象
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
比如:
Optional<Car> optCar = Optional.ofNullable(car);
如果car是null,那么得到的Optional对象就是个空对象。
读取Optional实例中的变量值
1. get()
如果此Optional中存在值,则返回该值,否则抛出NoSuchElementException。
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
比如:
Product构造函数(用于后面示例)
public Product(Long id, Integer num, BigDecimal price, String name, String category) {
this.id = id;
this.num = num;
this.price = price;
this.name = name;
this.category = category;
}
Product prod = new Product(1L, 1, new BigDecimal("15.5"), "面包", "零食");
Optional<Product> optProd = Optional.of(prod);
Optional<Product> optProdEmpty = Optional.empty();
Optional<Product> optProdNull = Optional.ofNullable(null);
Optional<Product> optProdDefault = Optional.ofNullable(prod);
//返回Product对象
System.out.println(optProd.get());
System.out.println(optProdDefault.get());
//抛异常:Exception in thread "main" java.util.NoSuchElementException: No value present
System.out.println(optProdEmpty.get());
System.out.println(optProdNull.get());
####2. orElse(T other)
如果Optional中存在值,则返回该值,否则返回设定的默认值。
public T orElse(T other) {
return value != null ? value : other;
}
比如:
//输出默认值
System.out.println(optProdEmpty.orElse(prod));
3. orElseGet(Supplier<? extends T> other)
orElseGet是orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时才执行调用。如果创建默认值是件耗时费力的工作,应该考虑采用这种方式(借此提升程序的性能),或者你需要非常确定某个方法仅在Optional为空时才进行调用,也可以考虑该方式(这种情况有严格的限制条件)
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
比如:
System.out.println(optProdEmpty.orElse(new Product()));
System.out.println(optProdEmpty.orElseGet(Product::new));
//String类型
Optional<String> empty = Optional.ofNullable(null);
System.out.println(empty.orElse("There is no value present!"));
System.out.println(empty.orElseGet(() -> "No value"));
4. orElseThrow(Supplier<? extends X> exceptionSupplier)
orElseThrow和get方法非常类似,如果值存在,返回该值。如果Optional对象为空时都会抛出一个异常,但是使用orElseThrow你可以定制希 望抛出的异常类型。
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
比如:
optProdEmpty.orElseThrow(() -> new ServiceException("ServiceException"));
//输出异常
Exception in thread "main" com.backend.business.ServiceException: ServiceException
5. ifPresent(Consumer<? super T> consumer)
在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
比如:
optProd.ifPresent(System.out::println);
optProd.ifPresent(item -> {
System.out.println(item.getName());
}
);
使用 isPresent()判断Optional 容器中是否包含对象
判断容器中是否包含值,用此方法可避免NoSuchElementException 异常。
public boolean isPresent() {
return value != null;
}
比如:
//注意这里取反
if(! optProdEmpty.isPresent()) {
System.out.println("optProdEmpty is null");
}
if(optProd.isPresent()) {
System.out.println("optProd is not null");
}
使用map从Optional对象中提取和转换值
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
比如:获取name值
//prodEmpty对象不知道是否为null
String name = null;
if(null != prodEmpty) {
name = prodEmpty.getName();
}else {
name = "test";
}
//使用map
Optional<Product> optProd2 = Optional.ofNullable(prodEmpty);
name = optProdEmpty.map(Product::getName).orElse("test");
使用flatMap链接Optional对象
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
比如:Product中包含Brand类,Brand有name属性.获取一个商品的品牌名
public class Product {
private Brand brand;
public Brand getBrand() {
return brand;
}
public void setBrand(Brand brand) {
this.brand = brand;
}
public Optional<Brand> getBrandAsOptional(){
return Optional.ofNullable(brand);
}
}
public class Brand {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Product prod = new Product(1L, 1, new BigDecimal("15.5"), "面包", "零食");
Brand brand = new Brand();
brand.setName("达利园");
prod.setBrand(brand);
String brandName = optProd.flatMap(Product::getBrandAsOptional).map(Brand::getName).orElse("other");
System.out.println(brandName);
注意:在域模型中使用Optional,是无法序列化的。所以可以写一个get方法返回Optional类型。
使用filter剔除特定的值
filter方法接受一个谓词作为参数。如果Optional对象的值存在,并且它符合谓词的条件, filter方法就返回其值;否则它就返回一个空的Optional对象。
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
比如:
optProd.filter(item -> item.getNum() > 1);
总结:Optional类的方法
方法 | 描述 |
---|---|
empty | 返回一个空的Optional 实例 |
of | 将指定值用Optional封装之后返回,如果该值为null,则抛出一个NullPointerException 异常 |
ofNullable | 将指定值用 Optional 封装之后返回,如果该值为 null,则返回一个空的 Optional 对象 |
filter | 如果值存在并且满足提供的谓词,就返回包含该值的Optional对象;否则返回一个空的Optional 对象 |
map | 如果值存在,就对该值执行提供的 mapping函数调用 |
flatMap | 如果值存在,就对该值执行提供的 mapping函数调用,返回一个 Optional 类型的值,否则就返 回一个空的 Optional 对象 |
get | 如果该值存在,将该值用Optional封装返回,否则抛出一个NoSuchElementException异常 |
orElse | 如果有值则将其返回,否则返回一个默认值 |
orElseGet | 如果有值则将其返回,否则返回一个由指定的 Supplier接口生成的值 |
orElseThrow | 如果有值则将其返回,否则抛出一个由指定的 Supplier接口生成的异常 |
ifPresent | 如果值存在,就执行使用该值的方法调用,否则什么也不做 |
isPresent | 如果值存在就返回true,否则返回 false |
相关链接:
java8中map新增方法详解
java8中Stream的使用
java8中Collection新增方法详解
java8中Collectors的方法使用实例
java8中常用函数式接口
java8中的方法引用和构造函数引用
java8中的Collectors.groupingBy用法
java8中的Optional用法
java8中的日期和时间API