所有示例代码打包下载 : 点击打开链接
- 接口新增默认方法和静态方法
- Optional类
- Lambda表达式
- 方法引用
- Stream API - 函数式操作流元素集合
- Date/Time API
- 新API和工具
- Nashorn , JavaScript引擎
6 . Date/Time API
在了解Java8的新Date/Time之前 , 先看一下之前的日期/时间存在哪些问题?- 非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
- 设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
- 时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8日期/时间API是JSR-310的实现,它的实现目标是克服旧的日期时间实现中所有的缺陷,新的日期/时间API的一些设计原则是:
- 不变性:新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处。
- 关注点分离:新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。
- 清晰:在所有的类中,方法都被明确定义用以完成相同的行为。举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()方法,而不是像以前那样专门有一个独立的类。为了更好的处理问题,所有的类都使用了工厂模式和策略模式,一旦你使用了其中某个类的方法,与其他类协同工作并不困难。
- 实用操作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。
- 可扩展性:新的日期/时间API是工作在ISO-8601日历系统上的,但我们也可以将其应用在非IOS的日历上。
- java.time包:这是新的Java日期/时间API的基础包,所有的主要基础类都是这个包的一部分,如:LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。所有这些类都是不可变的和线程安全的,在绝大多数情况下,这些类能够有效地处理一些公共的需求。
- java.time.chrono包:这个包为非ISO的日历系统定义了一些泛化的API,我们可以扩展AbstractChronology类来创建自己的日历系统。
- java.time.format包:这个包包含能够格式化和解析日期时间对象的类,在绝大多数情况下,我们不应该直接使用它们,因为java.time包中相应的类已经提供了格式化和解析的方法。
- java.time.temporal包:这个包包含一些时态对象,我们可以用其找出关于日期/时间对象的某个特定日期或时间,比如说,可以找到某月的第一天或最后一天。你可以非常容易地认出这些方法,因为它们都具有“withXXX”的格式。
- java.time.zone包:这个包包含支持不同时区以及相关规则的类。
1 . java.time.LocalDate:
LocalDate是一个不可变的类,它表示默认格式(yyyy-MM-dd)的日期,我们可以使用now()方法得到当前时间,也可以提供输入年份、月份和日期的输入参数来创建一个LocalDate实例。该类为now()方法提供了重载方法,我们可以传入ZoneId来获得指定时区的日期。该类提供与java.sql.Date相同的功能 .
LocalDate today = LocalDate.now();
System.out.println("当前日期 : "+today);//2018-02-11
LocalDate firstDay_2014 = LocalDate.of(2014, Month.JANUARY, 1);
System.out.println("指定日期 : "+firstDay_2014);//2014-01-01
LocalDate todayKolkata = LocalDate.now(ZoneId.of("Asia/Kolkata"));
System.out.println("指定时区日期 : "+todayKolkata);//2018-02-11
System.out.println("当前日期月份 : " + today.getMonth());//FEBRUARY
System.out.println("一个月后的日期 : " + today.plusMonths(1));//2018-03-11
2 . java.time.LocalTime:
LocalTime是一个不可变的类,它的实例代表一个符合人类可读格式的时间,默认格式是hh:mm:ss.zzz。像LocalDate一样,该类也提供了时区支持,同时也可以传入小时、分钟和秒等输入参数创建实例 .
LocalTime time = LocalTime.now();
System.out.println("当前时间 : "+time);//11:47:05.472
LocalTime specificTime = LocalTime.of(12,20,25,40);//12:20:25.000000040
System.out.println("指定时间 : "+specificTime);
LocalTime timeKolkata = LocalTime.now(ZoneId.of("Asia/Kolkata"));
System.out.println("指定时区时间 : "+timeKolkata);// 09:17:05.473
System.out.println("当前小时 : " + time.getHour());//11
System.out.println("5小时后的时间 : " + time.plusHours(5));//16:48:36.472
3 . java.time.LocalDateTime:
LocalDateTime是一个不可变的日期-时间对象,它表示一组日期-时间,默认格式是yyyy-MM-dd-HH-mm-ss.zzz。它提供了一个工厂方法,接收LocalDate和LocalTime输入参数,创建LocalDateTime实例
LocalDateTime today = LocalDateTime.now();
System.out.println("当前日期&时间 : "+today);//2018-02-11T11:52:06.398
today = LocalDateTime.of(LocalDate.now(), LocalTime.now());
System.out.println("当前日期&时间 : "+today);//2018-02-11T11:52:06.399
LocalDateTime specificDate = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);
System.out.println("指定日期&时间 : "+specificDate);//2014-01-01T10:10:30
LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Kolkata"));
System.out.println("指定时区日期&时间 : "+todayKolkata);//2018-02-11T09:22:06.400
System.out.println("当前日期&时间的月份 : " + today.getMonthValue());//2
System.out.println("5天后的日期&时间 : " + today.plusDays(5));//2018-02-16T11:52:06.399
4 . java.time.Instant:
Instant类是用在机器可读的时间格式上的,它以Unix时间戳的形式存储日期时间
Instant timestamp = Instant.now();
System.out.println("当前时间"+timestamp);
Long currMills = timestamp.toEpochMilli();
System.out.println("当前时间戳 : " + currMills);
Instant specificTime = Instant.ofEpochMilli(currMills);
System.out.println("时间戳转Instant : "+specificTime);
5 . 日期API工具:
我们早些时候提到过,大多数日期/时间API类都实现了一系列工具方法,如:加/减天数、周数、月份数,等等。还有其他的工具方法能够使用TemporalAdjuster调整日期,并计算两个日期间的周期。
LocalDate today = LocalDate.now();//今天日期
System.out.println("年 : "+today.getYear()+"是否闰年 : "+today.isLeapYear());//2018 false
System.out.println("今天是否在2015-01-01之前 : "+today.isBefore(LocalDate.of(2015,1,1)));//false
System.out.println("拼接为日期&时间 : "+today.atTime(LocalTime.now()));//2018-02-11T12:01:42.816
System.out.println("10天后的日期 : "+today.plusDays(10));//2018-02-21
System.out.println("3周后的日期 : "+today.plusWeeks(3));//2018-03-04
System.out.println("20个月之后的日期 : "+today.plusMonths(20));// 2019-10-11
System.out.println("10天前的日期 : "+today.minusDays(10));//2018-02-01
System.out.println("3周前的日期 : "+today.minusWeeks(3));//2018-01-21
System.out.println("20个月之前的日期 : "+today.minusMonths(20));//2016-06-11
System.out.println("本月第一天的日期 : "+today.with(TemporalAdjusters.firstDayOfMonth()));//2018-02-01
LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());
System.out.println("今年最后一天的日期 : "+lastDayOfYear);//2018-12-31
6 . DateTimeFormatter .
解析和格式化:将一个日期格式转换为不同的格式,之后再解析一个字符串,得到日期时间对象,这些都是很常见的。对此Java8也提供了新的类DateTimeFormatter LocalDate date = LocalDate.now();
System.out.println("默认格式日期 : "+date);//2018-02-11
System.out.println("yyyy/MM/dd : " + date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")));//2018/02/11
System.out.println("默认的ISO格式 : " + date.format(DateTimeFormatter.BASIC_ISO_DATE));//20180211
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("默认日期&时间 : "+dateTime);//2018-02-11T12:10:44.149
System.out.println("yyyy-MM-dd hh:mm:ss : " + dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));//2018-02-11 12::10::44
System.out.println("默认的ISO格式 : " + dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));//20180211
Instant timestamp = Instant.now();
System.out.println("默认时间戳 : "+timestamp);//2018-02-11T04:10:44.149Z
LocalDateTime dt = LocalDateTime.parse("2008-08-08 20:08:08", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println("字符串转日期 : "+dt);//2008-08-08T20:08:08
Long longStamp = timestamp.toEpochMilli();
DateTimeFormatter df= DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSS");
String dateStr = df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(longStamp), ZoneId.of("Asia/Shanghai")));
System.out.println("long 转日期字符串 : " + dateStr);//2018-02-11 12:10:44.149 貌似更复杂了 ?
7 . 旧的日期时间支持:
旧的日期/时间类已经在几乎所有的应用程序中使用,因此做到向下兼容是必须的。这也是为什么会有若干工具方法帮助我们将旧的类转换为新的类,反之亦然。
Instant timestamp = new Date().toInstant();//Date -> Instant
LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.of(ZoneId.SHORT_IDS.get("PST")));//Instant -> LocalDateTime
System.out.println(date);
Instant time = Calendar.getInstance().toInstant();//时间戳 -> Instant
System.out.println(time);
ZoneId defaultZone = TimeZone.getDefault().toZoneId();//TimeZone -> ZoneId
System.out.println(defaultZone);
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();//GregorianCalendar -> ZonedDateTime
System.out.println(gregorianCalendarDateTime);
Date dt = Date.from(Instant.now());// Instant -> Date
System.out.println(dt);
TimeZone tz = TimeZone.getTimeZone(defaultZone);//ZoneId -> TimeZone
System.out.println(tz);
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);//ZonedDateTime -> GregorianCalendar
System.out.println(gc);
8 . Clock :
它通过指定一个时区,然后就可以获取到当前的时刻,日期与时间。Clock可以替换System.currentTimeMillis()与TimeZone.getDefault()。
Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );//2018-02-11T04:18:41.362Z
System.out.println( clock.millis() );//1518322721440
9 . ZonedDateTime :
带时区日期时间处理
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前时区时间 : " + now);//2018-02-11T12:20:57.884+08:00[Asia/Shanghai]
ZonedDateTime date1 = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Shanghai]");
System.out.println("指定时区指定时间" + date1);//2007-12-03T10:15:30+08:00[Asia/Shanghai]
ZoneId id = ZoneId.of("Europe/Paris");
System.out.println("指定时区ZoneId: " + id);//Europe/Paris
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("当前时区: " + currentZone);//Asia/Shanghai
10 . ChronoUnit :
可以代替Calendar的日期操作
LocalDate today = LocalDate.now();
System.out.println("当前日期 : " + today);//2018-02-11
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("下周日期 : " + nextWeek);//2018-02-18
LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS);
System.out.println("下月日期 : " + nextMonth);//2018-03-11
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("明年日期 : " + nextYear);//2019-02-11
LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES);
LocalDate nextDecade20 = today.plus(2, ChronoUnit.DECADES);
System.out.println("20年后日期: " + nextDecade20);//2038-02-11
11 . Period/Duration :
使用Java8中两个专门用来来处理时间差的类 .
- Period - 处理有关基于时间的日期数量。
- Duration - 处理有关基于时间的时间量。
private static void testPeriod(){
LocalDate date1 = LocalDate.now();
System.out.println("当前日期 : " + date1);//2018-02-11
LocalDate date2 = date1.plus(3, ChronoUnit.DAYS);
System.out.println("3天后新日期 : " + date2);//2018-02-14
Period period = Period.between(date1, date2);
System.out.println("相差 : " + period);//P3D
System.out.println("相差年份 : " + period.getYears());//0
System.out.println("相差月份 : " + period.getMonths());//0
System.out.println("相差天数 : " + period.getDays());//3
}
private static void testDuration(){
LocalTime time1 = LocalTime.now();
Duration twoHours = Duration.ofHours(2);
System.out.println("2个小时的秒数 : " + twoHours.getSeconds());//7200
LocalTime time2 = time1.plus(twoHours);
System.out.println("2个小时后的新时间 : " + time2);//14:30:14.345
Duration duration = Duration.between(time1, time2);
System.out.println("相差: " + duration);//PT2H
System.out.println("相差秒数 : " + duration.getSeconds());//7200
}
12 . TemporalAdjuster :
是做日期数学计算 . 这个类在日期调整时非常有用,比如得到当月的第一天、最后一天,当年的第一天、最后一天,下一周或前一周的某天等。 LocalDate date1 = LocalDate.now();
System.out.println("当前日期 : " + date1);//2018-02-11
LocalDate nextTuesday = date1.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
System.out.println("下一个周二 : " + nextTuesday);//2018-02-13
LocalDate firstInMonth = LocalDate.of(date1.getYear(), date1.getMonth(), 1);
LocalDate secondSaturday = firstInMonth.with(
TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY)).with(
TemporalAdjusters.next(DayOfWeek.SATURDAY));
System.out.println("当月的第二个周六 : " + secondSaturday);//2018-02-10