9. Java8新特性-Optional

主要内容:

  1. 为什么要避免null引用
  2. 从null到Optional
  3. 读取Opational中可能值的几种方法
null引用的由来

1965年,英国一位名为Tony Hoare的计算机科学家在设计ALGOL W语言时提出了null引用的想法。Hoare选择null引用这种方式,“只
是因为这种方法实现起来非常容易”。

如何减少NullPointerException

通常可以采用防御式编程来减少NullPointerException。 如:

public String getCarInsuranceName(Person person) { 
 if (person != null) { 
 	Car car = person.getCar(); 
 	if (car != null) { 
 		Insurance insurance = car.getInsurance(); 
 		if (insurance != null) { 
 			return insurance.getName(); 
		 } 
 	} 
 } 
 
 return "Unknown"; 
}

很明显,这样的方式牺牲了代码的可读性。我们需要更优雅的解决方案。

Optional<T>入门

汲取Haskell和Scala的灵感,Java 8中引入了一个新的类java.util.Optional。这是一个封装Optional值的类。当变量存在时,Optional类只是对对象的简单封装,当变量不存在时,会封装一个空的Optional对象,由Optional.empty()返回。

  1. 声明一个空的Optional
    Optional<Car> optional = Optional .empty();

  2. 依据一个非空值创建Optional
    Optional<Car> optional = Optional .of(car);

  3. 可接受null的Optional
    Optional<Car> optCar = Optional.ofNullable(car);
    此种情况下,car可为null,为null时,实际返回的是Optional.empty()

使用map从Optional对象中提取和转换值

示例:

Optional<Insurance> optInsurance = Optional.ofNullable(insurance); 
Optional<String> name = optInsurance.map(Insurance::getName);
使用flatMap链接Optional对象
public String getCarInsuranceName(Optional<Person> person) { 
   return person.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unknown"); 
}

这样的写法不需要增加额外分支,也不会增加代码的复杂性。

获取Optional对象值
  1. get()
    是最简单也最不安全的方法。如果变量存在返回变量,否则抛出NoSuchElementException。
  2. orElse(T other)
    如果变量存在返回变量,不存在返回other。
  3. orElseGet(Supplier<? extends T> other)
    是orElse的延迟调用版
  4. orElseThrow(Supplier exceptionSupplier)
    当值为null时,可以定制抛出的异常
  5. ifPresent(Consumer<? super T> consumer)
    当值存在时执行消费,否则不执行
使用filter剔除特定的值

filter可接受一个谓词,当且仅当值不为空,且满足谓词时才继续执行,否则返回Optional.empty()。 示例:

Optional<Insurance> optInsurance = ...; 
optInsurance.filter(insurance -> "CambridgeInsurance".equals(insurance.getName())) .ifPresent(x -> System.out.println("ok"));

综合示例

@Slf4j
public class OptionalSample {

    public static void main(String[] args) {
        Properties props = new Properties();
        props.setProperty("a", "5");
        props.setProperty("b", "true");
        props.setProperty("c", "-3");

        int i = getPropertyTraditional(props, "b");
        int j = getPropertyOptional(props, "b");

        log.info("===> i : {}", i);
        log.info("===> j : {}", j);
    }


    /**
     * 从properties中读取指定key的值, 且数值必须大于0(传统实现)
     */
    public static int getPropertyTraditional(Properties properties, String key) {
        String val = properties.getProperty(key);

        if (val != null) {
            try {
                int i = Integer.parseInt(val);

                if (i > 0) {
                    return i;
                }

            } catch (NumberFormatException e) {
                // ignore...
            }
        }
        return -1;
    }

    /**
     * 从properties中读取指定key的值, 且数值必须大于0(Optional实现)
     */
    public static int getPropertyOptional(Properties properties, String key) {
        return Optional.ofNullable(properties.getProperty(key)).flatMap(OptionalSample::stringToInt).filter(e -> e > 0).orElse(-1);
    }

    private static Optional<Integer> stringToInt(String s) {
        try {
            return Optional.of(Integer.parseInt(s));
        } catch (NumberFormatException e) {
            return Optional.empty();
        }
    }
}
小结
  1. 你可以使用静态工厂方法Optional.empty、Optional.of以及Optional.ofNullable创建Optional对象。
  2. Optional类支持多种方法,比如map、flatMap、filter,它们在概念上与Stream类中对应的方法十分相似。
  3. 使用Optional能帮助你设计更好的API,用户只需要阅读方法签名,就能了解该方法是否接受一个Optional类型的值。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值