在Java中对一个空对象进行操作时,便会抛出最常见的异常NullPointerException
。为了改善这个问题,Java 8中提供了一个java.util.Optional<T>
类型。Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()
方法会返回true,调用get()
方法会返回该对象。下面介绍Optional类的使用方法。 假如有一个像下面这样的类层次结构:
classDepartment{privateEmployeeemployee;publicDepartment(Employeeemployee){this.employee=employee;}EmployeegetEmployee(){returnemployee;}}classEmployee{privateGirlgirlFriend;publicEmployee(GirlgirlFriend){this.girlFriend=girlFriend;}GirlgetGirlFriend(){returngirlFriend;}}classGirl{privateStringname;publicGirl(Stringname){this.name=name;}StringgetName(){returnname;}}
部门Department
类包含一个员工employee
属性,类型为Employee
,员工Employee
类包含girlFriend
属性,类型为Girl
。假如现在要获取部门某个员工的女朋友,我们通常是这样获取的:
staticStringgetGirlFriendName(Departmentdepartment){if(department!=null){Employeeemployee=department.getEmployee();if(employee!=null){Girlgirl=employee.getGirlFriend();if(girl!=null){returngirl.getName();}return"单身汪";}return"没有员工";}return"部门为空";}
可以看到,在每次引用变量的属性时,都要先判断变量是否为空,如果不做该检查将可能导致NullPointerException
。下面我们将使用Optional来改善这种层层嵌套,啰嗦的代码。
创建Optional
创建一个Optional对象有好几种方式:
创建一个空的Optional
我们可以使用静态工厂方法Optional.empty
,创建一个空的Optional对象:
Optional<Department>department=Optional.empty();
根据非空值创建Optional
我们也可以使用静态工厂方法Optional.of
来创建一个非空对象的Optional对象:
Optional<Employee>optEmployee=Optional.of(employee);
如果employee为空,这段代码会立即抛出一个NullPointerException
。
创建可以为null的Optional
使用静态工厂方法Optional.ofNullable
,我们可以创建一个允许null值的Optional对象:
Optional<Employee>optEmployee=Optional.ofNullable(employee);
如果employee为空,对其调用get
方法将抛出NoSuchElementException
。
Optional方法
Optional类包含了许多方法,下面介绍这些方法的使用。
isPresent
顾名思义,如果值存在返回true,否则返回false。如:
Optional<Department>opt=Optional.ofNullable(department);if(opt.isPresent()){System.out.println(opt.get().getEmployee());}
get
如果Optional有值则将其返回,否则抛出NoSuchElementException
。下面举个抛出NoSuchElementException
的例子:
try{Optional.empty().get();}catch(Exceptione){e.printStackTrace();}
代码将捕获到 java.util.NoSuchElementException: No value present 异常。
ifPresent
如果Optional实例有值则为其调用Consumer
(函数描述符为T -> void
),否则不做处理。如:
girl.ifPresent(g->System.out.println("我有女朋友,名字是:"+g.getName()));
orElse
如果Optional实例有值则将其返回,否则返回orElse
方法传入的参数。如:
System.out.println(Optional.empty().orElse("Thereisnovaluepresent!"));
程序将输出There is no value present!
。
orElseGet
orElseGet
与orElse
方法类似,orElse
方法将传入的字符串作为默认值,而orElseGet
方法可以接受Supplier
(函数描述符为() -> T
)来生成默认值。如:
System.out.println(Optional.empty().orElseGet(()->"Thereisnovaluepresent!"));
程序同样输出There is no value present!
。
orElseThrow
如果有值则将其返回,否则抛出Supplier
接口创建的异常。如:
staticStringgetGirlFriendName(Departmentdepartment){if(department!=null){Employeeemployee=department.getEmployee();if(employee!=null){Girlgirl=employee.getGirlFriend();if(girl!=null){returngirl.getName();}return"单身汪";}return"没有员工";}return"部门为空";}0
代码将捕获到 java.util.NoSuchElementException: No value present 异常。
map
如果Optional有值,则对其执行调用Function
函数描述符为(T -> R
)得到返回值。如果返回值不为null,则创建包含Function
回值的Optional作为map方法返回值,否则返回空Optional。
staticStringgetGirlFriendName(Departmentdepartment){if(department!=null){Employeeemployee=department.getEmployee();if(employee!=null){Girlgirl=employee.getGirlFriend();if(girl!=null){returngirl.getName();}return"单身汪";}return"没有员工";}return"部门为空";}1
flatMap
如果有值,为其执行Function
函数返回Optional类型返回值,否则返回空Optional。flatMap
与map
方法类似,区别在于flatMap
中的Function
函数返回值必须是Optional。调用结束时,flatMap
不会对结果用Optional封装。如:
staticStringgetGirlFriendName(Departmentdepartment){if(department!=null){Employeeemployee=department.getEmployee();if(employee!=null){Girlgirl=employee.getGirlFriend();if(girl!=null){returngirl.getName();}return"单身汪";}return"没有员工";}return"部门为空";}2
filter
filter个方法通过传入Predicate
(函数描述符为T -> Boolean
)对Optional实例的值进行过滤。如:
staticStringgetGirlFriendName(Departmentdepartment){if(department!=null){Employeeemployee=department.getEmployee();if(employee!=null){Girlgirl=employee.getGirlFriend();if(girl!=null){returngirl.getName();}return"单身汪";}return"没有员工";}return"部门为空";}3
方法输出Jane
。
实战
介绍完Optional类的方法后,我们使用Optional改善一开始的代码:
staticStringgetGirlFriendName(Departmentdepartment){if(department!=null){Employeeemployee=department.getEmployee();if(employee!=null){Girlgirl=employee.getGirlFriend();if(girl!=null){returngirl.getName();}return"单身汪";}return"没有员工";}return"部门为空";}4
整洁而又不失逼格。