学习与使用 Java 中的 Optional教程详解
前言:
Optional 被定义为一个简单的容器,主要解决的问题是开发中常见的空指针异常,本质上这是一个包含有可选值的包装类,在Java 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java 8中,不推荐你返回null而是返回Optional。
我们从一个简单的用例开始。
User user = ... if (user != null) { String userName = user.getUserName(); if (userName != null) { return userName.toUpperCase(); } else { return null; } } else { return null; }
从以上可以看出,对象字段比较多很容易就变得冗长,难以维护,我相信学完Optiona类完全可以简化这段代码。
Optional方法快速查看文档
Optional类的常用方法详解
of
为非null的值创建一个Optional。of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。
//调用工厂方法创建Optional实例 Optional<String> name = Optional.of("Hello world "); //传入参数为null,抛出NullPointerException. Optional<String> someNull = Optional.of(null);
ofNullable
为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况。
//下面创建了一个不包含任何值的Optional实例 //例如,值为'null' Optional empty = Optional.ofNullable(null);
isPresent
非常容易理解,如果值存在返回true,否则返回false。
//isPresent方法用来检查Optional实例中是否包含值 if (name.isPresent()) { //在Optional实例内调用get()返回已存在的值 System.out.println(name.get());//输出Sanaulla }
get
如果Optional有值则将其返回,否则抛出NoSuchElementException。
//执行下面的代码会输出:No value present try { //在空的Optional实例上调用get(),抛出NoSuchElementException System.out.println(empty.get()); } catch (NoSuchElementException ex) { System.out.println(ex.getMessage()); }
ifPresent
如果Optional实例有值则为其调用consumer,否则不做处理。
//ifPresent方法接受lambda表达式作为参数。 //lambda表达式对Optional的值调用consumer进行处理。 name.ifPresent((value) -> { System.out.println("The length of the value is: " + value.length()); });
orElse
如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。
//如果值不为null,orElse方法返回Optional实例的值。 //如果为null,返回传入的消息。 //输出:There is no value present! System.out.println(empty.orElse("There is no value present!")); //输出:Sanaulla System.out.println(name.orElse("There is some value!"));
orElseGet
orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。
//orElseGet与orElse方法类似,区别在于orElse传入的是默认值, //orElseGet可以接受一个lambda表达式生成默认值。 //输出:Default Value System.out.println(empty.orElseGet(() -> "Default Value")); //输出:Sanaulla System.out.println(name.orElseGet(() -> "Default Value"));
orElseThrow
如果有值则将其返回,否则抛出supplier接口创建的异常。
try { //orElseThrow与orElse方法类似。与返回默认值不同, //orElseThrow会抛出lambda表达式或方法生成的异常 empty.orElseThrow(ValueAbsentException::new); } catch (Throwable ex) { //输出: No value present in the Optional instance System.out.println(ex.getMessage()); }
map
如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
//map方法执行传入的lambda表达式参数对Optional实例的值进行修改。 //为lambda表达式的返回值创建新的Optional实例作为map方法的返回值。 Optional<String> upperName = name.map((value) -> value.toUpperCase()); System.out.println(upperName.orElse("No value found"));
flatMap
如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。而map方法的mapping函数返回值可以是任何类型T,调用结束时,map一定会对结果用Optional封装,如果mapper返回值是Optional,那么map就会将结果封装成Optional<Optional>类型。
Optional<String> name = Optional.ofNullable("Walker"); Optional<String> upperName = name.flatMap((value) -> Optional.of(value.toUpperCase())); System.out.println(upperName.orElse("No value found"));//输出WALKER
filter
filter方法通过传入限定条件对Optional实例的值进行过滤。如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
//filter方法检查给定的Option值是否满足某些条件。 //如果满足则返回同一个Option实例,否则返回空Optional。 Optional<String> longName = name.filter((value) -> value.length() > 6); System.out.println(longName.orElse("The name is less than 6 characters"));//输出Sanaulla //另一个例子是Optional值不满足filter指定的条件。 Optional<String> anotherName = Optional.of("Sana"); Optional<String> shortName = anotherName.filter((value) -> value.length() > 6); //输出:name长度不足6字符 System.out.println(shortName.orElse("The name is less than 6 characters"));
empty
方法用于创建一个没有值的Optional对象
Optional<String> emptyOpt = Optional.empty();
总结:
Optional 是 Java 语言的有益补充 —— 它旨在减少代码中的 NullPointerExceptions,虽然还不能完全消除这些异常。
它也是精心设计,自然融入 Java 8 函数式支持的功能。总的来说,这个简单而强大的类有助于创建简单、可读性更强、比对应程序错误更少的程序。