11 用Option取代null

11.1 如何为缺失的值建模

  1. public class Person {
  2. private Car car;
  3. public Car getCar() {
  4. return car;
  5. }
  6. }
  7. public class Car {
  8. private Insurance insurance;
  9. public Insurance getInsurance() {
  10. return insurance;
  11. }
  12. }
  13. public class Insurance {
  14. private String name;
  15. public String getName() {
  16. return name;
  17. }
  18. }

使用Optional而不是null的一个非常重要而又实际的语义区别是,我们在声明变量的时候使用Optional 类型,而不是Car类型,可能将变量赋值为null,这意味着你需要独立面对这些,你只能依赖你对业务模型的理解,判断一个null是否属于该变量的有效范围。

11.4.2 异常与Optional的对比

由于某种原因,函数无法返回某个值,这是除了返回null,Java API 比较常见的替代做法是抛出一个异常。这种情况比较典型的例子是使用静态方法Integer.parseInt(String) ,将String转换为int。在这个例子中,如果String无法解析到对应的整型,该方法就抛出一个NumberFormatException。最后的效果是,发生String无法转换为int时,代码发出了一个遭到非法参数的信号,唯一不同的是,这次你需要try/catch语句,而不是使用if条件来判断一个变量的值是否为非空。
你也可以使用空的Optional对象,对遭遇无法转换的String时返回非法值进行建模,这是你期望parseInt的返回值是一个Optional。我们无法修改最初的Java方法,但是这无碍我们进行需要的改进,你可以实现一个工具方法,将这部分逻辑封装于其中,最终返回一个我们希望的Optional对象。

  1. Optional<Integer> stringToInt(String numSer) {
  2. try {
  3. return Optional.of(Integer.parseInt(numSer));
  4. } catch (NumberFormatException e) {
  5. return Optional.empty();
  6. }
  7. }

12 新的日期和时间API

12.1.1 使用LocalDate和LocalTime

12.1.4 定义Duration或Period

Temporal接口定义了如何读取和操作为时间建模的对象的值。

  1. Duration d1 = Duration.between(time1, time2);
  2. Duration d1 = Duration.between(dateTime1, dateTime2);
  3. Duration d2 = Duration.between(instant1, instant2);

由于LocalDateTime和Instance是为不同的目的而设计的,一个是为了便于阅读使用,另一个是为了便于机器处理,因此不能将二者混用。Duration类主要用于秒和纳秒衡量时间的长短,所以不能仅向between方法传递一个LocalDate对象作为参数。
如果需要以年、月或者日的方式多个时间单位建模,那么使用Period类。使用该类的工厂方法between,你可以得到两个LocalDate之间的时长。

  1. Period tenDays = Period.between(LocalDate.of(2017, 9, 11),
  2. LocalDate.of(2017, 9, 21));

with方法,以该Temporal对象为模板,对某些状态进行修改创建该对象的副本。

12.2.1 使用TemporalAdjuster

需要进行一些更加复杂的操作,比如将日期调整到下个工作日,或者是本月最后一天。这是就可以使用重载版本的with方法,向其传递一个更多定制化选择的TemporalAdjuster对象,更加灵活地处理日期。

  1. // import static java.time.temporal.TemporalAdjusters.*;
  2. LocalDate date1 = LocalDate.of(2021, 9, 7);
  3. LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));//2021-09-12
  4. LocalDate date3 = date2.with(lastDayOfMonth());//2021-09-30

TemporalAdjusters类中的工厂方法

方法名 描述
dayOfWeekInMonth 创建一个新的日期,它的值为同一个月中每一周的第几天(负数表示从月末往月初计数)
firstDayOfMonth 创建一个新的日期,它的值为当月的第一天
firstDayOfNextMonth 创建一个新的日期,它的值Wie下月的第一天
fitstDayOfNextYear 创建一个新的日期,它的值为明年的第一天
firstDayOfYear 创建一个新的日期,它的值为当年的第一天
firstInMonth 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值
lastDayOfMonth 创建一个新的日期,它的值为当月的最后一天
lastDayOfNextMonth 创建一个新的日期,它的值为下月的最后一天
lastDayOfNextYear 创建一个新的日期,它的值为明年的最后一天
lastDayOfYear 创建一个新的日期,它的值为当年的最后一天
lastInMonth 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值
next/previous 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星


期几要求的日期 | | nextOrSame/previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星
期几要求的日期,如果该日期已经符合要求,则直接返回该对象 |