LoginSignup
0
2

More than 3 years have passed since last update.

JavaでIf式をしてみる

Posted at

まえがき

本稿は、こちらの記事に影響を受けて衝動的に作られました。
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());
  }
}
0
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2