本文作者:小虚竹,CSDN博客专家&CSDN原力计划作者,Java领域优质创作者,掘金年度人气作者,华为云专家,阿里云专家博主,51CTO专家博主。是一个乐于分享“IT圈”技术的博主。

开篇介绍

学习Java的经典名著非常多,这本书是你一定不能错过的:由凯.霍斯特曼写的《Core Java》,中文版名为《Java核心技术》。这本书几乎出现在每个“学Java要看什么书”类似的书单里,影响了几代技术人。豆瓣的评分很高:

主题

《Java核心技术》 这本书好在哪?我们都知道技术会过时的,技术会升级的,尤其是Java技术一直在持续不断地更新。《Java核心技术》 好在与时俱进,我查了下这本书的历程,1996年出版以来,至今已经更新了11版。写一本需要投入大量的精力,升级一本书也需要大量的精力,当前书的内容已经补充了Java SE 9,10,11的新版本最新特性,这对于我来说,帮助挺大的,可以及时跟上Java前进的脚步。(本书基于Java SE 17 的中文版本也即将出版)

对我的影响

《Java核心技术》 分为两本书,卷一和卷二。卷一主要是介绍Java语言的基本概念以及程序设计的基础知识,我在这里吸收到了基础知识,对原先掌握的知识进行了查缺补漏。对我编写专栏 《Java筑基100例》 起到了指导作用。

卷二主要涉及企业级专业软件开发时需要了解的高级主题,我更喜欢卷二,因为卷二的章节大部分是相互独立的,可以直接研究自己感兴趣的章节,不用关心前后章节。学习卷二的内容,我掌握了不少新知识,例如Java 8 的流库,文件的加锁机制,文件的ZIP压缩和解压缩技术,日期和时间新旧API对比,和网络通信等。


内容分享:日期和时间新旧API对比

下面我们来分享一个知识点:日期和时间新旧API对比

Java提供了两套处理日期和时间的API

1、旧的API,放在java.util 这个包下的:比较常用的有Date和Calendar等

2、新的API是java 8新引入的,放在java.time 这个包下的:LocalDateTime,ZonedDateTime,DateTimeFormatter和Instant等

为什么会有两套日期时间API,这个是有历史原因的,旧的API是jdk刚开始就提供的,随着版本的升级,逐渐发现原先的api不满足需要,暴露了一些问题,所以在java 8 这个版本中,重新引入新API。

这两套API都要了解,为什么呢?

因为java 8 发布时间是2014年,很多之前的系统还是沿用旧的API,所以这两套API都要了解,同时还要掌握两套API相互转化的技术。

1、Date

1.1 Date类说明

Date类负责时间的表示,在计算机中,时间的表示是一个较大的概念,现有的系统基本都是利用从1970.1.1 00:00:00 到当前时间的毫秒数进行计时,这个时间称为epoch(时间戳)

package java.util;public class Dateimplements java.io.Serializable, Cloneable, Comparable<Date>
{...private transient long fastTime;....
}

java.util.Date是java提供表示日期和时间的类,类里有个long 类型的变量fastTime,它是用来存储以毫秒表示的时间戳。

1.2 date常用的用法

import java.util.Date;
-----------------------------------------//获取当前时间Date date = new Date();System.out.println("获取当前时间:"+date);//获取时间戳System.out.println("获取时间戳:"+date.getTime());// date时间是否大于afterDate 等于也为falseDate afterDate = new Date(date.getTime()-3600*24*1000);System.out.println("after:"+date.after(afterDate));System.out.println("after:"+date.after(date));// date时间是否小于afterDate 等于也为falseDate beforeDate = new Date(date.getTime()+3600*24*1000);System.out.println("before:"+date.before(beforeDate));System.out.println("before:"+date.before(date));//两个日期比较System.out.println("compareTo:"+date.compareTo(date));System.out.println("compareTo:"+date.compareTo(afterDate));System.out.println("compareTo:"+date.compareTo(beforeDate));//转为字符串System.out.println("转为字符串:"+date.toString());//转为GMT时区 toGMTString() java8 中已废弃System.out.println("转为GMT时区:"+date.toGMTString());//转为本地时区 toLocaleString() java8 已废弃System.out.println("转为本地时区:"+date.toLocaleString());

1.3 自定义时间格式-SimpleDateFormat

date的toString方法转成字符串,不是我们想要的时间格式,如果要自定义时间格式,就要使用SimpleDateFormat

//获取当前时间Date date = new Date();System.out.println("获取当前时间:"+date);SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(simpleDateFormat.format(date));SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");System.out.println(simpleDateFormat1.format(date));

SimpleDateFormat也可以方便的将字符串转成Date

//获取当前时间String str = "2021-07-13 23:48:23";try {Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(str);System.out.println(date);} catch (ParseException e) {e.printStackTrace();}

日期和时间格式化参数说明

yyyy:年
MM:月
dd:日
hh:1~12小时制(1-12)
HH:24小时制(0-23)
mm:分
ss:秒
S:毫秒
E:星期几
D:一年中的第几天
F:一月中的第几个星期(会把这个月总共过的天数除以7)
w:一年中的第几个星期
W:一月中的第几星期(会根据实际情况来算)
a:上下午标识
k:和HH差不多,表示一天24小时制(1-24)。
K:和hh差不多,表示一天12小时制(0-11)。
z:表示时区

1.4 SimpleDateFormat线程不安全原因

1.4.1SimpleDateFormat线程为什么是线程不安全的呢?

来看看SimpleDateFormat的源码,先看format方法:

// Called from Format after creating a FieldDelegateprivate StringBuffer format(Date date, StringBuffer toAppendTo,FieldDelegate delegate) {// Convert input date to time field listcalendar.setTime(date);
...}

问题就出在成员变量calendar,如果在使用SimpleDateFormat时,用static定义,那SimpleDateFormat变成了共享变量。那SimpleDateFormat中的calendar就可以被多个线程访问到。

SimpleDateFormat的parse方法也是线程不安全的:

public Date parse(String text, ParsePosition pos){...Date parsedDate;try {parsedDate = calb.establish(calendar).getTime();// If the year value is ambiguous,// then the two-digit year == the default start yearif (ambiguousYear[0]) {if (parsedDate.before(defaultCenturyStart)) {parsedDate = calb.addYear(100).establish(calendar).getTime();}}}// An IllegalArgumentException will be thrown by Calendar.getTime()// if any fields are out of range, e.g., MONTH == 17.catch (IllegalArgumentException e) {pos.errorIndex = start;pos.index = oldStart;return null;}return parsedDate;  }

由源码可知,最后是调用**parsedDate = calb.establish(calendar).getTime();**获取返回值。方法的参数是calendar,calendar可以被多个线程访问到,存在线程不安全问题。

我们再来看看**calb.establish(calendar)**的源码

calb.establish(calendar)方法先后调用了cal.clear()和cal.set(),先清理值,再设值。但是这两个操作并不是原子性的,也没有线程安全机制来保证,导致多线程并发时,可能会引起cal的值出现问题了。

1.4.2 验证SimpleDateFormat线程不安全

public class SimpleDateFormatDemoTest {private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static void main(String[] args) {//1、创建线程池ExecutorService pool = Executors.newFixedThreadPool(5);//2、为线程池分配任务ThreadPoolTest threadPoolTest = new ThreadPoolTest();for (int i = 0; i < 10; i++) {pool.submit(threadPoolTest);}//3、关闭线程池pool.shutdown();}static class  ThreadPoolTest implements Runnable{@Overridepublic void run() {String dateString = simpleDateFormat.format(new Date());try {Date parseDate = simpleDateFormat.parse(dateString);String dateString2 = simpleDateFormat.format(parseDate);System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));} catch (Exception e) {System.out.println(Thread.currentThread().getName()+" 格式化失败 ");}}}
}

出现了两次false,说明线程是不安全的。而且还抛异常,这个就严重了。

2、LocalDateTime

2.1 LocalDateTime类说明

表示当前日期时间,相当于:yyyy-MM-ddTHH:mm:ss

2.2 LocalDateTime常用的用法

2.2.1获取当前日期和时间

LocalDate d = LocalDate.now(); // 当前日期
LocalTime t = LocalTime.now(); // 当前时间
LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间
System.out.println(d); // 严格按照ISO 8601格式打印
System.out.println(t); // 严格按照ISO 8601格式打印
System.out.println(dt); // 严格按照ISO 8601格式打印

由运行结果可行,本地日期时间通过now()获取到的总是以当前默认时区返回的

2.2.2获取指定日期和时间

LocalDate d2 = LocalDate.of(2021, 07, 14); // 2021-07-14, 注意07=07月
LocalTime t2 = LocalTime.of(13, 14, 20); // 13:14:20
LocalDateTime dt2 = LocalDateTime.of(2021, 07, 14, 13, 14, 20);
LocalDateTime dt3 = LocalDateTime.of(d2, t2);
System.out.println("指定日期时间:"+dt2);
System.out.println("指定日期时间:"+dt3);

2.2.3 日期时间的加减法及修改

LocalDateTime currentTime = LocalDateTime.now(); // 当前日期和时间
System.out.println("------------------时间的加减法及修改-----------------------");
//3.LocalDateTime的加减法包含了LocalDate和LocalTime的所有加减,上面说过,这里就只做简单介绍
System.out.println("3.当前时间:" + currentTime);
System.out.println("3.当前时间加5年:" + currentTime.plusYears(5));
System.out.println("3.当前时间加2个月:" + currentTime.plusMonths(2));
System.out.println("3.当前时间减2天:" + currentTime.minusDays(2));
System.out.println("3.当前时间减5个小时:" + currentTime.minusHours(5));
System.out.println("3.当前时间加5分钟:" + currentTime.plusMinutes(5));
System.out.println("3.当前时间加20秒:" + currentTime.plusSeconds(20));
//还可以灵活运用比如:向后加一年,向前减一天,向后加2个小时,向前减5分钟,可以进行连写
System.out.println("3.同时修改(向后加一年,向前减一天,向后加2个小时,向前减5分钟):" + currentTime.plusYears(1).minusDays(1).plusHours(2).minusMinutes(5));
System.out.println("3.修改年为2025年:" + currentTime.withYear(2025));
System.out.println("3.修改月为12月:" + currentTime.withMonth(12));
System.out.println("3.修改日为27日:" + currentTime.withDayOfMonth(27));
System.out.println("3.修改小时为12:" + currentTime.withHour(12));
System.out.println("3.修改分钟为12:" + currentTime.withMinute(12));
System.out.println("3.修改秒为12:" + currentTime.withSecond(12));

2.3 线程安全

网上大家都在说Java 8提供的LocalDateTime是线程安全的,但是它是如何实现的呢,今天让我们来挖一挖:

public final class LocalDateTimeimplements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable {... }

由上面的源码可知,LocalDateTime是不可变类。我们都知道一个Java并发编程规则:不可变对象永远是线程安全的。

对比下Date的源码 ,Date是可变类,所以是线程不安全的。

public class Dateimplements java.io.Serializable, Cloneable, Comparable<Date>
{
...
}

3、LocalDateTime和Date相互转化

3.1 Date转LocalDateTime

System.out.println("------------------方法一:分步写-----------------------");
//实例化一个时间对象
Date date = new Date();
//返回表示时间轴上同一点的瞬间作为日期对象
Instant instant = date.toInstant();
//获取系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
//根据时区获取带时区的日期和时间
ZonedDateTime zonedDateTime = instant.atZone(zoneId);
//转化为LocalDateTime
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
System.out.println("方法一:原Date = " + date);
System.out.println("方法一:转化后的LocalDateTime = " + localDateTime);System.out.println("------------------方法二:一步到位(推荐使用)-----------------------");
//实例化一个时间对象
Date todayDate = new Date();
//Instant.ofEpochMilli(long l)使用1970-01-01T00:00:00Z的纪元中的毫秒来获取Instant的实例
LocalDateTime ldt = Instant.ofEpochMilli(todayDate.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println("方法二:原Date = " + todayDate);
System.out.println("方法二:转化后的LocalDateTime = " + ldt);

3.2 LocalDateTime转Date

System.out.println("------------------方法一:分步写-----------------------");
//获取LocalDateTime对象,当前时间
LocalDateTime localDateTime = LocalDateTime.now();
//获取系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
//根据时区获取带时区的日期和时间
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
//返回表示时间轴上同一点的瞬间作为日期对象
Instant instant = zonedDateTime.toInstant();
//转化为Date
Date date = Date.from(instant);
System.out.println("方法一:原LocalDateTime = " + localDateTime);
System.out.println("方法一:转化后的Date = " + date);System.out.println("------------------方法二:一步到位(推荐使用)-----------------------");
//实例化一个LocalDateTime对象
LocalDateTime now = LocalDateTime.now();
//转化为date
Date dateResult = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("方法二:原LocalDateTime = " + now);
System.out.println("方法二:转化后的Date = " + dateResult);

四、DateTimeFormatter

4.1DateTimeFormatter类说明

DateTimeFormatter的作用是进行格式化显示,且DateTimeFormatter是不可变类且是线程安全的。

public final class DateTimeFormatter {
...
}

说到时间的格式化显示,就要说老朋友SimpleDateFormat了,之前格式化Date就要用上。但是我们知道SimpleDateFormat是线程不安全的,文前有介绍。

4.2 DateTimeFormatter常用的用法

ZonedDateTime zonedDateTime = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm ZZZZ");
System.out.println(formatter.format(zonedDateTime));DateTimeFormatter usFormatter = DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm", Locale.US);
System.out.println(usFormatter.format(zonedDateTime));DateTimeFormatter chinaFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm", Locale.CHINA);
System.out.println(chinaFormatter.format(zonedDateTime));

总结

《Java核心技术》 它不仅仅是一本书,还是学习Java语言的进阶路径指导。它高层建瓯地介绍了Java语言的核心概念、语法、重要特性,又对Java语言基础知识进行了专业级详解。既照顾了新手易入门,易上手,也照顾到了中高级Java开发人员需要了解的高级主题。

书也要与时俱进,刚好响应了技术更新换代的市场需求。对于开发人员来说,学习有用的新技术是必要的。选择大于努力,一本优秀的书籍可以让我们不走弯路,而 《Java核心技术》 正是我们值得花时间去学习研究的一本好书。

更多精彩回顾

书讯 | 5月书讯(上)|  元宇宙、因果推断、薛定谔方程...你关注的都在这

书讯 | 5月书讯(下)|设计致物系列+少儿编程好书推荐

资讯 |为企业数字人才建粮仓:专访极客邦科技双数研究院院长付晓岩

资讯 |2022美国科学院院士名单公布:图灵奖得主、龙书作者Alfred V. Aho当选!

干货 | 为什么每一名程序员都应该学习 C++?

干货 | 如果机器翻译始终存在缺陷和错误,那它还有什么用处?

Java核心技术:日期和时间新旧API对比相关推荐

  1. 详解java中的日期与时间;新旧API对比;各种日期格式转换

    一.基本概念 1.本地时间 不同的时区,在同一时刻,本地时间是不同的. 全球一共分为24个时区,伦敦所在的时区称为标准时区,其他时区按东/西偏移的小时区分,北京所在的时区是东八区. 2.时区 GMT ...

  2. Untiy InputSystem(一) 新旧API对比

    前言 新的输入系统在跨平台方面便捷了不少,最近公司在弄工具,其中一个功能就是希望实现PC和VR及其他平台的快速切换,输入模块正好用的上,先简单梳理下,后面有空再仔细研究. 一.前置操作 1.官方文档 ...

  3. 深入了解Java 8日期和时间API

    在这篇文章中,我们将更深入地了解通过Java 8获得的新的Date / Time API( JSR 310 ). 请注意,本文主要由显示新API功能的代码示例驱动. 我认为这些示例是不言自明的,因此我 ...

  4. java打印日期序列_Java8新特性之新日期API

    早期的日期 API 在早期也就是 Java 8 之前,JDK 原生比较有名的有两个类: Date 类 Calendar 类 这两个类相对来说用起来是比较困难的,之前我们往往是用的第三方的库. 新日期 ...

  5. Date - Java处理日期和时间

    在计算机中如何表示日期和时间呢,我们可以想到有几种表示方式,一种是2016-11-20 8::15:01 GMT+08:00,或者我们用其他的时区,比如GMT+00:00标准时区,或者 America ...

  6. Java 8 - 日期和时间实用技巧

    Java 8 – 日期和时间实用技巧 当你开始使用Java操作日期和时间的时候,会有一些棘手.你也许会通过System.currentTimeMillis() 来返回1970年1月1日到今天的毫秒数. ...

  7. Java 8 日期和时间解读

    转载自 Java 8 日期和时间解读 现在,一些应用程序仍然在使用java.util.Date和java.util.Calendar API和它们的类库,来使我们在生活中更加轻松的处理日期和时间,比如 ...

  8. Java 8 日期、时间、时间矫正器操作

    Java 8 日期.时间操作 真放肆不在饮酒放荡,假矜持偏要慷慨激昂.万事留一线,江湖好相见–老郭经典语录 本篇描述LocalDate.LocalTime.LocalDateTime.Temporal ...

  9. Java的日期与时间java.time.Duration的简介说明

    转自: Java的日期与时间java.time.Duration的简介说明 下文笔者讲述Duration类的简介说明,如下所示 Duration类简介 Duration对象:表示两个Instant间的 ...

最新文章

  1. 盘点丨2017年人工智能带火了哪些词
  2. HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
  3. (解决)mysql1366中文显示错误的终极解决方案
  4. Amazon S3和Swift鉴权机制分析
  5. Enze frist day
  6. Linux下redis的安装及用法
  7. 计算机模拟试题3,计算机一级考试MSoffice全真模拟试题3
  8. 【0xC1900101】BOOT过程中的SAFE_OS阶段安装win10失败的解决方法
  9. java实现模拟考试系统_基于JAVA SWING考试模拟系统.doc
  10. 电子邮件链接mailto_“ 3个链接”电子邮件的历史记录以及曾经发送的每个链接的存档...
  11. MyBatis整合Spring的实现(7)
  12. 捷普服务器群组防护系统,捷普入侵防御系统
  13. 删除自定义reg注册表
  14. 手机照片删了怎么恢复
  15. matlab 矩阵命令,matlab中的矩阵的基本运算命令
  16. graphQL入门分享
  17. union与order by 结合使用
  18. [256个管理学理论]006.刺猬效应(Hedgehog Effect)
  19. PCB检查-allegro PDN进行简单电源直流压降分析
  20. 2021年度中国科学之十大进展

热门文章

  1. spring boot 整合 jetcache 相关错误
  2. 【数据库教程】MySQL 复制表
  3. OpenHarmony轻量系统开发【14】使用语音控制鸿蒙小车
  4. [附源码]Python计算机毕业设计SSM基于web的烟草售卖系统(程序+LW)
  5. 计算机考研难度特别大吗,计算机考研难度大吗?学姐为你深度剖析
  6. 深度解析:播音主持配音与影视动漫游戏配音的区别
  7. PASCAL VOC统计各类目标数量
  8. 科技界的大事这4件事是指_科技界最响亮的声音是男性
  9. 使用两种脉冲神经网络(Spiking Neural Network)预测脑电图的癫痫发作:基于LIF神经元模型的实践与分析
  10. 六级备考23天|CET-6|翻译技巧4|2013年官方样题|新年|9:45~11:00