使用Java8中的Optional类来消除代码的Null检查

972 阅读3分钟

使用Java8中的Optional类来消除代码的Null检查

Optional类是Java 8新增的一个类,用以解决程序中常见的NullPointerException异常问题。本以及如何用它消除代码中的null检查。

避免使用null进行检查

对于NullPointerException异常,通常都会在异常出现的地方加上if代码块来判断值不为空,比如下面的代码:

public void bindUserToRole(User user){
    if(User != null){
        String roleId = user.getRoleId();
        
        if(roleId != null){
            Role role = roleDao.findOne(roleId);
            
            if(role != null){
                role.setUserId(user.getUserId());
                roleDao.save(role);
            }
        }
    }
}

使用Optional进行判断

java.util.Optional类是一个封装了Optional值的容器对象,Optional值可以为null,如果值存在,调用isPresent()方法返回true,调用get()方法可以获取值。

创建Optional对象

实例化optional对象的方法:

  1. empty() :创建一个没有值的Optional对象
Optional<String> emptyOpt = Optional.empty();

如果对emptyOpt变量调用isPresent()方法会返回false,调用get()方法抛出NullPointerException异常。

  1. of()创建一个非空的Optional对象

    String str = "Hello";
    Optional<String> notNullOpt = Optional.of(str)
    
  2. ofNullable() 方法接收一个可以为null的值:

    Optional<String> nullableOpt = Optional.ofNullable(str);
    

提取Optional对象中的值

// 通常
String roleId = null;
if(user != null){
    roleId = user.getRoleId();
}
// Optional
Optional<User> userOpt = Optional.ofNullable(user);
Optional<String> roleIdOpt = userOpt.map(User::getRoleId);

使用orElse()方法获取值

  1. orElse():如果有值就返回,否则返回一个给定的值作为默认值

    String str = "hello";
    Optional<String> strOpt = Optional.of(str);
    String orElseResult = strOpt.orElse("hello word");
    
  2. orElseGet():与orElse()方法作用类似,区别在于生成默认值的方式不同。该方法接受一个Supplier<? extends T>函数式接口参数,用于生成默认值

    String orElseGet = strElseGet(()->"hello"
    )
    
  3. orElseThrow():与前面介绍的get()方法类似,当值为null时调用这两个方法都会抛出NullPointerException异常,区别在于该方法可以指定抛出的异常类型。

    String orElseThrow = strOpt.orElseThrow(
        ()-> new IllegalArgumentException("Argument 'str' cannot be null or blank.")
    )
    
  4. ifPresent(),该方法接收一个Consumer<? super T>函数式接口,一般用于将信息打印到控制台

    Optional<String> strOpt = Optional.of("hellp");
    strOpt.ifPresent(System.out::println)
    
  5. filer() 可用于判断Optional对象是否满足给定条件,一般用于条件过滤:

    Optional<String> optional = Optional.of("newhzong@qq.com");
    optional = optional.filter(str - >str.contains("164"));
    

    如果filter()方法中的Lambda表达式成立,filter()方法会返回当前Optional对象值

新的思维方式处理null值,Java 8提倡函数式编程,新增的许多API都可以用函数式编程表示,建议:

  1. 尽量避免在程序中直接调用Optional对象的get()和isPresent()方法;
  2. 避免使用Optional类型声明实体类的属性;
正确创建Optional对象

// 使用of与ofNullable,如果确定一个对象不能为空,应该使用of(),否则使用ofNullable()
public static void method(Role role){
     // 当Optional的值通过常量获得或者通过关键字new初始化,可以直接使用of()方法
    Optional<String> strOpt = Optional.of("hello");
    Optional<User> userOpt = Optional.of(new User());
    // 方法参数中role值不确定是否为null,使用ofNullable()方法创建
     Optional<Role> roleOpt = Optional.ofNullable(role);
}

orElse()方法的使用
// 原始方法
str != null ? str: "hello";

// 使用Optional类型
return strOpt.orElse("hello")
简化if-else

User user = ...
if(User != null){
	String userName = user.getUserName();
}
if( userName != null){
	userName.toUpperCase();
}else{
return null;
}
User user = new User();
Optional<User> userOpt = Optional.ofNullable(user);
userOpt.map(User::getUserName)
    .map(String:: toUpperCase)
    .orElse(null);