まえがき
本稿は、こちらの記事に影響を受けて衝動的に作られました。
4歳娘「パパ、constしか使わないで?」
本文
みなさん、Javaは好きですか。
私は最近まであまり好きではありませんでしたが、最近は結構好きです。
なんだかんだライブラリも豊富ですし、モダンな構文やsyntax sugarも増えてきました。
ただ、If式が無いのはいただけないので、それっぽいものを作ってみました。
完成品
public class Iff<T, R> {
Map<Predicate<T>, Supplier<R>> evaluations = new LinkedHashMap<>();
private Supplier<R> elsef;
public Iff(Predicate<T> condition, Supplier<R> then) {
evaluations.put(condition, then);
}
public Iff<T, R> elseIf(Predicate<T> condition, Supplier<R> then) {
evaluations.put(condition, then);
return this;
}
public Iff<T, R> elsef(Supplier<R> elsef) {
this.elsef = elsef;
return this;
}
public Optional<R> eval(T target) {
for (Map.Entry<Predicate<T>, Supplier<R>> entry : this.evaluations.entrySet()) {
if (entry.getKey().test(target)) {
var value = entry.getValue().get();
return Objects.isNull(value) ? Optional.empty() : Optional.of(value);
}
}
if (this.elsef == null) {
return Optional.empty();
} else {
var result = this.elsef.get();
if (Objects.isNull(result)) {
return Optional.empty();
}
return Optional.of(result);
}
}
}
Tのパラメータを引数にとりチェックし、Optional<R>
な値を返すクラスです(本当にこれはif式・・・?)
使い方
雑にテストとしてサンプルを書いてみました。
class IffTest {
@Test
public void testIf() {
// 文字列を評価してIntegerを返す
var result = new Iff<String, Integer>((str) -> str.startsWith("hoge"), () -> 100).eval("hogeFuga");
Assertions.assertEquals(result.get(), 100);
}
@Test
public void testIfElseFirstMatch() {
// elseIfメソッドで、elseIfを何度でも足せます。
var result = new Iff<String, Integer>((str) -> str.startsWith("hoge"), () -> 100)
.elseIf((str) -> str.startsWith("hogeFuga"), () -> 200)
.elseIf((str) -> str.startsWith("hoho"), () -> 300)
.eval("hogeFuga");
Assertions.assertEquals(result.get(), 100);
}
@Test
public void noMatch() {
var result = new Iff<String, Integer>((str) -> str.startsWith("hoge"), () -> 100)
.elseIf((str) -> str.startsWith("hogeFuga"), () -> 200)
.elseIf((str) -> str.startsWith("hoho"), () -> 300)
// elsefメソッドで、elseの場合の挙動をセットできます
.elsef(() -> 400)
.eval(UUID.randomUUID().toString());
Assertions.assertEquals(result.get(), 400);
}
@Test
public void noMatchNotExistsElse() {
var result = new Iff<String, Integer>((str) -> str.startsWith("hoge"), () -> 100)
.elseIf((str) -> str.startsWith("hogeFuga"), () -> 200)
.elseIf((str) -> str.startsWith("hoho"), () -> 300)
.eval(UUID.randomUUID().toString());
// どの式にもマッチしない場合、Emptyが返却されます
result.ifPresentOrElse(v -> {
Assertions.fail();
}, () -> {
// elseだったら正解
});
}
@Test
public void elseResultIsNull() {
var result = new Iff<String, Integer>((str) -> str.startsWith("hoge"), () -> 100)
.elseIf((str) -> str.startsWith("hogeFuga"), () -> 200)
.elseIf((str) -> str.startsWith("hoho"), () -> 300)
.elsef(() -> null)
.eval(UUID.randomUUID().toString());
Assertions.assertTrue(result.isEmpty());
}
@Test
public void elseIfResultIsNull() {
var result = new Iff<String, Integer>((str) -> str.startsWith("hoge"), () -> 100)
.elseIf((str) -> str.startsWith("mogemoge"), () -> null)
.elseIf((str) -> str.startsWith("hoho"), () -> 300)
.elsef(() -> null)
.eval("mogemoge");
Assertions.assertTrue(result.isEmpty());
}
}