きり丸の技術日記

技術検証したり、資格等をここに残していきます。

Javaでメソッド参照を使ったまま、ラムダ式で条件否定をする(Predicate.not)

私はラムダ式での可読性を上げるため、メソッド参照を使用することが多いです。ただ、メソッド参照を使用したまま条件否定する方法を知らなかったため、無名関数を使用して条件を否定していました。または、内部で条件否定をしたメソッドを別に用意していることもありました。

今回、メソッド参照を使用したまま条件否定する方法を知ったので、それを残します。

環境

  • Java
    • 17

対応

Predicate.notを使用する。

次のコードは、日本円の商品以外の合計を取得するコードです。

public record Currency(String unit, int value) {
  public boolean isJpy() {
    return "JPY".equals(unit);
  }
}

public record Item(List<Currency> currencyList) {
  public int sumNotOnlyJpy() {
    return currencyList.stream()
        // 日本円「以外」、という条件になる
        .filter(Predicate.not(Currency::isJpy))
        .mapToInt(Currency::value)
        .sum();
  }
}

今までに行っていた対応

無名関数

分かりやすいが、どうしても否定の「!」を見逃すことはある。

public int sumNotOnlyJpy() {
  return currencyList.stream()
    .filter(e -> !e.isJpy())
    .mapToInt(Currency::value)
    .sum();
}

否定メソッドを用意する

否定条件の使用率が高い場合は、こちらを使用することもあります。ただ、無駄にメソッド数が増えてしまうので、最初から考慮する必要はありません。

public record Currency(String unit, int value) {
  public boolean isJpy() {
    return "JPY".equals(unit);
  }
  public boolean isNotJpy() {
    return !isJpy();
  }
}
public record Item(List<Currency> currencyList) {
  public int sumNotOnlyJpy() {
    return currencyList.stream()
      .filter(Currency::isNotJpy)
      .mapToInt(Currency::value)
      .sum();
  }
}

備考

そもそもメソッド参照の方が可読性が上がる理由としては無駄な変数が出てこないため、余計な処理をしていないことが約束されているからです。

無駄な変数が必ずしも悪いわけではないのですが、私だと無名関数で処理する意図を読もうとしてしまうので、一瞬身構えてしまいます。慣れるまではメソッド参照は難しいですが、IntelliJ IDEAでは変換を提案してくれるので、ガンガンIDEの力を使っていきましょう。

public int sumNotOnlyJpy() {
  return currencyList.stream()
      .filter(e -> e.isJpy()))
      .mapToInt(Currency::value)
      .sum();
}

ソースコード

終わりに

1行で終わるような記事ではあるのですが、こういう地味な書き方は知る機会がなくて難しいですね。