java8中的Optional
Optional类主要解决空指针异常NullPointerException。
Optional 类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
创建Optional 对象
声明一个空的Optional
通过静态工厂方法Optional.empty(),创建一个空的Optional 对象,Optional中只有私有的构造方法,所以只能在其类中查找已经提供的创建方法,比如如下提供的一个容器中没有任何值的返回类型
public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
使用方法:
Optional<Car> optCar = Optional.empty();
依据一个非空值创建Optional
使用静态工厂方法Optional.of(T),依据一个非空值创建一个Optional对象:
public static <T> Optional<T> of(T value) { return new Optional<>(value); } Optional<String> optCar = Optional.of("sdfs");
由于这种方法创建时,会new Optional(T t),而在new的过程中,私有的构造函数对其传入的变量有检验:
private Optional(T value) { this.value = Objects.requireNonNull(value); }
当传入的参数为null时会爆NullPointerException
3. 可接受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(Integer 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(1, 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); System.out.println("optProd = " + optProd); System.out.println("optProdEmpty = " + optProdEmpty); System.out.println("optProdNull = " + optProdNull); System.out.println("optProdDefault = " + optProdDefault);
输出结果:
optProd = Optional[com.bjmashibing.system.baierhu.stream.Product@23ab930d] optProdEmpty = Optional.empty optProdNull = Optional.empty optProdDefault = Optional[com.bjmashibing.system.baierhu.stream.Product@23ab930d]
使用get获取值:只要是 Optional.empty,即Opention容器为null,就返回的是nullpointerException
2. orElse(T other)
public T orElse(T other) { return value != null ? value : other; }
调用该方法,如果Optional中为 null,则返回传入的值,否则会取出Optional中的具体值,这里可以做判空处理,即为null的时候如何处理问题
3. orElseGet(Supplier<? extends T> other)
orElseGet是orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时才执行调用。如果创建默认值是件耗时费力的工作,应该考虑采用这种方式(借此提升程序的性能),或者你需要非常确定某个方法仅在Optional为空时才进行调用,也可以考虑该方式(这种情况有严格的限制条件)
public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
Optional<String> empty = Optional.ofNullable(null); System.out.println(empty.orElse("There is no value present!")); System.out.println(empty.orElseGet(()->{return "No value";}));
执行结果:
There is no value present! 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")); //输出异常
java.lang.RuntimeException: ServiceException
at com.bjmashibing.system.baierhu.stream.OptionalTest.lambda$createOpentional$1(OptionalTest.java:20)
at java.util.Optional.orElseThrow(Optional.java:290)
at com.bjmashibing.system.baierhu.stream.OptionalTest.createOpentional(OptionalTest.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
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()); } );
个人感觉就是打印一些信息而已,无实际作用
6.使用 isPresent()判断Optional 容器中是否包含对象
判断容器中是否包含值,用此方法可避免NoSuchElementException 异常。
public boolean isPresent() { return value != null; }
7.使用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");
8.使用flatMap链接Optional对象
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);
这种写法可以不用多重判断,前面为null时每个过程中返回的都是一个null的Optional
注意:在域模型中使用Optional,是无法序列化的。所以可以写一个get方法返回Optional类型。
9.使用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(); }
Product prod = new Product(1, 1, new BigDecimal("15.5"), "面包", "零食");
Optional<Product>optProd=Optional.ofNullable(prod);
Optional<Product>pr=optProd.filter(item -> item.getNum() > 1);
System.out.println("pr = " + pr);
输出:pr = Optional.empty
总结:Optional类的方法
本文大多转载于:https://blog.csdn.net/u014231523/article/details/102649003
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步