Java 中文官方教程 2022 版(二十七)(3)https://developer.aliyun.com/article/1486852
不可变单例集合
有时你会需要一个不可变的单例Set
,它由一个指定的元素组成。Collections.singleton
方法返回这样一个Set
。这种实现的一个用途是从Collection
中删除所有指定元素的出现。
c.removeAll(Collections.singleton(e));
一个相关的惯用法是从Map
中删除映射到指定值的所有元素。例如,假设你有一个将人员映射到他们的工作领域的Map
— job
— 并且假设你想要消除所有律师。下面的一行代码就能完成任务。
job.values().removeAll(Collections.singleton(LAWYER));
这种实现的另一个用途是为一个写成接受值集合的方法提供单个输入值。
空 Set、List 和 Map 常量
Collections
类提供了返回空Set
、List
和Map
的方法 — emptySet
、emptyList
和emptyMap
。这些常量的主要用途是作为不提供任何值时作为值的集合的输入方法的输入,就像这个例子中一样。
tourist.declarePurchases(Collections.emptySet());
实现摘要
原文:
docs.oracle.com/javase/tutorial/collections/implementations/summary.html
实现是用于存储集合的数据对象,这些对象实现了接口课程中描述的接口。
Java 集合框架提供了几个核心接口的通用实现:
- 对于
Set
接口,HashSet
是最常用的实现。 - 对于
List
接口,ArrayList
是最常用的实现。 - 对于
Map
接口,HashMap
是最常用的实现。 - 对于
Queue
接口,LinkedList
是最常用的实现。 - 对于
Deque
接口,ArrayDeque
是最常用的实现。
每个通用实现提供其接口中包含的所有可选操作。
Java 集合框架还提供了几个特殊用途的实现,用于需要非标准性能、使用限制或其他异常行为的情况。
java.util.concurrent
包含几个集合实现,这些实现是线程安全的,但不受单个排他锁的控制。
Collections
类(与Collection
接口相对),提供了在集合上操作或返回集合的静态方法,这些方法被称为包装器实现。
最后,还有几个便利实现,当您不需要它们的全部功能时,这些便利实现可能比通用实现更有效。这些便利实现通过静态工厂方法提供。
问题和练习:实现方式
原文:
docs.oracle.com/javase/tutorial/collections/implementations/QandE/questions.html
问题
- 你计划编写一个程序,使用几个基本的集合接口:
Set
、List
、Queue
和Map
。你不确定哪种实现方式最适合,所以决定在了解程序在实际环境中如何运行之前,先使用通用的实现方式。这些实现方式是哪些? - 如果你需要一个提供按值排序迭代的
Set
实现,应该使用哪个类? - 你使用哪个类来访问包装器实现?
练习
- 编写一个程序,将由第一个命令行参数指定的文本文件读入一个
List
中。然后,程序应该打印文件中的随机行,打印的行数由第二个命令行参数指定。编写程序时,应一次性分配正确大小的集合,而不是在读取文件时逐渐扩展。提示:要确定文件中的行数,可以使用java.io.File.length
来获取文件的大小,然后除以平均行的假定大小。
检查你的答案。
教训:算法
原文:
docs.oracle.com/javase/tutorial/collections/algorithms/index.html
这里描述的多态算法是 Java 平台提供的可重用功能块。所有这些功能块都来自Collections
类,并且都采用静态方法的形式,其第一个参数是要执行操作的集合。Java 平台提供的绝大多数算法都是在List
实例上操作的,但其中有一些是在任意Collection
实例上操作的。本节简要描述了以下算法:
- 排序
- 洗牌
- 常规数据操作
- 搜索
- 组合
- 查找极值
排序
sort
算法重新排列一个List
,使其元素按照一种排序关系升序排列。提供了两种形式的操作。简单形式接受一个List
,并根据其元素的自然排序对其进行排序。如果您对自然排序的概念不熟悉,请阅读对象排序部分。
sort
操作使用了一个稍微优化的归并排序算法,速度快且稳定:
- 快速:它保证在
n log(n)
时间内运行,并在几乎排序好的列表上运行得更快。经验测试表明它与高度优化的快速排序一样快。快速排序通常被认为比归并排序更快,但不稳定且不能保证n log(n)
性能。 - 稳定:它不会重新排序相等的元素。这一点对于在不同属性上重复对同一列表进行排序很重要。如果邮件程序的用户按邮件日期对收件箱进行排序,然后按发件人对其进行排序,用户自然期望来自同一发件人的现在连续的邮件列表仍然按邮件日期排序。只有第二次排序是稳定的才能保证这一点。
以下简单程序
按字典顺序打印出其参数。
import java.util.*; public class Sort { public static void main(String[] args) { List<String> list = Arrays.asList(args); Collections.sort(list); System.out.println(list); } }
让我们运行程序。
% java Sort i walk the line
产生了以下输出。
[i, line, the, walk]
该程序仅用于向您展示算法确实像看起来那样易于使用。
第二种sort
形式除了List
之外还需要一个Comparator
,并使用Comparator
对元素进行排序。假设你想要按照我们之前示例中的字谜分组的大小倒序打印出来,即最大的字谜组首先显示。接下来的示例展示了如何借助sort
方法的第二种形式实现这一目标。
请记住,变位词组以List
实例的形式存储在Map
中的值中。修改后的打印代码通过Map
的值视图迭代,将通过最小大小测试的每个List
放入一个List
的List
中。然后,该代码对此List
进行排序,使用一个期望List
实例的Comparator
,并实现逆大小排序。最后,该代码对排序后的List
进行迭代,打印其元素(变位词组)。以下代码替换了Anagrams
示例中main
方法末尾的打印代码。
// Make a List of all anagram groups above size threshold. List<List<String>> winners = new ArrayList<List<String>>(); for (List<String> l : m.values()) if (l.size() >= minGroupSize) winners.add(l); // Sort anagram groups according to size Collections.sort(winners, new Comparator<List<String>>() { public int compare(List<String> o1, List<String> o2) { return o2.size() - o1.size(); }}); // Print anagram groups. for (List<String> l : winners) System.out.println(l.size() + ": " + l);
在与 The Map Interface 部分相同的字典上运行程序
,具有相同的最小变位词组大小(八),产生以下输出。
12: [apers, apres, asper, pares, parse, pears, prase, presa, rapes, reaps, spare, spear] 11: [alerts, alters, artels, estral, laster, ratels, salter, slater, staler, stelar, talers] 10: [least, setal, slate, stale, steal, stela, taels, tales, teals, tesla] 9: [estrin, inerts, insert, inters, niters, nitres, sinter, triens, trines] 9: [capers, crapes, escarp, pacers, parsec, recaps, scrape, secpar, spacer] 9: [palest, palets, pastel, petals, plates, pleats, septal, staple, tepals] 9: [anestri, antsier, nastier, ratines, retains, retinas, retsina, stainer, stearin] 8: [lapse, leaps, pales, peals, pleas, salep, sepal, spale] 8: [aspers, parses, passer, prases, repass, spares, sparse, spears] 8: [enters, nester, renest, rentes, resent, tenser, ternes,��treens] 8: [arles, earls, lares, laser, lears, rales, reals, seral] 8: [earings, erasing, gainers, reagins, regains, reginas, searing, seringa] 8: [peris, piers, pries, prise, ripes, speir, spier, spire] 8: [ates, east, eats, etas, sate, seat, seta, teas] 8: [carets, cartes, caster, caters, crates, reacts, recast,��traces]
洗牌
shuffle
算法与sort
的作用相反,破坏了List
中可能存在的任何顺序痕迹。换句话说,该算法根据来自随机源的输入重新排序List
,以使所有可能的排列以相等的概率发生,假设有一个公平的随机源。该算法在实现游戏机会时非常有用。例如,它可以用来洗牌代表一副牌的Card
对象的List
。此外,它还用于生成测试用例。
此操作有两种形式:一种接受一个List
并使用默认的随机源,另一种要求调用者提供一个Random对象作为随机源。该算法的代码被用作List
部分的示例。
常规数据操作
Collections
类提供了五种用于在List
对象上进行常规数据操作的算法,所有这些算法都非常简单:
reverse
— 颠倒List
中元素的顺序。fill
— 用指定值覆盖List
中的每个元素。此操作对重新初始化List
非常有用。copy
— 接受两个参数,目标List
和源List
,并将源的元素复制到目标中,覆盖其内容。目标List
的长度必须至少与源相同。如果目标更长,则目标中剩余的元素不受影响。swap
— 交换List
中指定位置的元素。addAll
— 将所有指定的元素添加到Collection
中。要添加的元素可以逐个指定,也可以作为数组指定。
搜索
binarySearch
算法在排序的List
中搜索指定的元素。该算法有两种形式。第一种接受一个List
和一个要搜索的元素(“搜索键”)。这种形式假定List
根据其元素的自然顺序按升序排序。第二种形式除了List
和搜索键外还接受一个Comparator
,并假定List
根据指定的Comparator
按升序排序。在调用binarySearch
之前,可以使用sort
算法对List
进行排序。
两种形式的返回值相同。如果List
包含搜索键,则返回其索引。如果没有,则返回值为(-(插入点) - 1)
,其中插入点是将值插入List
的位置,或者大于该值的第一个元素的索引,或者list.size()
如果List
中的所有元素都小于指定值。这个确实丑陋的公式保证了返回值仅当找到搜索键时为>= 0
。这基本上是一个将布尔值(found)
和整数值(index)
组合成单个int
返回值的技巧。
下面的习语可用于binarySearch
操作的两种形式,查找指定的搜索键,并在适当位置插入它(如果尚未存在)。
int pos = Collections.binarySearch(list, key); if (pos < 0) l.add(-pos-1, key);
组成
频率和不相交算法测试一个或多个Collections
的组成方面:
frequency
— 计算指定元素在指定集合中出现的次数disjoint
— 确定两个Collections
是否不相交;即它们是否没有共同元素。
查找极值
min
和max
算法分别返回指定Collection
中包含的最小和最大元素。这两个操作有两种形式。简单形式只接受一个Collection
,根据元素的自然顺序返回最小(或最大)元素。第二种形式除了Collection
外还接受一个Comparator
,根据指定的Comparator
返回最小(或最大)元素。
教训:自定义集合实现
原文:
docs.oracle.com/javase/tutorial/collections/custom-implementations/index.html
许多程序员永远不需要实现自己的Collection
类。您可以通过使用本章前面描述的实现来走得很远。但是,总有一天您可能想要编写自己的实现。借助 Java 平台提供的抽象实现,这样做相当容易。在讨论如何编写实现之前,让我们讨论一下为什么您可能想要编写一个。
编写实现的原因
以下列表说明了您可能想要实现的自定义Collection
类型。这并不是详尽无遗的:
- 持久性:所有内置的
Collection
实现都驻留在主内存中,并在程序退出时消失。如果您希望在下次程序启动时仍然存在的集合,可以通过在外部数据库上构建一个薄层来实现它。这样的集合可能可以被多个程序同时访问。 - 特定应用:这是一个非常广泛的类别。一个例子是包含实时遥测数据的不可修改的
Map
。键可以表示位置,值可以根据get
操作从这些位置的传感器中读取。 - 高性能,特定用途:许多数据结构利用受限使用来提供比通用实现更好的性能。例如,考虑一个包含长时间相同元素值的
List
。这样的列表在文本处理中经常出现,可以进行运行长度编码 — 运行可以表示为包含重复元素和连续重复次数的单个对象。这个例子很有趣,因为它在性能方面进行了权衡:它需要更少的空间但比ArrayList
需要更多的时间。 - 高性能,通用用途:Java 集合框架的设计者试图为每个接口提供最佳的通用实现,但是可以使用许多许多数据结构,并且每天都会有新的数据结构被发明。也许您可以想出更快的解决方案!
- 增强功能:假设您需要一个高效的包实现(也称为multiset):一个
Collection
,它在允许重复元素的同时提供常数时间的包含性检查。在HashMap
之上实现这样一个集合是相当简单的。 - 便利性:您可能希望提供超出 Java 平台提供的便利的其他实现。例如,您可能经常需要表示一系列
Integer
的连续范围的List
实例。 - 适配器:假设您正在使用具有自己的特定集合 API 的旧 API。您可以编写一个适配器实现,使这些集合能够在 Java 集合框架中运行。适配器实现是一个薄膜,包装一种类型的对象,并通过将对后者类型的操作转换为对前者类型的操作来使其行为类似于另一种类型的对象。
如何编写自定义实现
编写自定义实现出人意料地容易。Java 集合框架提供了专门设计用于促进自定义实现的抽象实现。我们将从以下Arrays.asList
实现的示例开始。
public static <T> List<T> asList(T[] a) { return new MyArrayList<T>(a); } private static class MyArrayList<T> extends AbstractList<T> { private final T[] a; MyArrayList(T[] array) { a = array; } public T get(int index) { return a[index]; } public T set(int index, T element) { T oldValue = a[index]; a[index] = element; return oldValue; } public int size() { return a.length; } }
信不信由你,这与包含在java.util.Arrays
中的实现非常接近。就是这么简单!您提供一个构造函数和get
,set
和size
方法,AbstractList
会处理其余的所有事情。您将获得ListIterator
,批量操作,搜索操作,哈希码计算,比较和字符串表示。
假设您想让实现变得更快一点。抽象实现的 API 文档准确描述了每个方法的实现方式,因此您将知道要重写哪些方法以获得所需的性能。前面的实现性能很好,但可以稍微改进一下。特别是,toArray
方法会遍历List
,一次复制一个元素。鉴于内部表示,仅克隆数组会更快更合理。
public Object[] toArray() { return (Object[]) a.clone(); }
添加此覆盖和其他几个类似的覆盖后,此实现与java.util.Arrays
中找到的实现完全相同。为了充分披露,使用其他抽象实现会有点困难,因为您将不得不编写自己的迭代器,但仍然不是那么困难。
以下列表总结了抽象实现:
AbstractCollection
— 既不是Set
也不是List
的Collection
。至少,您必须提供iterator
和size
方法。AbstractSet
— 一个Set
;使用方式与AbstractCollection
相同。AbstractList
— 由随机访问数据存储支持的List
。至少,您必须提供位置访问
方法(get
,可选的set
,remove
和add
)以及size
方法。抽象类负责listIterator
(和iterator
)。AbstractSequentialList
— 由顺序访问数据存储支持的List
,例如链表。至少,你必须提供listIterator
和size
方法。抽象类负责处理位置访问方法。(这与AbstractList
相反。)AbstractQueue
— 至少,你必须提供offer
、peek
、poll
和size
方法以及支持remove
的iterator
。AbstractMap
— 一个Map
。至少你必须提供entrySet
视图。通常使用AbstractSet
类来实现。如果Map
是可修改的,你还必须提供put
方法。
编写自定义实现的过程如下:
- 从上述列表中选择适当的抽象实现类。
- 为类的所有抽象方法提供实现。如果你的自定义集合是可修改的,你还必须重写一个或多个具体方法。抽象实现类的 API 文档将告诉你哪些方法需要重写。
- 测试并且,如果需要,调试实现。现在你有一个可工作的自定义集合实现。
- 如果你关心性能,阅读抽象实现类的 API 文档,了解你要继承的所有方法的实现。如果有任何方法看起来太慢,就重写它们。如果你重写任何方法,请确保在重写之前和之后测量方法的性能。调整性能的努力程度应该取决于实现的使用程度以及其使用对性能的关键性。 (通常最好省略此步骤。)
课程:互操作性
原文:
docs.oracle.com/javase/tutorial/collections/interoperability/index.html
在这一部分,您将学习互操作性的以下两个方面:
- 兼容性:本小节描述了如何使集合能够与早于将
Collection
添加到 Java 平台的旧 API 一起工作。 - API 设计:本小节描述了如何设计新的 API,以便它们能够与其他 API 无缝互操作。
兼容性
原文:
docs.oracle.com/javase/tutorial/collections/interoperability/compatibility.html
Java 集合框架旨在确保核心集合接口与早期 Java 平台版本中用于表示集合的类型之间的完全互操作性:Vector
,Hashtable
,数组,以及Enumeration
。在本节中,您将学习如何将旧集合转换为 Java 集合框架集合,反之亦然。
向上兼容性
假设你正在使用一个返回传统集合的 API 以及另一个 API,需要对象实现集合接口。为了使这两个 API 顺利互操作,你必须将传统集合转换为现代集合。幸运的是,Java 集合框架使这变得容易。
假设旧的 API 返回一个对象数组,而新的 API 需要一个Collection
。集合框架有一个方便的实现,允许将对象数组视为List
。你可以使用Arrays.asList
将数组传递给任何需要Collection
或List
的方法。
Foo[] result = oldMethod(arg); newMethod(Arrays.asList(result));
如果旧的 API 返回一个Vector
或Hashtable
,你根本不需要做任何工作,因为Vector
已经被改装为实现List
接口,而Hashtable
已经被改装为实现Map
。因此,Vector
可以直接传递给任何需要Collection
或List
的方法。
Vector result = oldMethod(arg); newMethod(result);
类似地,Hashtable
可以直接传递给任何需要Map
的方法。
Hashtable result = oldMethod(arg); newMethod(result);
较少情况下,一个 API 可能返回一个代表对象集合的Enumeration
。Collections.list
方法将Enumeration
转换为Collection
。
Enumeration e = oldMethod(arg); newMethod(Collections.list(e));
向后兼容性
假设你正在使用一个返回现代集合的 API 以及另一个 API,需要你传递传统集合。为了使这两个 API 顺利互操作,你必须将现代集合转换为旧集合。同样,Java 集合框架使这变得容易。
假设新的 API 返回一个Collection
,而旧的 API 需要一个Object
数组。正如你可能知道的那样,Collection
接口包含一个专门设计用于这种情况的toArray
方法。
Collection c = newMethod(); oldMethod(c.toArray());
如果旧的 API 需要一个String
数组(或其他类型)而不是一个Object
数组怎么办?你只需使用toArray
的另一种形式 — 需要一个数组作为输入的形式。
Collection c = newMethod(); oldMethod((String[]) c.toArray(new String[0]));
如果旧的 API 需要一个Vector
,标准集合构造函数会派上用场。
Collection c = newMethod(); oldMethod(new Vector(c));
需要Hashtable
的旧 API 的情况类似处理。
Map m = newMethod(); oldMethod(new Hashtable(m));
最后,如果旧的 API 需要一个Enumeration
怎么办?这种情况并不常见,但偶尔会发生,Collections.enumeration
方法就是为了处理这种情况而提供的。这是一个静态工厂方法,接受一个Collection
并返回该Collection
中元素的Enumeration
。
Collection c = newMethod(); oldMethod(Collections.enumeration(c));
API 设计
原文:
docs.oracle.com/javase/tutorial/collections/interoperability/api-design.html
在这个简短但重要的部分,你将学到一些简单的准则,让你的 API 能够与遵循这些准则的所有其他 API 无缝交互。实质上,这些规则定义了在集合世界中成为一个好“公民”所需的条件。
参数
如果你的 API 包含一个需要在输入时传入集合的方法,那么声明相关参数类型为集合接口类型至关重要。永远不要使用实现类型,因为这违背了基于接口的集合框架的目的,即允许集合在不考虑实现细节的情况下进行操作。
此外,你应该始终使用最不具体的类型。例如,如果Collection
足够了,就不要要求一个List
或者一个Set
。并不是说你在输入时永远不应该要求一个List
或者Set
;如果一个方法依赖于这些接口的属性,那么这样做是正确的。例如,Java 平台提供的许多算法在输入时需要一个List
,因为它们依赖于列表是有序的这一事实。然而,作为一般规则,最好在输入时使用最通用的类型:Collection
和Map
。
注意: 永远不要定义自己的临时collection
类,并要求在输入时使用这些类的对象。这样做会使你失去 Java 集合框架提供的所有好处。
返回值
对于返回值,你可以比输入参数更加灵活。可以返回任何实现或扩展集合接口之一的类型的对象。这可以是接口之一,也可以是扩展或实现这些接口的特殊用途类型。
例如,可以想象一个图像处理包,称为ImageList
,它返回实现List
的新类的对象。除了List
操作外,ImageList
还可以支持任何看起来有用的特定应用操作。例如,它可能提供一个indexImage
操作,返回一个包含ImageList
中每个图形缩略图的图像。需要注意的是,即使 API 在输出时提供ImageList
实例,它也应该接受任意的Collection
(或者也许是List
)实例作为输入。
从某种意义上说,返回值应该具有与输入参数相反的行为:最好返回最具体的适用集合接口,而不是最一般的。例如,如果你确定总是返回一个SortedMap
,你应该给相关方法返回类型为SortedMap
,而不是Map
。SortedMap
实例比普通的Map
实例更耗时构建,也更强大。考虑到你的模块已经投入了时间来构建SortedMap
,让用户访问其增强功能是明智的。此外,用户将能够将返回的对象传递给需要SortedMap
的方法,以及接受任何Map
的方法。
传统 API
目前有很多 API 定义了自己的临时集合类型。虽然这很不幸,但考虑到 Java 平台的前两个主要版本中没有集合框架,这是现实。假设你拥有其中一个这样的 API;以下是你可以采取的措施。
如果可能的话,更新你的传统集合类型以实现标准集合接口之一。然后,你返回的所有集合将与其他基于集合的 API 无缝地进行交互。如果这是不可能的(例如,因为一个或多个现有类型签名与标准集合接口冲突),定义一个适配器类,包装你的传统集合对象之一,使其能够作为标准集合运行。(Adapter
类是自定义实现的一个示例。)
如果可能的话,通过新的调用来更新你的 API,遵循输入指南以接受标准集合接口的对象。这样的调用可以与接受传统集合类型的调用共存。如果这是不可能的,为你的传统类型提供一个构造函数或静态工厂,接受一个标准接口的对象,并返回包含相同元素(或映射)的传统集合。这两种方法中的任何一种都将允许用户将任意集合传递给你的 API。
教程:日期时间
日期时间包,java.time,在 Java SE 8 发布中引入,提供了一个全面的日期和时间模型,并在JSR 310: 日期和时间 API下开发。虽然java.time
基于国际标准化组织(ISO)日历系统,但也支持常用的全球日历。
这个教程涵盖了使用基于 ISO 的类来表示日期和时间以及操作日期和时间值的基础知识。
教训:日期时间概述
原文:
docs.oracle.com/javase/tutorial/datetime/overview/index.html
时间似乎是一个简单的主题;即使是一只廉价的手表也可以提供相当准确的日期和时间。然而,仔细观察后,你会意识到时间的微妙复杂性和许多影响你对时间理解的因素。例如,将一个月加到 1 月 31 日的结果对于闰年和其他年份是不同的。时区也增加了复杂性。例如,一个国家可能会在短时间内进入和退出夏令时,或者一年内多次进入和退出夏令时,或者在某一年完全跳过夏令时。
日期时间 API 使用ISO-8601中定义的日历系统作为默认日历。这个日历基于格里高利历系统,在全球范围内被用作代表日期和时间的事实标准。日期时间 API 中的核心类的名称如LocalDateTime
、ZonedDateTime
和OffsetDateTime
。所有这些类都使用 ISO 日历系统。如果你想使用另一个日历系统,比如伊斯兰历或泰国佛历,java.time.chrono
包允许你使用其中一个预定义的日历系统。或者你也可以创建自己的日历系统。
日期时间 API 使用Unicode 通用区域数据存储库 (CLDR)。这个存储库支持世界上的语言,并包含可用的最大的区域数据集合。这个存储库中的信息已被本地化到数百种语言。日期时间 API 还使用时区数据库 (TZDB)。这个数据库提供自 1970 年以来全球每个时区变更的信息,以及自该概念引入以来主要时区的历史。
日期时间设计原则
原文:
docs.oracle.com/javase/tutorial/datetime/overview/design.html
日期时间 API 是根据几个设计原则开发的。
清晰
API 中的方法被明确定义,其行为清晰可预期。例如,使用null
参数值调用日期时间方法通常会触发NullPointerException
。
流畅
日期时间 API 提供了流畅的接口,使代码易于阅读。因为大多数方法不允许带有null
值的参数,并且不返回null
值,方法调用可以链接在一起,结果代码可以快速理解。例如:
LocalDate today = LocalDate.now(); LocalDate payday = today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2);
不可变
日期时间 API 中的大多数类创建的对象是不可变的,这意味着在对象创建后,它是不能被修改的。要修改不可变对象的值,必须构建一个修改后的原始副本作为新对象。这也意味着日期时间 API 在定义上是线程安全的。这影响了 API,大多数用于创建日期或时间对象的方法都以of
、from
或with
为前缀,而不是构造函数,并且没有set
方法。例如:
LocalDate dateOfBirth = LocalDate.of(2012, Month.MAY, 14); LocalDate firstBirthday = dateOfBirth.plusYears(1);
可扩展
日期时间 API 在尽可能的地方是可扩展的。例如,您可以定义自己的时间调整器和查询,或构建自己的日历系统。
日期时间包
原文:
docs.oracle.com/javase/tutorial/datetime/overview/packages.html
日期时间 API 由主要包java.time
和四个子包组成:
java.time
该 API 的核心用于表示日期和时间。它包括了日期、时间、日期和时间的组合、时区、瞬间、持续时间和时钟的类。这些类基于 ISO-8601 中定义的日历系统,是不可变的和线程安全的。
java.time.chrono
用于表示除默认 ISO-8601 之外的日历系统的 API。您也可以定义自己的日历系统。本教程不会详细介绍这个包。
java.time.format
用于格式化和解析日期和时间的类。
java.time.temporal
扩展 API,主要用于框架和库的编写者,允许日期和时间类之间的互操作,查询和调整。在这个包中定义了字段(TemporalField
和 ChronoField
)和单位(TemporalUnit
和 ChronoUnit
)。
java.time.zone
支持时区、时区偏移和时区规则的类。如果涉及时区,大多数开发人员只需要使用ZonedDateTime
、ZoneId
或ZoneOffset
。