当前位置: 首页 > >

Java8新特性

发布时间:


书籍 《Java实战第二版》





文章目录
1. 为什么要引入新的日期与时间api2. jdk8:java.time包2.1 使用LocalDate和LocalTime2.2 合并日期和时间LocalDateTime2.3 机器的日期和时间格式2.4 定义Duration或Period2.5 操纵、解析和格式化日期2.6 使用TemporalAdjuster2.7 打印输出及解析日期-时间对象java.time.format包2.8 获取毫秒值
3. 处理不同的时区和历法4. 总结



1. 为什么要引入新的日期与时间api
    在Java 1.0中,对日期和时间的支持只能依赖java.util.Date类。这个类无法表示日期,只能以毫秒的精度表示时间。年份的起始选择是1900年,月份的起始从0开始。java.util.Calendar类,月份依旧是从0开始计算。用于以语言无关方式格式化和解析日期或时间的DateFormat方法就只在Date类里有。它不是线程安全的。这意味着两个线程如果尝试使用同一个formatter解析日期,你可能会得到无法预期的结果。

2. jdk8:java.time包

java.time包中提供了很多新的类可以帮你解决问题,它们是LocalDate、LocalTime、LocalDateTime、Instant、Duration和Period。



2.1 使用LocalDate和LocalTime

LocalDate date = LocalDate.of(2020, 6, 23);//获取日期
System.out.println(date.toString());
int year = date.getYear();//获取年
System.out.println(year);
Month month = date.getMonth();
System.out.println(month.toString());
int dayOfMonth = date.getDayOfMonth();
System.out.println(dayOfMonth);
DayOfWeek ofWeek = date.getDayOfWeek();
System.out.println(ofWeek.toString());
int lengthOfMonth = date.lengthOfMonth();
System.out.println(lengthOfMonth);
boolean leapYear = date.isLeapYear();//是否闰年
System.out.println(leapYear);
LocalDate now = LocalDate.now();//工厂方法获取now
System.out.println(now.toString());


使用TemporalField获取LocalDate的值:


int DAY_OF_WEEK = now.get(ChronoField.DAY_OF_WEEK);
int year = now.get(ChronoField.YEAR);
//。。。。


一天内的之间可使用LocalTime来表示;


LocalTime localTime=LocalTime.of(16,28);

LocalDate和LocalTime都可以通过解析代表它们的字符串创建。


LocalTime localTime1 = LocalTime.parse("16:28:13");
LocalDate localDate1 = LocalDate.parse("2020-06-23");

注意:


LocalDate localDate1 = LocalDate.parse("2020-6-23");

会抛出异常,不符合格式的也会抛出异常。


LocalTime localTime1 = LocalTime.parse("16-28-13");


格式如下:


2.2 合并日期和时间LocalDateTime

LocalDateTime time = LocalDateTime.of(2020, Month.AUGUST, 23, 17, 10);
LocalDateTime localDateTime = LocalDateTime.now();
LocalDate localDate = localDateTime.toLocalDate();
LocalTime localTime = localDateTime.toLocalTime();

2.3 机器的日期和时间格式

从计算机的角度来看,建模时间最自然的格式是表示一个持续时间段上某个点的单一大整型数。
可以通过向静态工厂方法ofEpochSecond传递代表秒数的值创建一个该类的实例。


Instant instant = Instant.ofEpochSecond(1);
Instant now1 = Instant.now();

2.4 定义Duration或Period

以上的类都实现了Temporal接口;



定义对时间对象的读写访问的框架级接口,例如日期,时间,偏移或这些的一些组合。
这是日期,时间和偏移对象的基本界面类型,其完整性足以使用加和减操作。 它由那些可以提供和操纵信息的类实现,如fields或queries 。




大多数日期和时间信息可以表示为一个数字。 这些模型使用TemporalField进行建模,数字持有使用long处理大值。 年份,月份和日期是字段的简单示例,但它们还包括即时和偏移量。



当我们需要需要创建两个Temporal对象之间的Duration。Duration类的静态工厂方法between就是为这个目的而设计的。



Duration duration = Duration.between(LocalTime.now(), LocalTime.of(17, 40));

Duration类主要用于以秒和纳秒衡量时间的长短,所以不能仅向between方法传递一个LocalDate对象做参数。
如果需要以年、月或者日的方式对多个时间单位建模,那么可以使用Period类。


Period period = Period.between(LocalDate.now(), LocalDate.of(2019, 6, 23));

日期-时间类中表示时间间隔的通用方法


2.5 操纵、解析和格式化日期

如果你已经有一个LocalDate对象,想要创建它的一个修改版,最直接也最简单的方法是使用withAttribute方法。withAttribute方法会创建对象的一个副本,并按照需要修改它的属性。注意,下面的这段代码中所有的方法都返回一个修改了属性的对象。它们都不会修改原来的对象!


LocalDate localDate = LocalDate.of(2020, 6, 23);
LocalDate localDate1 = localDate.withYear(2021);
System.out.println(localDate.equals(localDate1));

输出结果:

源码:


如下是LocalDate、LocalTime、LocalDateTime以及Instant这样表示时间点的日期-时间类的通用的方法:



2.6 使用TemporalAdjuster

使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象,可以更加灵活地处理日期。


LocalDate localDate = LocalDate.of(2020, 6, 23);
LocalDate date = localDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
System.out.println(date);

TemporalAdjusters类中的工厂方法


那么我们是否可以自定义自己的TemporalAdjusters呢?
先来看一下我们上面用到的到底是个什么东西:

可以看到TemporalAdjusters只是返回了temporal经过处理后的TemporalAdjuster类型接口;
再来看看TemporalAdjuster:


@FunctionalInterface
public interface TemporalAdjuster {
Temporal adjustInto(Temporal temporal);

}

TemporalAdjuster是一个Function类的函数式接口,意味着我们可以直接用lambda表达式来自定义。


LocalDate date = localDate.with(temporal -> {
DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
int dayToAdd = 1;
if (dayOfWeek == DayOfWeek.FRIDAY) dayToAdd = 3;
else if (dayOfWeek == DayOfWeek.SATURDAY) dayToAdd = 2;
return temporal.plus(dayToAdd, ChronoUnit.DAYS);
});

2.7 打印输出及解析日期-时间对象java.time.format包

类是DateTime-Formatter。创建格式器最简单的方法是通过它的静态工厂方法以及常量。


LocalDate localDate =
LocalDate.parse("20200623", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date =
LocalDate.parse("2020-06-23", DateTimeFormatter.ISO_LOCAL_DATE);

和老的java.util.DateFormat相比较,所有的DateTimeFormatter实例都是线程安全的。所以,你能够以单例模式创建格式器实例,就像DateTimeFormatter所定义的那些常量,并能在多个线程间共享这些实例。


    按照某个模式创建DateTimeFormatter

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date = LocalDate.of(2020, 6, 23);
String format = date.format(dateTimeFormatter);
System.out.println(format); //23/06/2020
System.out.println(date);
LocalDate date1 = LocalDate.parse(format, dateTimeFormatter);//还原成原格式
System.out.println(date1);


    创建一个本地化的DateTimeFormatter

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d.MMMM.yyyy", Locale.CHINA);
LocalDate date = LocalDate.of(2020, 6, 23);
String format = date.format(formatter);
System.out.println(date);
System.out.println(format);
LocalDate date1 = LocalDate.parse(format, formatter);//还原成原格式
System.out.println(date1);


3.构造一个DateTimeFormatter


DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder()
.appendText(ChronoField.DAY_OF_MONTH)
.appendLiteral(". ")
.appendText(ChronoField.MONTH_OF_YEAR)
.appendLiteral(" ")
.appendText(ChronoField.YEAR)
.parseCaseInsensitive()
.toFormatter(Locale.CHINA);
LocalDate date = LocalDate.of(2020, 6, 23);
String format = date.format(timeFormatter);
System.out.println(format);


2.8 获取毫秒值


//获取秒数
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
//获取毫秒数
Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();


或者:


1、System.currentTimeMillis();
2、Calendar.getInstance().getTimeInMillis();
3、new Date().getTime();

3. 处理不同的时区和历法

新版java.time.ZoneId类是*鎗ava.util.TimeZone类的替代品。它的设计目标就是要让你无须为时区处理的复杂和烦琐而操心,比如处理夏令时(daylight saving time, DST)这种问题。跟其他日期和时间API类一样,ZoneId类也是无法修改的。


ZoneId romezone = ZoneId.of("Europe/Rome")
LocalDate date = LocalDate.of(2020, Month.AUGUST, 23);
ZonedDateTime zdt = date.atStartOfDay(romezone);
LocalDateTime dateTime = LocalDateTime.of(2020, Month.AUGUST, 23, 18, 13, 15);
dateTime.atZone(romezone);


4. 总结
Java 8之前*娴膉ava.util.Date类以及其他用于建模日期和时间的类有很多不一致及设计上的缺陷,包括易变性以及糟糕的偏移值、默认值和命名。新版的日期和时间API中,日期-时间对象是不可变的。新的API提供了两种不同的时间表示方式,有效地区分了运行时人和机器的不同需求。你可以用绝对或者相对的方式操纵日期和时间,操作的结果总是返回一个新的实例,老的日期-时间对象不会发生变化。TemporalAdjuster让你能够用更精细的方式操纵日期,不再局限于一次只能改变它的一个值,并且你还可按照需求定义自己的日期转换器。你现在可以按照特定的格式需求,定义自己的格式器,打印输出或者解析日期-时间对象。这些格式器可以通过模板创建,也可以自己编程创建,并且它们都是线程安全的。你可以用相对于某个地区/位置的方式,或者以与UTC/格林尼治时间的绝对偏差的方式表示时区,并将其应用到日期-时间对象上,对其进行本地化。你现在可以使用不同于ISO-8601标准系统的其他日历系统了。



友情链接: