11 用Option取代null
11.1 如何为缺失的值建模
public class Person {private Car car;public Car getCar() {return car;}}public class Car {private Insurance insurance;public Insurance getInsurance() {return insurance;}}public class Insurance {private String name;public String getName() {return name;}}
使用Optional而不是null的一个非常重要而又实际的语义区别是,我们在声明变量的时候使用Optional
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对象。
Optional<Integer> stringToInt(String numSer) {try {return Optional.of(Integer.parseInt(numSer));} catch (NumberFormatException e) {return Optional.empty();}}
12 新的日期和时间API
12.1.1 使用LocalDate和LocalTime
12.1.4 定义Duration或Period
Temporal接口定义了如何读取和操作为时间建模的对象的值。
Duration d1 = Duration.between(time1, time2);Duration d1 = Duration.between(dateTime1, dateTime2);Duration d2 = Duration.between(instant1, instant2);
由于LocalDateTime和Instance是为不同的目的而设计的,一个是为了便于阅读使用,另一个是为了便于机器处理,因此不能将二者混用。Duration类主要用于秒和纳秒衡量时间的长短,所以不能仅向between方法传递一个LocalDate对象作为参数。
如果需要以年、月或者日的方式多个时间单位建模,那么使用Period类。使用该类的工厂方法between,你可以得到两个LocalDate之间的时长。
Period tenDays = Period.between(LocalDate.of(2017, 9, 11),LocalDate.of(2017, 9, 21));
with方法,以该Temporal对象为模板,对某些状态进行修改创建该对象的副本。
12.2.1 使用TemporalAdjuster
需要进行一些更加复杂的操作,比如将日期调整到下个工作日,或者是本月最后一天。这是就可以使用重载版本的with方法,向其传递一个更多定制化选择的TemporalAdjuster对象,更加灵活地处理日期。
// import static java.time.temporal.TemporalAdjusters.*;LocalDate date1 = LocalDate.of(2021, 9, 7);LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));//2021-09-12LocalDate date3 = date2.with(lastDayOfMonth());//2021-09-30
TemporalAdjusters类中的工厂方法
| 方法名 | 描述 |
|---|---|
| dayOfWeekInMonth | 创建一个新的日期,它的值为同一个月中每一周的第几天(负数表示从月末往月初计数) |
| firstDayOfMonth | 创建一个新的日期,它的值为当月的第一天 |
| firstDayOfNextMonth | 创建一个新的日期,它的值Wie下月的第一天 |
| fitstDayOfNextYear | 创建一个新的日期,它的值为明年的第一天 |
| firstDayOfYear | 创建一个新的日期,它的值为当年的第一天 |
| firstInMonth | 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值 |
| lastDayOfMonth | 创建一个新的日期,它的值为当月的最后一天 |
| lastDayOfNextMonth | 创建一个新的日期,它的值为下月的最后一天 |
| lastDayOfNextYear | 创建一个新的日期,它的值为明年的最后一天 |
| lastDayOfYear | 创建一个新的日期,它的值为当年的最后一天 |
| lastInMonth | 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值 |
| next/previous | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星 |
期几要求的日期 |
| nextOrSame/previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星
期几要求的日期,如果该日期已经符合要求,则直接返回该对象 |
