読者です 読者をやめる 読者になる 読者になる

argius note

プログラミング関連

開発しています



Java8のStreamとDateTime APIで日付のストリームを作る

Java

今回は小ネタです。前回の続編と言えなくもないかもです。
Java8のStreamとDateTime APIを使って、Stream的に日付の順列を処理する方法です。



インターフェイス

fromDateからtoDateまでの日付の順列をStreamで返すようにします。
以降、Stream<LocalDate>のことを、ここでは「日付ストリーム」と呼びます。

// import java.time.*;
// import java.util.*;
// import java.util.function.*;
// import java.util.stream.*;

static Stream<LocalDate> dateStream(LocalDate fromDate, LocalDate toDate) {
    // TODO not impl yet
}

あとは、この日付ストリームを使って、forEachするなりflatMapするなりします。


実装1: 有限数列から日付ストリームを得る

有限の数列を作ってから、map操作によりそれぞれの数を日付に変換します。

  1. 日数を割り出す
  2. 日数分の数列を生成する (0, 1, 2, .... 30)
  3. 数列をfromDateに+n日したLocalDateに変換
// 日数
int days = fromDate.until(toDate).getDays() + 1;
// fromDateに加算する値の数列
IntStream numbers = IntStream.range(0, days);
// 数列→fromDateに日数を加算した日付ストリーム に変換
Stream<LocalDate> dateStream = numbers.mapToObj(x -> fromDate.plusDays(x));

return dateStream;

最後のコード部分3行は、通常は1行で書くところですが、意味をはっきりさせるために分割しています。


実装2: 無限の日付ストリーム+limit

fromDateから+1日を繰り返す無限の日付ストリームを生成し、日数で制限(limit)します。

  1. 日数を割り出す
  2. fromDateから+1日を繰り返す無限の日付ストリームを生成
  3. limitで日数と同じだけ取り出す(日数で打ち切る)
// 日数
int days = fromDate.until(toDate).getDays() + 1;
// +1日を繰り返す無限日付ストリームを生成
Stream<LocalDate> generator = Stream.iterate(fromDate, x -> x.plusDays(1));
// 日数で打ち切る
Stream<LocalDate> dateStream = generator.limit(days);

return dateStream;



(架空の)実装3: 無限の日付ストリーム+takeWhile

HaskellScalaなどのtakeWhileのように、Predicate<T>を取るメソッドがあれば、日数を取得する必要も無かったんですが...残念。

// コンパイルエラー: そんなメソッド(takeWhile)はありません!
return Stream.iterate(fromDate, x -> x.plusDays(1)).takeWhile(x -> !x.isAfter(toDate));
//

それっぽいことを実現するには、Spliterators.spliteratorUnknownSizeなどを使ってできないこともないですが。



おしまい。