確定給定年份範圍內從星期日開始的所有年份
1. 概述
確定以星期日開始的所有年份似乎是一個簡單的要求。然而,它在各種現實場景或業務用例中可能非常相關。特定的日期和日曆結構通常會影響操作、事件或時間表。例如,這樣的要求可能出現在假期或宗教活動安排、或薪資和工作時間表規劃中。
在本教程中,我們將介紹三種方法來尋找給定範圍內從星期日開始的所有年份。我們將首先查看使用Date
和Calendar
解決方案,然後了解如何使用現代java.time
API。最後,我們將包含一個使用Spliterator<LocalDate>
的最佳化範例。
2. 遺留解決方案
首先,我們將使用舊的Calendar
類別來檢查給定範圍內每年的 1 月 1 日是否是星期日:
public class FindSundayStartYearsLegacy {
public static List<Integer> getYearsStartingOnSunday(int startYear, int endYear) {
List<Integer> years = new ArrayList<>();
for (int year = startYear; year <= endYear; year++) {
Calendar calendar = new GregorianCalendar(year, Calendar.JANUARY, 1);
if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
years.add(year);
}
}
return years;
}
}
首先,我們為每年建立一個Calendar
對象,並將日期設定為 1 月 1 日。然後我們使用calendar.get(Calendar.DAY_OF_WEEK)
方法來檢查這一天是否是星期日。我們將2023
2006
到2012
的年份範圍來測試FindSundayStartYearsLegacy
2017
。
@Test
public void givenYearRange_whenCheckingStartDayLegacy_thenReturnYearsStartingOnSunday() {
List<Integer> expected = List.of(2006, 2012, 2017, 2023);
List<Integer> result = FindSundayStartYearsLegacy.getYearsStartingOnSunday(2000, 2025);
assertEquals(expected, result);
}
3.新的API解決方案
讓我們使用 Java 8 中引入的java.time
套件來解決相同的問題。我們將使用LocalDate
檢查每年 1 月 1 日是否從星期日開始:
public class FindSundayStartYearsTimeApi {
public static List<Integer> getYearsStartingOnSunday(int startYear, int endYear) {
List<Integer> years = new ArrayList<>();
for (int year = startYear; year <= endYear; year++) {
LocalDate firstDayOfYear = LocalDate.of(year, 1, 1);
if (firstDayOfYear.getDayOfWeek() == DayOfWeek.SUNDAY) {
years.add(year);
}
}
return years;
}
}
我們在這裡使用LocalDate.of(year, 1, 1)
來表示每年的 1 月 1 日。然後,我們使用getDayOfWeek()
方法來檢查這一天是否是星期日。接下來,我們使用FindSundayStartYearsTimeApi
類別中的java.time
API 驗證解決方案,輸入和預期結果與先前的測試相同:
@Test
public void givenYearRange_whenCheckingStartDayTimeApi_thenReturnYearsStartingOnSunday() {
List<Integer> expected = List.of(2006, 2012, 2017, 2023);
List<Integer> result = FindSundayStartYearsTimeApi.getYearsStartingOnSunday(2000, 2025);
assertEquals(expected, result);
}
4. 使用串流的增強功能
讓我們看看如何使用Spliterator<LocalDate>
迭代年份並過濾掉以 Sunday 開始的年份。 Spliterator
對於高效能遍歷大數據範圍非常有用:
public class FindSundayStartYearsSpliterator {
public static List<Integer> getYearsStartingOnSunday(int startYear, int endYear) {
List<Integer> years = new ArrayList<>();
Spliterator<LocalDate> spliterator = Spliterators.spliteratorUnknownSize(
Stream.iterate(LocalDate.of(startYear, 1, 1), date -> date.plus(1, ChronoUnit.YEARS))
.limit(endYear - startYear + 1)
.iterator(), Spliterator.ORDERED);
Stream<LocalDate> stream = StreamSupport.stream(spliterator, false);
stream.filter(date -> date.getDayOfWeek() == DayOfWeek.SUNDAY)
.forEach(date -> years.add(date.getYear()));
return years;
}
}
在這裡,我們使用Stream.iterator()
來建立一個Spliterator<LocalDate>
來迭代給定範圍內每年的第一天。接下來, StreamSupport.stream()
方法將Spliterator
轉換為Stream<LocalDate>
。此外,我們使用filter()
來檢查每年的第一天是否是星期日。最後,我們用有效的條目填充數組,並在最後返回該條目。現在我們將在FindSundayStartYearsSpliterator
類別中測試基於Streams
的實作:
@Test
public void givenYearRange_whenCheckingStartDaySpliterator_thenReturnYearsStartingOnSunday() {
List<Integer> expected = List.of(2006, 2012, 2017, 2023);
List<Integer> result = FindSundayStartYearsSpliterator.getYearsStartingOnSunday(2000, 2025);
assertEquals(expected, result);
}
5. 結論
在本文中,我們研究了三個選項來尋找給定範圍內從星期日開始的年份。儘管Date
和Calendar
可用,但它們也存在諸如可變性、笨重的 API 和不建議使用的方法等問題。這種遺留解決方案很簡單,但不是新開發的最佳實踐。一般來說, java.time
套件提供了一個更清晰、更健壯的 API 來處理日期和時間。它是類型安全的、不可變的,並且比Date
和Calendar
更容易使用。因此,將Spliterator
與Stream
結合使用是一種處理大數據範圍的實用且高效的方法,允許並行化和惰性求值。 java.time
方法是在 Java 中處理日期和時間的建議方法。 Spliterator
解決方案增加了靈活性和效能優勢。本文的完整原始碼可以在 GitHub 上找到。