web-dev-qa-db-ja.com

enumの文字列表現をより単純にするために、すべて大文字のネーミングに反対してもかまいませんか?

たとえば、enum定数にタイトルケースまたはすべて小文字のネーミングを使用する人を見たことがあります。次に例を示します。

_enum Color {
  red,
  yellow,
  green;
}
_

これにより、たとえばthrow new IllegalStateException("Light should not be " + color + ".")を実行する場合に、文字列形式の操作が簡単になります。

列挙型がprivateの場合、これはより受け入れやすいように見えますが、それでも私は好きではありません。次のように、Stringフィールドを使用してenumコンストラクタを作成し、toStringをオーバーライドしてその名前を返すことができることを知っています。

_enum Color {
  RED("red"),
  YELLOW("yellow"),
  GREEN("green");

  private final String name;

  private Color(String name) { 
    this.name = name 
  }

  @Override public String toString() {
    return name; 
  }
}
_

しかし、それがどれほど長いか見てください。シンプルにしたい小さな列挙型がたくさんある場合、それを続けるのは面倒です。ここでは、型破りなケースフォーマットを使用しても大丈夫ですか?

14
codebreaker

もちろん、簡単な答えは、基本的に定数であるものの命名規則を破るかどうかです... [〜#〜] jls [〜#〜] からの引用:

定数名

インターフェース型の定数の名前は、クラス型の最終的な変数は、通常、1つ以上の単語、頭字語、または略語のシーケンスであり、コンポーネントはアンダースコア「_」文字で区切られています。定数名は、わかりやすく、不必要に省略しないでください。通常、それらは適切な品詞である場合があります。

toString()の使用に関する長い答えは、enumのより多くの読み取り可能な表現が必要な場合に間違いなくオーバーライドする方法です。値。 Object.toString()からの引用(私の強調):

オブジェクトの文字列表現を返します。一般に、toStringメソッドはこのオブジェクトを「テキストで表す」文字列を返します。結果は簡潔ですが、有益な表現である必要があります人が読みやすい。すべてのサブクラスがこのメソッドをオーバーライドすることをお勧めします。

さて、なぜenumsString値で前後に変換することについて話をするのにいくつかの答えがドリフトしたのかはわかりませんが、ここでも私の見解を説明します。このようなenum値のシリアル化は、name()またはordinal()メソッドを使用することで簡単に処理できます。どちらもfinalなので、値の名前や位置が変わらない限り、戻り値を確認できます。私には、それは十分に明らかなマーカーです。

上記から私が収集するのは、今日、YELLOWを単に「黄色」と表現したいと思うかもしれません。明日、あなたはそれを "Pantone Minion Yellow" と表現したいと思うかもしれません。これらの説明はtoString()の呼び出しから返される必要があり、name()ordinal()のどちらも変更されることはないと思います。もしそうなら、それは私のコードベースまたは私のチーム内で解決する必要があるものであり、単なるenum命名スタイルよりも大きな問題になります

結論として、enum値のより多くの読み取り可能な表現をログに記録することだけが目的の場合でも、慣習に固執してオーバーライドすることをお勧めしますtoString()。それらをデータファイルまたは他のJava以外の宛先にシリアル化するつもりでも、name()およびordinal()メソッドでバックアップできるため、フレットオーバーする必要はありません。 toString()を上書きします。

14
h.j.k.

ENUMを変更しないでください。これはコードの悪臭です。 enumをenum、文字列を文字列とします。

代わりに、文字列値にはキャメルケースコンバーターを使用します。

throw new IllegalStateException("Light should not be " + CamelCase(color) + ".");

Javaのこの問題をすでに解決している多くのオープンソースライブラリがあります。

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/CaseFormat.html

5
Reactgular

My Javaコードとデータベースまたはクライアントアプリの間で列挙型を送信すると、列挙型の値を文字列として読み書きすることがよくあります。toString()は、文字列を連結するときに暗黙的に呼び出されます。一部の列挙型のtoString()は、時々私がちょうどできることを意味しました

_"<input type='checkbox' value='" + MY_CONST1 + "'>"
_

そして時々私は電話することを覚えなければなりませんでした

_"<input type='checkbox' value='" + MY_CONST1.name() + "'>"
_

エラーが発生したので、もうそれはしません。実際、私はEnumのanyメソッドをオーバーライドしません。十分なクライアントコードにこれらのメソッドを投入すると、最終的に誰かの期待に反するためです。

public String text()またはtoEnglish()などの独自の新しいメソッド名を作成します。

上記のような列挙型がたくさんある場合、タイピングを節約できる小さなヘルパー関数を次に示します。

_public static String ucFirstLowerRest(String s) {
    if ( (s == null) || (s.length() < 1) ) {
        return s;
    } else if (s.length() == 1) {
        return s.toUpperCase();
    } else {
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
}
_

.toUpperCase()または.toLowerCase()を呼び出すのは常に簡単ですが、大文字と小文字が混在する状態に戻すのは難しい場合があります。 「bleu de France」という色を考えてみましょう。フランスは常に大文字なので、それに遭遇した場合は、enumにtextLower()メソッドを追加することをお勧めします。このテキストを文の最初、文の途中、またはタイトルで使用すると、単一のtoString()メソッドでは不十分であることがわかります。そして、これは、Java=識別子で不正な文字、または標準のキーボードで表されないために入力するのが面倒な文字、または大文字小文字の区別のない文字(漢字など)。

_enum Color {
  BLEU_DE_FRANCE {
    @Override public String textTc() { return "Bleu De France"; }
    @Override public String textLc() { return "bleu de France"; }
  }
  CAFE_NOIR {
    @Override public String textTc() { return "Café Noir"; }
  }
  RED,
  YELLOW,
  GREEN;

  // The text in title case
  private final String textTc;

  private Color() { 
    textTc = ucFirstLowerRest(this.toString());
  }

  // Title case
  public String textTc() { return textTc; }

  // For the middle of a sentence
  public String textLc() { return textTc().toLowerCase(); }

  // For the start of a sentence
  public String textUcFirst() {
    String lc = textLc();
    return lc.substring(0, 1).toUpperCase() + lc.substring(1);
  }
}
_

これらを適切に使用することはそれほど難しくありません:

_IllegalStateException(color1.textUcFirst() + " clashes horribly with " +
                      color2.textLc() + "!")
_

うまくいけば、大文字と小文字が混在するenum値を使用すると失望する理由も示されます。アンダースコアの列挙型定数をすべて大文字にしておく最後の理由の1つは、それが最小驚きの原則に従うことです。人々はそれを期待しているので、何か違うことをすると、常に自分自身を説明したり、コードを悪用する人々に対処したりする必要があります。

3
GlenPeterson

間違いなく、大文字の命名規則に従うと [〜#〜] dry [〜#〜] に違反します。 (そして [〜#〜] yagni [〜#〜] )。たとえば、コード例#2では、「RED」と「red」が繰り返されています。

それで、あなたは公式大会に従うのですか、それともDRYに従うのですか?あなたの電話。

私のコードでは、DRYに従います。ただし、Enumクラスには「すべて大文字ではない(説明はこちら)」というコメントを付けます。

0
user949300

これらの文字列表現がデータベースやテキストファイルなどの場所に格納される可能性が少しでもある場合、列挙型をリファクタリングする必要がある場合、それらを実際の列挙型定数に関連付けることは非常に問題になります。

「白」を含むデータファイルがそこにあるときに、ある日Color.WhiteColor.TitaniumWhiteに名前変更することにした場合はどうなりますか?

また、列挙型定数を文字列に変換し始めたら、次のステップは、ユーザーが表示できる文字列を生成することです。ここでの問題は、ご存じのとおり、Javaでは、識別子内にスペースを使用できません。 (Color.Titanium Whiteを使用することは決してありません。)したがって、おそらくユーザーに表示する列挙名を生成するための適切なメカニズムが必要になるため、列挙が不必要に複雑になるのを避けるのが最善です。

そうは言っても、もちろん、先に進んで自分の考えていることを実行し、後で列挙型をリファクタリングして、問題が発生した場合(およびその場合)にコンストラクタに名前を渡すことができます。

nameフィールドpublic finalを宣言してゲッターを失うことにより、enum-with-constructorから数行を削ることができます。 (Javaプログラマーがゲッターに対して持っているこの愛は何ですか?)

0
Mike Nakis