Java8之Optional与日期API

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);
		

	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值