Java SE 8のOptionalはガード節と相性が悪いのが悩みどころですが、
何とかガード節と共存できないかなと考えて作ってみました。
package com.ikemo3;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
System.out.println(Main.sqrt("16"));
System.out.println(Main.sqrt("-16"));
System.out.println(Main.sqrt("str"));
}
public static String sqrt(String str) {
return Optionals.of(str, String.class)
.guard((s) -> toInteger(s), () -> "整数ではない")
.guard((i) -> sqrt(i), () -> "正の数ではない")
.get((d) -> String.valueOf(d));
}
/**
* 値が正なら整数にする
*/
public static Optional<Integer> toInteger(String str) {
try {
return Optional.of(Integer.valueOf(str));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
/**
* 値が正なら平方根を取る
*/
public static Optional<Double> sqrt(int i) {
if (i >= 0) {
return Optional.of(Math.sqrt(i));
} else {
return Optional.empty();
}
}
}
出力結果は以下のようになります。
4.0
正の数ではない
整数ではない
呼び出し方はこんな感じです。
だいたいガード節っぽく見えるかなと。
public static String sqrt(String str) {
return Optionals.of(str, String.class)
.guard((s) -> toInteger(s), () -> "整数ではない")
.guard((i) -> sqrt(i), () -> "正の数ではない")
.get((d) -> String.valueOf(d));
}
クラスの実装は次の通り。
package com.ikemo3;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
public class Optionals<IN, RET> {
private final IN value;
private final RET elseValue;
private final Class<RET> clazz;
public static <IN, OUT> Optionals<IN, OUT> of(IN value, Class<OUT> clazz) {
return new Optionals(value, clazz);
}
private Optionals(IN value, Class<RET> clazz) {
this.value = value;
this.clazz = clazz;
this.elseValue = null;
}
private Optionals(RET elseValue) {
this.value = null;
this.clazz = null;
this.elseValue = elseValue;
}
public <OUT> Optionals<OUT, RET> guard(Function<IN, Optional<OUT>> func, Supplier<RET> elseValue) {
if (this.elseValue != null) {
return new Optionals(this.elseValue);
}
Optional<OUT> result = func.apply(this.value);
if (result.isPresent()) {
return Optionals.of(result.get(), this.clazz);
} else {
return new Optionals(elseValue.get());
}
}
public RET get(Function<IN, RET> func) {
if (this.elseValue != null) {
return this.elseValue;
} else {
return func.apply(this.value);
}
}
}