空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
例如:
// 参数不能是null
Optional<Integer> optional1 = Optional.of(1);
// 参数可以是null
Optional<Integer> optional2 = Optional.ofNullable(null);
// 参数可以是非null
Optional<Integer> optional3 = Optional.ofNullable(2);
isPresent():判断值是否存在
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// isPresent判断值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);
orElse(value):如果optional对象保存的值不是null,则返回原来的值,否则返回value
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// orElse
System.out.println(optional1.orElse(1000) == 1);// true
System.out.println(optional2.orElse(1000) == 1000);// true
orElseGet(Supplier supplier):功能与orElse一样,只不过orElseGet参数是一个对象
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
System.out.println(optional1.orElseGet(() -> {
return 1000;
}) == 1);//true
System.out.println(optional2.orElseGet(() -> {
return 1000;
}) == 1000);//true
orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似Guava的Precoditions
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
optional1.orElseThrow(()->{throw new IllegalStateException();});
try
{
// 抛出异常
optional2.orElseThrow(()->{throw new IllegalStateException();});
}
catch(IllegalStateException e )
{
e.printStackTrace();
}
map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
Optional<String> str1Optional = optional1.map((a) -> "key" + a);
Optional<String> str2Optional = optional2.map((a) -> "key" + a);
System.out.println(str1Optional.get());// key1
System.out.println(str2Optional.isPresent());// false
Optional最大的好处是简化if-else和更优雅的去除多层if嵌套。
实例: 定义Person类,一个人持有一个汽车的引用。
class Car{
private String brand;
private String color;
public Car() {
}
public Car(String brand, String color) {
this.brand = brand;
this.color = color;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
class Person {
private String name;
private String gender;
private int age;
private Car car;
public Person() {
}
public Person(String name, String gender, int age,Car car) {
this.name = name;
this.gender = gender;
this.age = age;
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public String introduce(){
return "hello,my name is:" + this.name + ",I am " + this.age + " years old!";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
}
在OptionalDemo中定义有sayHello方法,判断person对象如果不为空则获得其自我介绍的字符串,并打印,否则输出"unknown".传统的java代码实现方式如下:
public class OptionalDemo{
public static void sayHello(Person p){
if(p!=null){
System.out.println(p.introduce());
}else{
System.out.println("unknown");
}
}
}
主方法测试,运行结果如下:
public static void main(String[] args) throws Exception {
Person p = new Person("张三","男",30,new Car("BMW","red"));
sayHello(p);
}
运行结果如下:

如果给sayHello方法传入null对象,运行结果如下:
public static void main(String[] args) throws Exception {
Person p = null;
sayHello(p);
}

上面的sayHello方法,使用Optional可以大大精简if-else.实现如下:
public static void sayHello(Person p){
Optional<Person> person = Optional.ofNullable(p);
//写法一:
//System.out.println(person.map(per -> per.introduce()).orElse("unknown"));
//写法二:
System.out.println(person.map(Person::introduce).orElse("unknown"));
}
实现效果与传统if-else完全相同。
再例如:在getCarBrand方法中获取这个人持有的汽车品牌。传统实现方式如下:
public static String getCarBrand(Person p) throws Exception{
if(p!=null){
Car car = p.getCar();
if(car!=null){
return car.getBrand();
}
}
throw new Exception("Person or Car is null!");
}
在主方法中测试,传入一个汽车属性为null的Person对象。
public static void main(String[] args) throws Exception {
Person p = new Person("张三","男",30,null);
System.out.println(getCarBrand(p));
}
运行结果如下:

使用Optional可以优雅的去除多重if-else语句,实现代码如下:
public static String getCarBrand(Person p) throws Exception{
Optional<Person> person = Optional.ofNullable(p);
return person.map(Person::getCar).map(Car::getBrand).orElseThrow(()->new Exception("Person or Car is null!"));
//或者下面的写法
//return person.map(per->per.getCar()).map(c->c.getBrand()).orElseThrow(()->new Exception("Person or Car is null!"));
}
实现效果与传统多重if-else完全相同。