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

Stream で LocalDateリストを生成

最終目的は、jQuery ui の datepicker 等を使用しないで、Javaからカレンダーを作成してスケジュールを
描画編集すること。DBに用意するデータと連携するために jQuery だけじゃ苦しいので Java でベースになる
日付のリストを先ず生成する。
簡単なものから、、、

現在日→当月のLocalDateリスト (現在日の個所は任意の日付にすればこのパターンが使える)

final LocalDate firstDate = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
List<LocalDate> list = Stream.iterate(firstDate, e->e.plusDays(1))
  .limit(firstDate.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth())
  .collect(Collectors.toList());

1日~末日だけのリストはこれで充分だが、カレンダー表示;曜日に沿って並べるのはこれでは苦しい。
CSSの nth-child と float属性で、並べていくとして、

li{
   float: left;
}
li:nth-child(7n+1){
   clear: both;
}

これで並べるにしても、月の初日が曜日の適切な位置で始まるようにリストを作成する必要がある。
→ 今回は、null を先頭に適切な数だけ入れることにする。

上の Stream の collect 終端処理で、Collectors.toList() でなくて
 collect(Supplier supplier,
BiConsumer accumulator,
BiConsumer combiner)
リスト生成するようにする。
段階として、上の処理を、一旦、Collectors.toList() を書き換えて確認しておく。

final LocalDate firstDate = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
List<LocalDate> list = Stream.iterate(firstDate, e->e.plusDays(1))
   .limit(firstDate.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth())
   .collect(ArrayList::new, (r, t)->r.add(t), (r, u)->r.addAll(u));

ここから、collect の Supplier 部分を必要な部分を適切に、null が格納されたリストを提供するようにする。
月の初日の曜日の列挙型の int値 を 7で割った余りの数だけ null を格納するリストを生成して
Supplierが返すリストにする。

final LocalDate firstDate = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
List<LocalDate> list = Stream.iterate(firstDate, e->e.plusDays(1))
  .limit(firstDate.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth())
  .collect(()->IntStream.range(0, firstDate.getDayOfWeek().getValue() % 7)
           .collect(ArrayList::new, (r, t)->r.add(null), (r, u)->r.addAll(u))
     , (r, t)->r.add(t), (r, u)->r.addAll(u)
);

これで完成。他人がパッと見て読み解くのたいへんそう。でも使い回しができそう。
li タグを書き並べる処理が書けるし、タグ内も LocalDateをキーにしてDBに用意した情報を
割りあてができる。もちろん1日ずつの走査の中でDBに毎回アクセスするような
馬鹿な事はしないで、予め Map に1ヶ月分を読み込んで格納しておくことが前提である