Predicate 結果で Function 実行する

任意の検査をして Function<T, R> を実行する。
これは、stream か、Optional filter 実行後に map あるいは flatMap を実行と
ラムダ式を連結して記述すれば済むことではある。

例)日付文字列→LocalDate

String str;
// TODO 日付文字列をstr に格納
LocalDate dt = Optional.ofNullable(str)
   .filter(e->Pattern.compile("^\\d{4}/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01])$")
         .matcher(e).matches())
   .map(e->LocalDate.parse(e, DateTimeFormatter.ofPattern("yyyy/MM/dd")))
   .orElse(LocalDate.of(2021, 4, 1));

Predicate 結果、成功なら処理をする Function<T, R> としてまとめたらどうであろう。

import java.io.Serializable;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
 * PredicateFunction
 */
@FunctionalInterface
public interface PredicateFunction<T, R> extends Serializable{
   R apply(T t);

   static <T, R> Function<T, R> of(Predicate<T> p, PredicateFunction<T, R> f){
      return t-> p.test(t) ? f.apply(t) : null;
   }
   static <T, R> Function<T, R> of(Predicate<T> p, PredicateFunction<T, R> f, R r){
      return t-> p.test(t) ? f.apply(t) : r;
   }
   static <T, R> Function<T, R> of(Predicate<T> p, PredicateFunction<T, R> f, Supplier<R> s){
      return t-> p.test(t) ? f.apply(t) : s.get();
   }
}

Optional の実行で、filter を書かずに当てはめてみる。

Function<String, LocalDate> predicFunction = PredicateFunction.of(
   t->Pattern.compile("^\\d{4}/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01])$")
      .matcher(t.toString()).matches()
   , e->LocalDate.parse(e.toString(), DateTimeFormatter.ofPattern("yyyy/MM/dd"))
);
LocalDate date = Optional.ofNullable(str).map(predicFunction)
.orElse(LocalDate.of(2021, 4, 1));

今回の例は、Pattern の matcher メソッドが、CharSequenceを引数であるため、
Optional による null チェックが入り、Object の toString() を実行しているのでこのようになっている、

だから、Optional でなく、PredicateFunction の apply メソッド実行で書けば、、、

LocalDate date = PredicateFunction.of(
   t->Pattern.compile("^\\d{4}/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01])$")
      .matcher(t==null ? "" :t.toString()).matches()
   , e->LocalDate.parse(e.toString(), DateTimeFormatter.ofPattern("yyyy/MM/dd"))
   , LocalDate.of(2021, 4, 1)
).apply(str);

PredicateFunction.of による Function<T, R> を予め生成しておく方法としては
少しばかり有効な手段かもしれない。