Java

Javaで三項演算子はどこまで許されるか

はじめに

この記事ではJavaに限った話をします。

先日、以下の記事を書きました(タイトル変更してます)。

この記事で、以下のように三項演算子を良い例として挙げました。

String userType = isAdmin ? "管理者" : "一般";

しかし、三項演算子は読みにくいという反応が結構ありました。あくまでシンプルな例として挙げたつもりだったのですが、説明不足だったので、別途記事を書きます。

三項演算子を使っていいのは、単純なもののみに限られるのが自分の中での結論です。

三項演算子とは

三項演算子(ternary operator)は以下のような形をしています。

<条件式> ? <trueのときの値> : <falseのときの値>

どの書き方ならよいかの話をする前に、自分が「どこまでならよい」と感じているのか、その例を書きます。

/*
 * 白(ほぼ問題なし)
 */
String userType = isAdmin ? "管理者" : "一般";

String userType = user.isAdmin() ? "管理者" : "一般";

UserType userType = user.isAdmin() ? UserType.ADMIN : UserType.NORMAL;

String userName = user.isAdmin() ? "管理者" : user.getName();

/*
 * 白に近いグレー
 */
return user.getType() == UserType.GUEST ? "ゲストユーザ" : user.getName();

/*
 * 黒に近いグレー
 */
String userName = user.getType() == UserType.GUEST ? "ゲストユーザ" : user.getName();

/*
 * 黒(アウト)
 */
String userName = user.getType() == UserType.GUEST ? "ゲスト" : user.getType() == UserType.ADMIN ? "管理者" : user.getName() + "さん";

何が基準か

三項演算子の定義に戻ります。

<条件式> ? <trueのときの値> : <falseのときの値>

先程の例で、どのようなパターンが良いのか、悪いのかは、以下のように分類できます。

  • 白(ほぼ問題なし)
    • 条件式
      • boolean変数
      • booleanを返すメソッド
    • true/falseのときの値
      • 定数
      • enum
      • getterなど単純な呼び出し
  • グレー
    • 条件式に ==!= での比較が入る
  • 黒(アウト)
    • ネストしている
    • true/falseのときの値が、単純な呼び出し以外

三項演算子が嫌われがちなのは、どこまでが条件式なのか、どこまでがtrueのときの値なのか、頭の中で字句解析、文法解析するコストが高いからです。また、 ==!= での比較が入るとよくないのは、代入の = と見間違えて、一瞬混乱するからです。

なので、単純な書き方以外は避けるようにしています。

どのように書くべきか

以下のように書くこともできますが、後ろ向きな解決案なので、自分は好きではありません。

String userName; // ここでの初期化は無駄なのでしない

if (user.getType() == UserType.GUEST) {
    userName = "ゲスト";
} else if (user.userType() == UserType.ADMIN) {
    userName = "管理者";
} else {
    userName = user.getName() + "さん";
}

自分なら以下のように、メソッドを作ります。この場合はUserクラスのメソッドとして実装できますが。

なお、今回は元の条件式と合わせるためにif文にしましたが、enumの場合はswitch文を使うことが多いです。

private String getName(User user) {
    if (user.getType() = UserType.GUEST) {
        return "ゲスト";
    } else if (user.getType() == UserType.ADMIN) {
        return "管理者";
    } else {
        return user.getName() + "さん";
    }
}

// 呼び出し元
String userName = getName(user);

おわりに

自分が思っていたより、読みにくくなるパターンのほうが多かったです。三項演算子を禁止するのはやりすぎだと思いますが、単純なもの以外は使わないくらいでいいと思います。