Java8之Optional与日期API
一、Optional
在开发过程中我们经常会遇到NPE,也就是空指针异常,而Optional正是一种解决NPE的很好方式。
Null所带来的问题:
① Null对象是NPE异常的源头
② 因为检查Null,会带来大量的代码检查
③ Null值没有任何意义
④ 当将Null值传递给变量时,无法通过该变量获取其类型
1.Optional的创建
声明一个空的Optional对象
Optional<Integer> empty = Optional.empty();
创建一个非空容器对象
// 创建非空对象
// 如果传入的值为null,则会直接抛出异常,而不会等使用时报错
Optional<Integer> integer = Optional.of(100);
创建一个可为空的Optional对象
// 可为空的Optional对象
// 当传入值为null时,等同于调用empty()方法
Optional<Object> nullObj = Optional.ofNullable(null);
通过map方法获取值,转换值
/**
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional1 {
public static void main(String[] args) {
Person person = new Person(1, "kns", 22);
// 创建一个Optional对象
Optional<Person> op = Optional.of(person);
// 获取名称
Optional<String> name = op.map(Person::getName);
// 转换值的做法可参照Stream API中的map方式,几乎一样
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
private Integer id;
private String name;
private Integer age;
}
使用flatMap
/**
* 当属性中包含Optional<T>对象时,需要使用flatMap转换
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional1 {
public static void main(String[] args) {
Person person = new Person(1, "kns", 22,
Optional.of(new Department(1, "华中")));
// 创建一个Optional对象
Optional<Person> op = Optional.of(person);
// 获取名称
Optional<String> name = op.map(Person::getName);
// 编译不通过
//Optional<Department> dept1 = op.map(Person::getDepartment);
Optional<Department> dept2 = op.flatMap(Person::getDept);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
private Integer id;
private String name;
private Integer age;
private Optional<Department> dept;
}
@Data
@AllArgsConstructor
class Department {
private Integer id;
private String name;
}
2.Optional的值获取
T get()
get方法最简单的获取值,但是如果容器中的值为null,那么会抛出NoSuchElementException异常,因此除非你确定容器的值不为null,否则与NPE区别不大,都是抛异常。
/**
* 读取Optional中的值
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional2 {
public static void main(String[] args) {
String test = "test";
String nullString = null;
Optional<String> ot = Optional.of(test);
System.out.println(ot.get()); // test
Optional<String> ns = Optional.ofNullable(nullString);
System.out.println(ns.get()); // 抛出异常
}
}
T orElse(T other)
获取Optional对象的默认值,当Optional对象中值为null时,使用该方法可以获取一个默认值,若不为空,则使用容器中的值。
/**
* 读取Optional中的值
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional2 {
public static void main(String[] args) {
String nullString = null;
Optional<String> ns = Optional.ofNullable(nullString);
//System.out.println(ns.get());
String orElse = ns.orElse("默认值");
System.out.println(orElse); // 默认值
}
}
T orElseGet(Supplier<? extends T> other)
如果Optional对象中的值为不为null,则返回原值,如原值为null,则调用传入的Supplier对象的get()方法,获取自定义方式的值。
/**
* 读取Optional中的值
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional2 {
public static void main(String[] args) {
String nullString = null;
Optional<String> ns = Optional.ofNullable(nullString);
//System.out.println(ns.get());
String result = ns.orElseGet(() -> {
System.out.println("调用了supplier.get()");
return "supplier-default";
});
System.out.println(result);
}
}
T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
当容器值为空时,可以自己定义抛出所需异常
/**
* 读取Optional中的值
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional2 {
public static void main(String[] args) {
String nullString = null;
Optional<String> ns = Optional.ofNullable(nullString);
//System.out.println(ns.get());
String exp = ns.orElseThrow(RuntimeException::new);
System.out.println(exp);
}
}
void ifPresent(Consumer<? super T> consumer)
当容器值不为null时,调用Consumer的accept方法,消费这个值,否则不做操作
/**
* 读取Optional中的值
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional2 {
public static void main(String[] args) {
String test = "test";
String nullString = null;
Optional<String> ot = Optional.of(test);
ot.ifPresent(System.out::println);
Optional<String> ns = Optional.ofNullable(nullString);
//System.out.println(ns.get());
ns.ifPresent(System.out::println);
}
}
filter的使用
使用filter方法过滤Optional对象中的值,如果符合条件则返回this,否则创建一个空容器。
/**
* @author kenewstar
* @date 2022/01/24
*/
public class TestOptional3 {
public static void main(String[] args) {
String test = "str";
Optional<String> ot = Optional.of(test);
ot.filter("str"::equals).ifPresent(System.out::println);
ot.filter("str2"::equals).ifPresent(System.out::println);
}
}
二、日期API
1.LocalDate(日期)
/**
* LocalDate使用 yyyy-MM-dd
* 获取年月日
* @author kenewstar
* @date 2022/01/24
*/
public class TestDate01 {
public static void main(String[] args) {
// 获取当前日期
LocalDate date = LocalDate.now();
// 2021-12-15
System.out.println(date);
LocalDate of = LocalDate.of(2022, 1, 1);
// 2022-01-01
System.out.println(of);
// 获取年份
System.out.println(date.getYear());
// 获取月份
System.out.println(date.getMonth());
// 获取当前年份的第多少天
System.out.println(date.getDayOfYear());
// 获取当前月份的第多少天
System.out.println(date.getDayOfMonth());
// 获取星期几
System.out.println(date.getDayOfWeek());
// 当前月份的天数
System.out.println(date.lengthOfMonth());
// 当前年份的天数
System.out.println(date.lengthOfYear());
// 是否是闰年
System.out.println(date.isLeapYear());
System.out.println("-------------------");
// 获取年份
System.out.println(date.get(ChronoField.YEAR));
// 获取月份
System.out.println(date.get(ChronoField.MONTH_OF_YEAR));
// 获取月份中的第多少天
System.out.println(date.get(ChronoField.DAY_OF_MONTH));
System.out.println("-------------------");
// 解析字符串为日期类
LocalDate parse = LocalDate.parse("2021-12-15");
System.out.println(parse);
// 自定义解析格式
LocalDate parse1
= LocalDate.parse("2021/12/15", DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(parse1);
}
}
2.LocalTime(时间)
/**
* LocalTime 时间 HH:mm:ss
* 获取时分秒
*
* @author kenewstar
* @date 2022/01/24
*/
public class TestDate02 {
public static void main(String[] args) {
// 获取时间
LocalTime time = LocalTime.now();
System.out.println(time);
// 指定时间
LocalTime of = LocalTime.of(18, 3, 12);
System.out.println(of);
// 获取当前小时数
System.out.println(time.getHour());
// 获取分钟
System.out.println(time.getMinute());
// 获取秒
System.out.println(time.getSecond());
// 获取纳秒
System.out.println(time.getNano());
System.out.println("-----------------");
// 解析时间字符串
LocalTime parse = LocalTime.parse("18:03:21");
System.out.println(parse);
// 自定义解析格式
LocalTime parse1
= LocalTime.parse("23/03/12", DateTimeFormatter.ofPattern("HH/mm/ss"));
System.out.println(parse1);
}
}
3.LocalDateTime(日期+时间)
/**
* LocalDateTime (2021-12-15T18:12:57.449)
* 获取日期 + 时间
* @author kenewstar
* @date 2022/01/24
*/
public class TestDate03 {
public static void main(String[] args) {
// 获取日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
// 获取日期
LocalDate date = LocalDate.now();
// 获取时间
LocalTime time = LocalTime.now();
// 拼接日期和时间
LocalDateTime of = LocalDateTime.of(date, time);
System.out.println(of);
// 日期+自设置时间
LocalDateTime dateTime = date.atTime(10, 10, 10);
// 时间+ 日期对象
LocalDateTime dateTime1 = time.atDate(date);
// 获取日期
LocalDate localDate = now.toLocalDate();
// 获取时间
LocalTime localTime = now.toLocalTime();
}
}
4.Duration/Period
/**
* Period / Duration计算两个日期或时间之差
*
* @author kenewstar
* @date 2022/01/24
*/
public class TestDate04 {
public static void main(String[] args) {
LocalTime now = LocalTime.now();
LocalTime of = LocalTime.of(10, 10, 10);
Duration between = Duration.between(of, now);
System.out.println(between);
// 两个时间秒数之差
System.out.println(between.getSeconds());
// 两个时间分钟之差
System.out.println(between.toMinutes());
LocalDateTime dateTime1 = LocalDateTime.now();
LocalDateTime dateTime2 = LocalDateTime.of(2021, 12, 15, 10, 10, 10);
Duration duration = Duration.between(dateTime2, dateTime1);
System.out.println(duration);
Instant instant = Instant.now();
Instant parse = Instant.parse("2021-12-03T10:15:30Z");
Duration duration1 = Duration.between(parse, instant);
System.out.println(duration1);
System.out.println("----------------");
Duration seconds = Duration.ofSeconds(100);
System.out.println(seconds); //PT1M40S
Duration minutes = Duration.ofMinutes(3);
System.out.println(minutes); //PT3M
Duration dm = Duration.of(4, ChronoUnit.MINUTES);
System.out.println(dm); //PT4M
LocalDate date1 = LocalDate.of(2021, 10, 10);
LocalDate date2 = LocalDate.now();
Period p = Period.between(date2, date1);
System.out.println(p); // P-2M-6D 2个月6天
}
}
日期-时间类中表示时间间隔的通用方法
方法名 | 是否是静态方法 | 描述 |
---|---|---|
between | 是 | 创建两个时间点之间的interval |
from | 是 | 由一个临时时间点创建interval |
of | 是 | 由它的组成部分创建interval |
parse | 是 | 由字符串创建interval的实例 |
addTo | 否 | 创建该interval的副本,并将其叠加到某个指定的temporal对象 |
get | 否 | 读取该interval的状态 |
isNegative | 否 | 检查该interval是否为负值,不包含零 |
isZero | 否 | 检查该interval的时长是否为零 |
minus | 否 | 通过减去一定的时间创建该interval的副本 |
multipliedBy | 否 | 将interval的值乘以某个标量创建该interval的副本 |
negated | 否 | 以忽略某个时长的方式创建该interval的副本 |
plus | 否 | 以增加某个指定的时长的方式创建该interval的副本 |
subtractFrom | 否 | 从指定的temporal对象中减去该interval |
(以上表格摘自Java8实战)
5.操作日期
对日期的加减,修改操作
/**
* @author kenewstar
* @date 2022/01/24
*/
public class TestDate05 {
public static void main(String[] args) {
// 创建一个日期
LocalDate date = LocalDate.of(2021, 12, 16);
// 修改副本的日期年份
LocalDate dateYear = date.withYear(2022);
System.out.println(dateYear);
// 修改副本的日期月份
LocalDate dateMonth = date.withMonth(6);
System.out.println(dateMonth);
// 修改副本的日期日
LocalDate dateDay = date.withDayOfMonth(19);
System.out.println(dateDay);
LocalDate d = date.with(ChronoField.YEAR, 2030);
System.out.println(d);
System.out.println("-----------------------");
// 加10天
LocalDate plusDays = date.plusDays(10);
System.out.println(plusDays);
// 减10天
LocalDate minusDays = date.minusDays(10);
System.out.println(minusDays);
// 加1周
LocalDate plusWeeks = date.plusWeeks(1);
System.out.println(plusWeeks);
// 其他略...
// 加10个月
LocalDate plus = date.plus(10, ChronoUnit.MONTHS);
System.out.println(plus);
// 减10个月
LocalDate minus = date.minus(10, ChronoUnit.MONTHS);
System.out.println(minus);
}
}
6.TemporalAdjusters
/**
* @author kenewstar
* @date 2022/01/24
*/
public class TestDate06 {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
// 这个月第一天的日期
TemporalAdjuster ta1 = TemporalAdjusters.firstDayOfMonth();
System.out.println(date.with(ta1));
// 这个月最后一天的日期
TemporalAdjuster ta2 = TemporalAdjusters.lastDayOfMonth();
System.out.println(date.with(ta2));
// 这一年的第一天
TemporalAdjuster ta3 = TemporalAdjusters.firstDayOfYear();
System.out.println(date.with(ta3));
// 这一年的最后一天
TemporalAdjuster ta4 = TemporalAdjusters.lastDayOfYear();
System.out.println(date.with(ta4));
}
}
7.LocalDateTime与Date的转换
/**
* date与localDateTime的互换
* @author kenewstar
* @date 2022/01/24
*/
public class TestDate07 {
public static void main(String[] args) {
// date转换为localDateTime
Date date = new Date();
Instant instant = date.toInstant();
// 方式一
LocalDateTime dateTime
= LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println(dateTime);
// 方式二
LocalDateTime dateTime1
= instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(dateTime1);
// 方式三
long time = date.getTime();
System.out.println(time);
LocalDateTime dateTime2 = Instant.ofEpochMilli(time)
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
System.out.println(dateTime2);
// localDateTime转换为date
LocalDateTime now = LocalDateTime.now();
Instant instant1 = now.atZone(ZoneId.systemDefault()).toInstant();
Date date1 = Date.from(instant1);
System.out.println(date1);
}
}