文章目录
-
- 1. 简介
- 2. 常用方法
- 3. 基本使用
-
- 1. 创建 Optional 对象
- 2. 判断值是否存在
- 3. 非空表达式
- 4. 设置(获取)默认值
- 5. 获取值
- 6. 过滤值
- 7. 转换值
- 4. 案例
1. 简介
通常在日常的开发中,总是无法难以避免会出现空指针异常的错误。OPtional 类是一个容器类,代表一个值存在或者不存在,可以用来避免空指针异常。
2. 常用方法
- Optional.of(T t):静态方法,创建一个基于T的Optional实例,不能用该方法创建空实例,否则会报空指针异常
- Optional.empty():静态方法,创建一个空的Optional实例
- Optional.ofNullable(T t):静态方法,若t不为null,则创建基于 T 的 Optional实例,若 t 为null,则创建空的 Optional 实例
- optionl.isPresent():判断optional对象是否有值,有则返回 true,否则 false
- isEmpty():与 isPresent() 相反的结果
- optional.orElse(T t):若optional不为空,则返回optional实例子,否则返回T的Optional实例
- orElseGet(Supplier s):若对象包含值,则返回值,否则返回s获取的值
- map(Function f):若有值,返回操作后的Optional实例,否则返回空的Optional实例
- flatMap(Function mapper):与map类似,返回值是Optional
3. 基本使用
1. 创建 Optional 对象
- 使用静态方法 empty() 创建一个空的 Optional 对象
Optional<String> empty = Optional.empty(); System.out.println(empty); // 输出:Optional.empty
- 使用静态方法 of() 创建一个非空的 Optional 对象
传递给 of() 方法的参数必须是非空的,也就是说不能为 null,否则仍然会抛出 NullPointerExceptionOptional<String> opt = Optional.of("沉默王二"); System.out.println(opt); // 输出:Optional[沉默王二]
- 使用静态方法 ofNullable() 创建一个即可空又可非空的 Optional 对象
ofNullable() 方法内部有一个三元表达式,如果为参数为 null,则返回私有常量 EMPTY;否则使用 new 关键字创建了一个新的 Optional 对象——不会再抛出 NPE 异常了String name = null; Optional<String> optOrNull = Optional.ofNullable(name); System.out.println(optOrNull); // 输出:Optional.empty
2. 判断值是否存在
- 可以通过方法 isPresent() 判断一个 Optional 对象是否存在,如果存在,该方法返回 true,否则返回 false。取代了
obj != null
的判断Optional<String> opt = Optional.of("沉默王二"); System.out.println(opt.isPresent()); // 输出:trueOptional<String> optOrNull = Optional.ofNullable(null); System.out.println(opt.isPresent()); // 输出:false
- Java 11 后还可以通过方法 isEmpty() 判断与 isPresent() 相反的结果
Optional<String> opt = Optional.of("沉默王二"); System.out.println(opt.isEmpty()); // 输出:falseOptional<String> optOrNull = Optional.ofNullable(null); System.out.println(opt.isEmpty()); // 输出:true
3. 非空表达式
- Optional 类有一个非常现代化的方法:ifPresent(),允许我们使用函数式编程的方式执行一些代码,因此,我把它称为非空表达式。如果没有该方法的话,我们通常需要先通过 isPresent() 方法对 Optional 对象进行判空后再执行相应的代码:
Optional<String> optOrNull = Optional.ofNullable(null); if (optOrNull.isPresent()) { System.out.println(optOrNull.get().length()); }
- 有了 ifPresent() 之后,情况就完全不同了,可以直接将 Lambda 表达式传递给该方法,代码更加简洁,更加直观
Optional<String> opt = Optional.of("沉默王二"); opt.ifPresent(str -> System.out.println(str.length()));
- Java 9 后还可以通过方法 ifPresentOrElse(action, emptyAction) 执行两种结果,非空时执行 action,空时执行 emptyAction
Optional<String> opt = Optional.of("沉默王二"); opt.ifPresentOrElse(str -> System.out.println(str.length()), () -> System.out.println("为空"));
4. 设置(获取)默认值
有时候,我们在创建(获取) Optional 对象的时候,需要一个默认值,orElse() 和 orElseGet() 方法就派上用场了
- orElse() 方法用于返回包裹在 Optional 对象中的值,如果该值不为 null,则返回;否则返回默认值。该方法的参数类型和值得类型一致
String nullName = null; String name = Optional.ofNullable(nullName).orElse("沉默王二"); System.out.println(name); // 输出:沉默王二
- orElseGet() 方法与 orElse() 方法类似,但参数类型不同。如果 Optional 对象中的值为 null,则执行参数中的函数
从输出结果以及代码的形式上来看,这两个方法极其相似,这不免引起我们的怀疑,Java 类库的设计者有必要这样做吗?假设现在有这样一个获取默认值的方法,很传统的方式。String nullName = null; String name = Optional.ofNullable(nullName).orElseGet(()->"沉默王二"); System.out.println(name); // 输出:沉默王二
然后,通过 orElse() 方法和 orElseGet() 方法分别调用 getDefaultValue() 方法返回默认值public static String getDefaultValue() { System.out.println("getDefaultValue");return "沉默王二"; }
public static void main(String[] args) { String name = null;System.out.println("orElse");String name2 = Optional.ofNullable(name).orElse(getDefaultValue());System.out.println("orElseGet");String name3 = Optional.ofNullable(name).orElseGet(OrElseOptionalDemo::getDefaultValue); }
类名 :: 方法名
是 Java 8 引入的语法,方法名后面是没有 () 的,表明该方法并不一定会被调用
输出结果是相似的,没什么太大的不同,这是在 Optional 对象的值为 null 的情况下。假如 Optional 对象的值不为 null 呢?//结果 orElse getDefaultValueorElseGet getDefaultValue
public static void main(String[] args) { String name = "沉默王三";System.out.println("orElse");String name2 = Optional.ofNullable(name).orElse(getDefaultValue());System.out.println("orElseGet");String name3 = Optional.ofNullable(name).orElseGet(OrElseOptionalDemo::getDefaultValue); }
orElseGet() 没有去调用 getDefaultValue()。也就是说,使用 orElseGet() 的性能更好。//结果 orElse getDefaultValueorElseGet
5. 获取值
- 直观从语义上来看,get() 方法才是最正宗的获取 Optional 对象值的方法,但很遗憾,该方法是有缺陷的,因为假如 Optional 对象的值为 null,该方法会抛出 NoSuchElementException 异常。这完全与我们使用 Optional 类的初衷相悖
public class GetOptionalDemo { public static void main(String[] args) { String name = null;Optional<String> optOrNull = Optional.ofNullable(name);System.out.println(optOrNull.get());} }
尽管抛出的异常是 NoSuchElementException 而不是 NPE,但在我们看来,显然是在“五十步笑百步”。建议 orElseGet() 方法获取 Optional 对象的值。//结果 Exception in thread "main" java.util.NoSuchElementException: No value presentat java.base/java.util.Optional.get(Optional.java:141)at com.cmower.dzone.optional.GetOptionalDemo.main(GetOptionalDemo.java:9)
6. 过滤值
-
Optional 类的 filter() 方法可以用来过滤值
public class FilterOptionalDemo { public static void main(String[] args) { String password = "12345";Optional<String> opt = Optional.ofNullable(password);System.out.println(opt.filter(pwd -> pwd.length() > 6).isPresent());} }
filter() 方法的参数类型为 Predicate,也就是说可以将一个 Lambda 表达式传递给该方法作为条件,如果表达式的结果为 false,则返回一个 EMPTY 的 Optional 对象,否则返回过滤后的 Optional 对象
在上例中,由于 password 的长度为 5 ,所以程序输出的结果为 false。假设密码的长度要求在 6 到 10 位之间,那么还可以再追加一个条件
Predicate<String> len6 = pwd -> pwd.length() > 6; Predicate<String> len10 = pwd -> pwd.length() < 10;password = "1234567"; opt = Optional.ofNullable(password); boolean result = opt.filter(len6.and(len10)).isPresent(); System.out.println(result); //输出:true
7. 转换值
我们可以增加密码的强度,比如说密码不能是“password”,这样的密码太弱了
-
map() 方法可以按照一定的规则将原有 Optional 对象转换为一个新的 Optional 对象,原有的 Optional 对象不会更改
public class OptionalMapDemo { public static void main(String[] args) { String name = "沉默王二";Optional<String> nameOptional = Optional.of(name);Optional<Integer> intOpt = nameOptional.map(String::length);System.out.println( intOpt.orElse(0));} }
在上面这个例子中,map() 方法的参数 String::length,意味着要 将原有的字符串类型的 Optional 按照字符串长度重新生成一个新的 Optional 对象,类型为 Integer
搞清楚了 map() 方法的基本用法后,可以把 map() 方法与 filter() 方法结合起来用,前者用于将密码转化为小写,后者用于判断长度以及是否是“password”
public class OptionalMapFilterDemo { public static void main(String[] args) { String password = "PAssworD";Optional<String> opt = Optional.ofNullable(password);Predicate<String> len6 = pwd -> pwd.length() > 6;Predicate<String> len10 = pwd -> pwd.length() < 10;Predicate<String> eq = pwd -> pwd.equals("password");boolean result = opt.map(String::toLowerCase).filter(len6.and(len10 ).and(eq)).isPresent();System.out.println(result); //输出:true} }
4. 案例
class Employee {
private String name;private int age;private double basicSalary;private double dealTotalPrice;public String getName() {
return name;}public void setName(String name) {
this.name = name;}public int getAge() {
return age;}public void setAge(int age) {
this.age = age;}public double getBasicSalary() {
return basicSalary;}public void setBasicSalary(double basicSalary) {
this.basicSalary = basicSalary;}public double getDealTotalPrice() {
return dealTotalPrice;}public void setDealTotalPrice(double dealTotalPrice) {
this.dealTotalPrice = dealTotalPrice;}@Overridepublic String toString() {
return "Employee{" +"name='" + name + '\'' +", age=" + age +", basicSalary=" + basicSalary +", dealTotalPrice=" + dealTotalPrice +'}';}public Employee(String name, int age, double basicSalary) {
this.name = name;this.age = age;this.basicSalary = basicSalary;}
}
public static void main(String[] args) {
//testOptionalOF(); 抛出异常//testOptionalEmpty(); 抛出异常//testNull(); 抛出异常testOptionalOrElse();}/*** 测试OptionalOF的null*/public static void testOptionalOF() {
Optional<Employee> optional = Optional.of(null);//不可以用 of 方法创建空对象// 返回 java.lang.NullPointerExceptionSystem.out.println(optional.get());}/*** 测试OptionalEmpty*/public static void testOptionalEmpty() {
// 构建空的OptionalOptional<Employee> optional = Optional.empty();// 返回 java.util.NoSuchElementException: No value presentSystem.out.println(optional.get());}/*** 测试OptionalOfNull*/public static void testNull() {
Optional<Employee> optional = Optional.ofNullable(null);// 返回 java.util.NoSuchElementException: No value presentSystem.out.println(optional.get());}/*** 测试OptionalOrelse,map,FlatMap*/public static void testOptionalOrElse() {
// 创建空的Optional对象Optional<Employee> optional = Optional.ofNullable(null);// 这里因为Optional对象为空,所以将会返回新建的李四对象Employee employee = optional.orElse(new Employee("李四", 25, 20001D));// 打印李四的姓名Optional<String> s = optional.map(Employee::getName);// (e) -> e.getName()Optional<String> s1 = optional.flatMap((e) -> Optional.of(e.getName()));System.out.println(s1);System.out.println(s);System.out.println(employee);Employee employee1 = optional.orElseGet(Employee::new);System.out.println(employee1);}
}//结果
Optional.empty //s1
Optional.empty //s
Employee{
name='李四', age=25, basicSalary=20001.0, dealTotalPrice=0.0} //employee
Employee{
name='null', age=0, basicSalary=0.0, dealTotalPrice=0.0} //employee1