在 Java 中對日期字符串進行排序
一、概述
在處理包含字符串格式的日期時間的數據集時,對這些字符串進行排序是許多 Java 應用程序中的一項常見任務。
在本教程中,我們將探討在 Java 中有效排序日期字符串的不同方法。
二、問題介紹
我們可以直接按特定日期格式對字符串進行字典順序排序,例如 ISO 日期時間格式 ( YYYY-MM-dd'T' HH:mm:ss
)。但是,這不是排序日期字符串的通用解決方案。
我們不能對所有日期時間格式應用字典排序操作。例如,假設我們有這樣一個字符串列表:
List<String> dtStrings = Lists.newArrayList(
"01/21/2013 10:41",
"01/20/2013 10:48",
"01/22/2013 15:13",
"01/21/2013 16:37",
"01/21/2013 17:16",
"01/21/2013 17:19",
"01/20/2013 06:16",
"01/22/2013 06:19"
);
如果列表中的字符串排序正確,結果應該如下所示:
List<String> EXPECTED = Lists.newArrayList(
"01/20/2013 06:16",
"01/20/2013 10:48",
"01/21/2013 10:41",
"01/21/2013 16:37",
"01/21/2013 17:16",
"01/21/2013 17:19",
"01/22/2013 06:19",
"01/22/2013 15:13"
);
我們將探索解決排序問題的不同方法。此外,為簡單起見,我們將使用單元測試斷言來驗證每個解決方案是否產生預期結果。
接下來,讓我們看看它們的實際效果。
3. 使用自定義Comparator
Java 標準庫提供了Collections.sort()
方法來對集合中的元素進行排序。如果我們想按字典順序對字符串列表進行排序,我們可以簡單地將列表傳遞給Collections.sort()
方法。此外,該方法也接受Comparator
對像作為第二個參數。
接下來,讓我們看看如何使用自定義Comparator
對日期時間字符串進行排序:
DateFormat dfm = new SimpleDateFormat("MM/dd/yyyy HH:mm");
Collections.sort(dtStrings, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
try {
return dfm.parse(o1).compareTo(dfm.parse(o2));
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
});
assertEquals(EXPECTED, dtStrings);
如上面的代碼所示,首先,我們根據日期字符串格式創建了一個SimpleDateFormat
對象。然後,當我們調用Collections.sort()
方法時,我們將dtStrings
列表與匿名Comparator
對像一起傳遞。
在compare()
方法實現中,我們首先將兩個日期時間字符串解析為Date
對象,然後比較兩個Date
對象。
如果我們的 Java 版本是 8 或更高,我們可以使用強大的 compare with lambdas 特性來使我們的代碼緊湊且更易於閱讀:
final DateTimeFormatter dfm = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm");
dtStrings.sort(Comparator.comparing(s -> LocalDateTime.parse(s, dfm)));
assertEquals(EXPECTED, dtStrings);
重要的是要注意**Collections.sort()
和list.sort()
方法都有助於就地排序,這意味著直接修改原始列表而不創建新的排序副本**。這在內存效率和性能方面提供了顯著的優勢。
4. 使用流 API
此外,要對日期時間字符串列表進行排序,我們可以採用三步法:
- 將
String
元素轉換為LocalDateTime
實例 - 對那些
LocalDateTime
對象進行排序 - 將
LocalDateTime
對象轉換回String
s
Stream API 讓我們可以方便的處理集合。如果我們用 Stream API 實現這個想法, map()
方法可以幫助我們執行轉換:
DateTimeFormatter dfm = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm");
List<String> sortedList = dtStrings.stream()
.map(s -> LocalDateTime.parse(s, dfm))
.sorted()
.map(dfm::format)
.collect(Collectors.toList());
assertEquals(EXPECTED, sortedList);
與Collections.sort()
和list.sort()
解決方案不同,此方法不會更改原始列表。相反,它返回一個新列表來保存排序後的字符串。
5. 使用TreeMap
Java 中的TreeMap
類提供了基於鍵的條目自動排序。通過使用此功能,我們可以通過使用類型為LocalDateTime
和 String 的鍵值對創建TreeMap
來輕鬆地對日期時間字符串進行排序String.
然後,如果我們從TreeMap
中獲取所有值,例如,使用treeMap.values()
方法,我們將得到排序後的結果。
接下來,讓我們在測試中實現它:
DateTimeFormatter dfm = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm");
Map<LocalDateTime, String> dateFormatMap = new TreeMap<>();
dtStrings.forEach(s -> dateFormatMap.put(LocalDateTime.parse(s, dfm), s));
List<String> result = new ArrayList<>(dateFormatMap.values());
assertEquals(EXPECTED, result);
這個解決方案很簡單。然而,它有一個缺點。由於標準 Java Map
不能有重複的鍵,重複的日期時間字符串將在排序列表中丟失。因此,在我們應用TreeMap
方法對它們進行排序之前,最好確保列表不包含重複值。
六,結論
在本文中,我們探討了對日期字符串進行排序的不同通用解決方案:
-
Collections.sort()
和list.sort()
帶有自定義Comparator
(就地排序) - 將字符串轉換為日期對象,對對象進行排序,並將它們轉換回日期字符串
-
TreeMap
方法
與往常一樣,此處提供的所有代碼片段都可以在 GitHub 上找到。