Edited at

TemporalQueryで関数合成したかった

More than 3 years have passed since last update.

TemporalQueryは、TemporalAccessor(Java8で追加されたDate and Time APIで時刻・時間を表すベースクラス)をLocalDateTimeとかYearとかに変換する関数を表すクラスで、以下のように定義されている。

@FunctionalInterface

public interface TemporalQuery<R> {
R queryFrom(TemporalAccessor temporal);
}

たとえばDateTimeFormatterではTemporalQueryを以下のように利用する。

    String pattern = "yyyy-MM-dd HH:mm:ss.SSS z";

DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern(pattern);
TemporalQuery<LocalDateTime> tq = LocalDateTime::From;
DateTime dt = dtFormatter.parse(dateString,tq);

ここでTemporalAccessorをDateに変換しようとするとき、TemporalAccessorからDateに直接変換するTemporalQueryが標準では用意されていないので、TemporalAccessor -> Instant -> Dateと変換していくTemporalQueryを用意する必要がある。

これはただの"TemporalAccessor -> Instant"と"Instant -> Date"の合成関数だが、Function型とTemporalQuery型は関係がないので

Function#andThen()で合成関数を作ってもTemporalQuery型にならない。

"TemporalAccessor -> Date"のTemporalQueryを使うには、自分で"TemporalAccessor -> Date"のメソッドを定義してやる必要がありそう。

import java.time.Instant;

import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DateTimeFormatterTest{
private final static String pattern = "yyyy-MM-dd HH:mm:ss.SSS z";
private final static DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern(pattern);

public static Date stringToDate(String dateString) {
//これはダメ
//return dtFormatter.parse(dateString,((Function<TemporalAccessor,Instant>)Instant::from).andThen(Date::from))

//これはOK
return dtFormatter.parse(dateString,DateTimeFormatterTest::taToDate);
}
private static Date taToDate(TemporalAccessor ta){
Function<TemporalAccessor,Date> fun = ((Function<TemporalAccessor,Instant>)Instant::from).andThen(Date::from);
return fun.apply(ta);
}

public static void main(String[] args){
List<Date> ds = IntStream.range(00,59).parallel()
.mapToObj(sec -> stringToDate("2015-12-16 14:"+String.format("%02d",sec)+":00.655 JST"))
.collect(Collectors.toList());
System.out.println(ds);// -> [Wed Dec 16 14:00:00 JST 2015, Wed Dec 16 14:01:00 JST 2015, Wed Dec 16 14:02:00 JST 2015, ..
}
}

gist

もうちょっとうまい方法ないかな…