Java中使用流Stream查詢列表中的最大和最小日期

banq發表於2024-07-09

在本文中,我們將探討如何使用Streams在這些物件列表中查詢最大和最小日期。

示例設定
Java 的原始Date API 仍然被廣泛使用,因此我們將展示一個使用它的示例。但是,自 Java 8 以來,引入了LocalDate ,並且大多數Date方法已被棄用。因此,我們還將展示一個使用LocalDate的示例。

首先,讓我們建立一個包含單獨Date屬性的基本Event物件:

public class Event {
    Date date;
    <font>// constructor, getter and setter<i>
}

要將天數新增到日期,我們將使用Apache Commons 的 DateUtils方法addDays()。為此,我們需要將最新版本的庫新增到我們的pom.xml中:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
</dependency>

現在我們可以定義三個事件的列表:第一個事件發生在今天,第二個事件發生在明天,第三個事件發生在一週內:

Date TODAY = new Date();
Event TODAYS_EVENT = new Event(TODAY);
Date TOMORROW = DateUtils.addDays(TODAY, 1);
Event TOMORROWS_EVENT = new Event(TOMORROW);
Date NEXT_WEEK = DateUtils.addDays(TODAY, 7);
Event NEXT_WEEK_EVENT = new Event(NEXT_WEEK);
List<Event> events = List.of(TODAYS_EVENT, TOMORROWS_EVENT, NEXT_WEEK_EVENT);

我們的目標是編寫一個方法,能夠確定NEXT_WEEK_EVENT是此Event列表中的最大日期。我們還將使用LocalDate而不是Date執行相同操作。我們的LocalEvent將如下所示:

public class LocalEvent {
    LocalDate date;
    <font>// constructor, getter and setter<i>
}

構建事件列表更加簡單,因為LocalDate已經有內建的plusDays()方法:

LocalDate TODAY_LOCAL = LocalDate.now();
LocalEvent TODAY_LOCAL_EVENT = new LocalEvent(TODAY_LOCAL);
LocalDate TOMORROW_LOCAL = TODAY_LOCAL.plusDays(1);
LocalEvent TOMORROW_LOCAL_EVENT = new LocalEvent(TOMORROW_LOCAL);
LocalDate NEXT_WEEK_LOCAL = TODAY_LOCAL.plusWeeks(1);
LocalEvent NEXT_WEEK_LOCAL_EVENT = new LocalEvent(NEXT_WEEK_LOCAL);
List<LocalEvent> localEvents = List.of(TODAY_LOCAL_EVENT, TOMORROW_LOCAL_EVENT, NEXT_WEEK_LOCAL_EVENT);

獲取最大日期
首先,我們將使用Stream API來流式傳輸我們的事件列表。然後,我們需要將Date getter 應用於Stream的每個元素。這樣,我們將獲得一個包含事件日期的Stream 。我們現在可以對其使用max()函式。這將返回Stream中與提供的Comparator相關的最大日期。

Date類實現了Comparable<Date>。因此,compareTo()方法定義了自然的日期順序。簡而言之,可以在max()中等效地呼叫以下兩個方法:

  1. Date的compareTo()可以透過方法引用來引用
  2. Comparator的naturalOrder()可以直接使用

最後,請注意,如果給定的事件列表為 null 或為空,我們可以直接返回 null。這將確保我們在流式傳輸列表時不會遇到問題。

該方法最終如下所示:

Date findMaxDateOf(List<Event> events) {
    if (events == null || events.isEmpty()) {
        return null;
    }
    return events.stream()
      .map(Event::getDate)
      .max(Date::compareTo)
      .get();
}

或者,使用naturalOrder(),它將讀取:

Date findMaxDateOf(List<Event> events) {
    if (events == null || events.isEmpty()) {
        return null;
    }
    return events.stream()
      .map(Event::getDate)
      .max(Comparator.naturalOrder())
      .get();
}

總而言之,我們現在可以快速測試我們的方法是否為我們的列表返回正確的結果:

assertEquals(NEXT_WEEK, findMaxDateOf(List.of(TODAYS_EVENT, TOMORROWS_EVENT, NEXT_WEEK_EVENT);

對於LocalDate,道理完全一樣。LocalDate確實實現了ChronoLocalDate 介面,該介面擴充套件了Comparable<ChronoLocalDate> 。 因此, LocalDate的自然順序由ChronoLocalDate的compareTo()方法定義。

因此,該方法可以寫成:

LocalDate findMaxDateOf(List<LocalEvent> events) {
    if (events == null || events.isEmpty()) {
        return null;
    }
    return events.stream()
      .map(LocalEvent::getDate)
      .max(LocalDate::compareTo)
      .get();
}

或者,以完全等效的方式:

LocalDate findMaxDateOf(List<LocalEvent> events) {
    if (events == null || events.isEmpty()) {
        return null;
    }
    return events.stream()
      .map(LocalEvent::getDate)
      .max(Comparator.naturalOrder())
      .get();
}

我們可以編寫以下測試來確認它有效:

assertEquals(NEXT_WEEK_LOCAL, findMaxDateOf(List.of(TODAY_LOCAL_EVENT, TOMORROW_LOCAL_EVENT, NEXT_WEEK_LOCAL_EVENT)));

獲取最小日期
類似地,我們可以在日期列表中找到最小日期:

Date findMinDateOf(List<Event> events) {
    if (events == null || events.isEmpty()) {
        return null;
    }
    return events.stream()
      .map(Event::getDate)
      .min(Date::compareTo)
      .get();
}

我們可以看到,唯一的變化是我們使用了min()函式而不是max()。讓我們驗證一下它是否給出了三個日期中最早的日期:

@Test
void givenEventList_whenFindMinDateOf_thenReturnMinDate() {
    assertEquals(TODAY, DateHelper.findMinDateOf(List.of(TODAYS_EVENT, TOMORROWS_EVENT, NEXT_WEEK_EVENT)));
}

如果我們使用LocalDate,我們將使用此方法:

LocalDate findMaxDateOfLocalEvents(List<LocalEvent> events) {
    if (events == null || events.isEmpty()) {
        return null;
    }
    return events.stream()
      .map(LocalEvent::getDate)
      .max(LocalDate::compareTo)
      .get();
}

再次,我們所做的唯一更改是用對min()方法的呼叫替換對max()的呼叫。最後,我們也可以測試它:

@Test
void givenEventList_whenFindMinDateOfWithComparator_thenReturnMaxDate() {
    assertEquals(TODAY, DateHelper.findMinDateOfWithComparator(List.of(TODAYS_EVENT, TOMORROWS_EVENT, NEXT_WEEK_EVENT)));
}

結論
在本教程中,我們瞭解瞭如何獲取物件列表中的最大或最小日期。我們使用了Date和LocalDate物件。
 

相關文章