Optional
如果一个方法返回一个Object,那么我们在使用的时候总是要判断一下返回的结果是否为空,一般是这样的形式:
if (a != null) { //do something... }
但是简单的情况还好,如果复杂的情况下每一个都要去检查非常麻烦,而且写出来的代码也不好看、很臃肿,但是如果不检查就很容易遇到NullPointerException
, Java8中的Optional就是为此而设计的。
Optional一般使用在方法的返回值中,如果使用Optional来包装方法的返回值,这就表示方法的返回值可能为null
,需要使用Optional提供的方法来检查,如果为null,还可以提供一个默认值。
//创建Optional对象 Optional<String> opt = Optional.empty(); //依据一个非空值创建Optional Optional<String> opt = Optional.of("hello"); //可接受null的Optional Optional<String> opt = Optional.ofNullable(null);
除了以上这些方法外,Optional还提供了以下方法:
方法 | 描述 |
---|---|
empty | 返回一个空的Optional实例 |
filter | 如果值存在并且满足提供的谓词,就返回包括该值的Optional对象;否则返回一个空的Optional对象 |
flatMap | 如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象 |
get | 如果该值存在,将该值用Optional封装返回,否则抛出一个NoSuchElementException异常 |
ifPresent | 如果值存在,就执行使用该值的方法调用,否则返回false |
isPresent | 如果值存在就返回true,否则返回false |
map | 如果值存在,就对该值执行提供的mapping函数调用 |
of | 将指定值用Optional封装之后返回,如果该值为null,抛出一个NullPointerException异常 |
ofNullable | 将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象 |
orElse | 如果有值则将其返回,否则返回一个默认值 |
orElseGet | 如果有值则将其返回,否则返回一个由指定的Supplier接口生成的值 |
orElseThrow | 如果有值则将其返回,否则抛出一个由指定的Supplier接口生成的异常 |
of
为非null的值创建一个Optional。通过工厂方法创建Optional类。注意:创建对象时传入的参数不能为null。否则抛出NullPointerException 。
//调用工厂方法创建Optional实例 Optional<String> name = Optional.of("Name"); //传入参数为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()) { System.out.println(name.get()); // 输出结果 }
示例2
// 推荐 user.ifPresent(System.out::println); // 不推荐 if (user.isPresent()) { System.out.println(user.get()); }
ifPresent
如果Optional实例有值则为其调用consumer,否则不做处理
要理解ifPresent方法,首先需要了解Consumer类。简答地说,Consumer类包含一个抽象方法。该抽象方法对传入的值进行处理,但没有返回值。Java8支持不用接口直接通过lambda表达式传入参数。
如果Optional实例有值,调用ifPresent()可以接受接口段或lambda表达式。类似下面的代码:
// ifPresent方法接受lambda表达式作为参数。 // lambda表达式对Optional的值调用consumer进行处理。 Optional<String> name = Optional.of("Name"); name.ifPresent(value -> System.out.println("The length of the value is: " + value.length())); System.out.println(name.get()); // 运行结果 The length of the value is: 4 Name
示例2
Optional<Student> student = Optional.of(new Student("Anson",100)); System.out.println(student.get().getName()); // Anson student.ifPresent(stu->stu.setName("听风")); System.out.println(student.get().getName()); // 听风
get
如果Optional有值则将其返回,否则抛出NoSuchElementException。
Optional empty = Optional.ofNullable(null); System.out.println(empty.get()); // 异常内容 Exception in thread "main" java.util.NoSuchElementException: No value present
orElse 存在即返回, 无则提供默认值
如果有值则将其返回,否则返回指定的其它值。
如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。示例如下:
Optional<String> name = Optional.of("听风"); Optional<String> empty = Optional.empty(); // 如果值不为null,orElse方法返回Optional实例的值。 // 如果为null,返回传入的消息。 System.out.println(empty.orElse("There is no value present!")); // There is no value present! System.out.println(name.orElse("There is some value!")); // 听风
orElseGet 存在即返回, 无则由函数来产生
orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。示例如下:
return user.orElseGet(() -> fetchAUserFromDatabase()); // 而不要 return user.isPresent() ? user: fetchAUserFromDatabase();
orElseThrow
如果有值则将其返回,否则抛出supplier接口创建的异常。
在orElseGet方法中,我们传入一个Supplier接口。然而,在orElseThrow中我们可以传入一个lambda表达式或方法,如果值不存在来抛出异常。示例如下:
try { //orElseThrow与orElse方法类似。与返回默认值不同, //orElseThrow会抛出lambda表达式或方法生成的异常 empty.orElseThrow(ValueAbsentException::new); } catch (Throwable ex) { //输出: No value present in the Optional instance System.out.println(ex.getMessage()); }
ValueAbsentException定义如下:
public class ValueAbsentException extends Throwable { public ValueAbsentException() { super(); } public ValueAbsentException(String msg) { super(msg); } @Override public String getMessage() { return "No value present in the Optional instance"; } }
map
如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
map方法用来对Optional实例的值执行一系列操作。通过一组实现了Function接口的lambda表达式传入操作。
map方法示例如下:
// map方法执行传入的lambda表达式参数对Optional实例的值进行修改。为lambda表达式的返回值创建新的Optional实例作为map方法的返回值。 Optional<String> name = Optional.of("hello"); Optional<String> upperName = name.map(value -> value.toUpperCase()); System.out.println(upperName.orElse("No value found")); // HELLO
flatMap
如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。
参照map函数,使用flatMap重写的示例如下:
Optional<String> name = Optional.of("hello"); Optional<String> upperName = name.flatMap(value -> Optional.of(value.toUpperCase())); System.out.println(upperName.orElse("No value found")); // HELLO
filter
filter个方法通过传入限定条件对Optional实例的值进行过滤。
描述:如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
读到这里,可能你已经知道如何为filter方法传入一段代码。是的,这里可以传入一个lambda表达式。对于filter函数我们应该传入实现了Predicate接口的lambda表达式。
现在我来看看filter的各种用法,下面的示例介绍了满足限定条件和不满足两种情况:
Optional<String> name = Optional.of("helloWorld"); Optional<String> longName = name.filter(v -> v.length() > 6); System.out.println(longName.orElse("名字长度小于6")); // 输出:helloWorld Optional<String> anotherName = Optional.of("程序喵"); Optional<String> shortName = anotherName.filter(v -> v.length() > 6); System.out.println(shortName.orElse("名字长度小于6")); // 输出:名字长度小于6
Map其他示例
当 user.isPresent() 为真, 获得它关联的 orders , 为假则返回一个空集合时, 我们用上面的 orElse , orElseGet 方法都乏力时, 那原本就是 map 函数的责任, 我们可以这样一行
return user.map(u -> u.getOrders()).orElse(Collections.emptyList()) //上面避免了我们类似 Java 8 之前的做法 if(user.isPresent()) { return user.get().getOrders(); } else { return Collections.emptyList(); }
map 是可能无限级联的, 比如再深一层, 获得用户名的大写形式
return user.map(u -> u.getUsername()) .map(name -> name.toUpperCase()) .orElse(null);
这要搁在以前, 每一级调用的展开都需要放一个 null 值的判断
User user = ..... if(user != null) { String name = user.getUsername(); if(name != null) { return name.toUpperCase(); } else { return null; } } else { return null; }
针对这方面 Groovy 提供了一种安全的属性/方法访问操作符 ?.
user?.getUsername()?.toUpperCase();
Swift 也有类似的语法, 只作用在 Optional 的类型上.
未经允许请勿转载:程序喵 » Java8新特性:Optional类深度解析