列挙型とは何で、なぜ有用なのですか?


488

今日、私はこのサイトでいくつかの質問を閲覧していましたが、そのようなソリューションに対するスレッドセーフティの利点についてenum シングルトンパターンで使用されいることに言及しました。

私はenumsを使用したことがなく、数年以上Javaでプログラミングしています。そしてどうやら彼らは大きく変わった。現在、彼らは彼ら自身の中でOOPの完全なサポートさえしています。

さて、なぜそして何のために日々のプログラミングで列挙型を使用すべきですか?




enumはプライベートコンストラクターがあるためインスタンス化できません。それらはjvmの起動時にインスタンス化されるため、シングルトンのEnumはスレッドセーフではありません。
Arnav Joshi 2016

回答:


633

変数(特にメソッドパラメーター)が可能な値の小さなセットから1つしか取得できない場合は、常に列挙型を使用する必要があります。例としては、型定数(契約ステータス:「永続的」、「temp」、「見習い」)やフラグ(「今すぐ実行」、「実行を延期」)などがあります。

整数(または文字列コード)の代わりに列挙型を使用する場合は、コンパイル時のチェックを増やし、無効な定数でエラーが渡されるのを回避し、どの値が使用可能かを文書化します。

ところで、列挙型の多用は、メソッドが過度に機能することを意味する場合があります(多くの場合、複数のフラグを取り、機能を変更する1つのメソッドを使用するよりも、複数の個別のメソッドを使用する方が適切です)。ただし、フラグまたは型コードを使用する必要がある場合は、列挙型行く方法です。

例として、どちらが良いですか?

/** Counts number of foobangs.
 * @param type Type of foobangs to count. Can be 1=green foobangs,
 * 2=wrinkled foobangs, 3=sweet foobangs, 0=all types.
 * @return number of foobangs of type
 */
public int countFoobangs(int type)

/** Types of foobangs. */
public enum FB_TYPE {
 GREEN, WRINKLED, SWEET, 
 /** special type for all types combined */
 ALL;
}

/** Counts number of foobangs.
 * @param type Type of foobangs to count
 * @return number of foobangs of type
 */
public int countFoobangs(FB_TYPE type)

次のようなメソッド呼び出し:

int sweetFoobangCount = countFoobangs(3);

それから:

int sweetFoobangCount = countFoobangs(FB_TYPE.SWEET);

2番目の例では、どのタイプが許可されているかがすぐにわかり、ドキュメントと実装が同期しなくなることはなく、コンパイラーはこれを強制できます。また、次のような無効な呼び出し

int sweetFoobangCount = countFoobangs(99);

もはや不可能です。


41
enumを使用し、値の組み合わせを許可する場合は、EnumSetを使用します。これには、public static final EnumSet <FB_TYPE> ALL = EnumSet.allOf(FB_TYPE.class);のような、あらゆる種類のきちんとしたヘルパーが付属しています。
RobAu 2013

20
これらの答えは、誰かが実際に努力したのでSOで本当に見たいものです。
2013年

1
それは本当だとは思いませんyou should *always* use enums when a variable can only take one out of a small set of possible values。「バイナリフラグ」として(論理orING を使用して)定数値を使用すると、メモリが不足しているリアルタイムアプリケーションに役立ちます。
Elist 2014

列挙型を使用した@Elistはコードの可読性を向上させます。ある時点で定数を使用すると、後継者はそれが使用される理由を知らない...:)
theRoot

136

なぜプログラミング言語機能を使用するのですか?私たちに言語がある理由は

  1. プログラマが効率的かつ正確にアルゴリズムをコンピュータが使用できる形式で表現する。
  2. メンテナーは、他の人が書いたアルゴリズムを理解し、正しく変更行います。

列挙型は、多くのボイラープレートを作成することなく、正確さと読みやすさの両方の可能性を向上させます。ボイラープレートを作成したい場合は、列挙型を「シミュレート」できます。

public class Color {
    private Color() {} // Prevent others from making colors.
    public static final Color RED = new Color();
    public static final Color AMBER = new Color();
    public static final Color GREEN = new Color();
}

今、あなたは書くことができます:

Color trafficLightColor = Color.RED;

上記のボイラープレートは、

public enum Color { RED, AMBER, GREEN };

どちらも、コンパイラから同じレベルのチェックヘルプを提供します。ボイラープレートは単なるタイピングです。しかし、多くのタイピングを節約することで、プログラマーはより効率的になり(1を参照)、価値のある機能です。

また、少なくとももう1つの理由から価値があります。

スイッチステートメント

static final上記の列挙型シミュレーションで得られない 1つのことは、素晴らしいswitchケースです。列挙型の場合、Javaスイッチはその変数の型を使用して列挙型のケースのスコープを推測するため、enum Color上記の場合は次のように言うだけで済みます。

Color color = ... ;
switch (color) {
    case RED:
        ...
        break;
}

Color.REDケースではないことに注意してください。enumを使用しない場合、名前付き数量を使用する唯一の方法switchは次のようなものです。

public Class Color {
    public static final int RED = 0;
    public static final int AMBER = 1;
    public static final int GREEN = 2;
}

ただし、色を保持する変数にはtypeが必要intです。列挙型とstatic finalシミュレーションの素晴らしいコンパイラチェックはなくなりました。満足していない。

妥協案は、シミュレーションでスカラー値のメンバーを使用することです。

public class Color {
    public static final int RED_TAG = 1;
    public static final int AMBER_TAG = 2;
    public static final int GREEN_TAG = 3;

    public final int tag;

    private Color(int tag) { this.tag = tag; } 
    public static final Color RED = new Color(RED_TAG);
    public static final Color AMBER = new Color(AMBER_TAG);
    public static final Color GREEN = new Color(GREEN_TAG);
}

今:

Color color = ... ;
switch (color.tag) {
    case Color.RED_TAG:
        ...
        break;
}

しかし、さらに定型文に注意してください!

列挙型をシングルトンとして使用する

上記のボイラープレートから、列挙型がシングルトンを実装する方法を提供する理由がわかります。書く代わりに:

public class SingletonClass {
    public static final void INSTANCE = new SingletonClass();
    private SingletonClass() {}

    // all the methods and instance data for the class here
}

そして、それにアクセスする

SingletonClass.INSTANCE

私たちはただ言うことができます

public enum SingletonClass {
    INSTANCE;

    // all the methods and instance data for the class here
}

同じことを私たちに与えます。Java enum 完全なクラスとして実装されているので、これを回避することができます。これも定型的ではありませんが、慣用句に慣れていない限り、自明ではありません。私はまた、あなたが、彼らはシングルトンのためにあまり意味がありませんが、様々な列挙機能を得るという事実を嫌い:ordvalues、他(トリッキーシミュレーション実際にありますColor extends Integerそれはスイッチで動作しますが、それはつまり、それはなおさら難しいですはなぜenumより良いアイデアであるかを明確に示しています。)

スレッドセーフ

スレッドセーフティは、シングルトンがロックなしでレイジーに作成された場合にのみ潜在的な問題になります。

public class SingletonClass {
    private static SingletonClass INSTANCE;
    private SingletonClass() {}
    public SingletonClass getInstance() {
        if (INSTANCE == null) INSTANCE = new SingletonClass();
        return INSTANCE;
    }

    // all the methods and instance data for the class here
}

がnullであるgetInstance間に多くのスレッドが同時に呼び出す場合INSTANCE、インスタンスはいくつでも作成できます。これは悪いです。唯一の解決策はsynchronized、変数を保護するアクセスを追加することですINSTANCE

ただし、static final上記のコードにはこの問題はありません。クラスのロード時に熱心にインスタンスを作成します。クラスの読み込みは同期されます。

enumそれは最初に使用するまで初期化されていないため、シングルトンが効果的に怠け者です。Javaの初期化も同期されるため、複数のスレッドがの複数のインスタンスを初期化することはできませんINSTANCE。非常に少ないコードで遅延初期化されたシングルトンを取得しています。唯一の欠点は、かなりあいまいな構文です。何が起こっているのかを知るには、イディオムを理解するか、クラスのロードと初期化がどのように機能するかを完全に理解する必要があります。


15
最後の段落は、私にとってシングルトンの状況を本当に明確にしました。ありがとう!スキミングしている読者はそれをもう一度読んでください。
バジルブルク2014

私はこれを読んでいました、stackoverflow.com / questions / 16771373 / … 。今、私はあなたの最後のパラと混同しています。列挙型はどのようにレイ初期化機能を提供しませんか?
Deepankar Singh

static finalフィールドは、ロード時ではなく、クラス初期化時に初期化されます。これは、enum定数初期化の場合とまったく同じです(実際、内部的には同じです)。そのため、最初のJavaバージョンでも、シングルトンに「巧妙な」遅延初期化コードを実装しようとしても無意味でした。
Holger

42

すでに述べたユースケースの他に、いくつかの基本的なOOPガイドラインに従って、戦略パターンを実装するために列挙型が役立つことがよくあります。

  1. データが存在する場所にコードがあること(つまり、列挙型自体内、または多くの場合、メソッドをオーバーライドする可能性がある列挙型定数内)。
  2. クライアントコードを列挙型にバインドしないようにするためのインターフェイス(またはそれ以上)の実装(デフォルトの実装のセットのみを提供する必要があります)。

最も単純な例は、一連のComparator実装です。

enum StringComparator implements Comparator<String> {
    NATURAL {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    },
    REVERSE {
        @Override
        public int compare(String s1, String s2) {
            return NATURAL.compare(s2, s1);
        }
    },
    LENGTH {
        @Override
        public int compare(String s1, String s2) {
            return new Integer(s1.length()).compareTo(s2.length());
        }
    };
}

この「パターン」は、列挙型に付属するすべての便利な機能を広範囲に使用して、はるかに複雑なシナリオで使用できます。インスタンスの反復、暗黙的な順序による、名前によるインスタンスの取得、適切なインスタンスを提供する静的メソッド特定のコンテキストなどの場合。これはすべてインターフェイスの背後に隠されているため、「デフォルトのオプション」で使用できないものが必要な場合に、コードを変更せずにカスタム実装で使用できます。

これは、すべてのロジックが列挙型にカプセル化された時間粒度(毎日、毎週など)の概念のモデリングにこれがうまく適用されていることを確認しました(特定の時間範囲に適切な粒度を選択し、特定の動作を一定として各粒度にバインドしました)メソッドなど)。それでも、Granularityサービス層から見たは単なるインターフェースでした。


2
追加することもできCASE_INSENSITIVE { @Override public int compare(String s1, String s2) { return s1.compareToIgnoreCase(s2); }ます。まだ言及されていない利点の1つは、堅牢なシリアル化サポートを利用できることです。永続フォームには、クラス名と定数名のみが含まれ、コンパレーターの実装の詳細には依存しません。
Holger

32

列挙型を特に強力にする他の回答でカバーされていないものは、テンプレートメソッドを持つ能力です。メソッドは基本列挙型の一部であり、各タイプによってオーバーライドできます。そして、列挙型に取り付けた行動と、それは多くの場合、このようであれば、他の構築物またはswitch文の必要性がなくなりブログ記事を実証 -どこenum.method()何が当初の条件内で実行されますありません。同じ例は、列挙型での静的インポートの使用と、コードのようなよりクリーンなDSLの生成も示しています。

いくつかの他の興味深い性質は、列挙型のための実装を提供しているという事実が含まequals()toString()およびhashCode()、実施SerializableとをComparable

すべての列挙型の完全な概要については、この章の章全体を取り上げたBruce EckelのThinking in Java 4th Editionを強くお勧めします。列挙型としてRock、Paper、Scissors(つまりRoShamBo)ゲームを含む例は、特に明快です。


23

Java ドキュメントから-

定数の固定セットを表す必要があるときはいつでも列挙型を使用する必要があります。これには、コンパイル時のすべての可能な値(たとえば、メニューの選択、コマンドラインフラグなど)がわかっている太陽系の惑星やデータセットなどの自然列挙型が含まれます。

一般的な例は、クラスを列挙型のプライベート静的final int定数のセット(定数の数が妥当な範囲内)で置き換えることです。基本的に、コンパイル時に「何か」のすべての可能な値を知っていると思う場合、それを列挙型として表すことができます。列挙型は、定数を使用するクラスに対して可読性と柔軟性を提供します。

列挙型について考えることができる他の利点はほとんどありません。それらは常に特定の列挙型クラスの1つのインスタンスです(したがって、シングルトンの到着時に列挙型を使用するという概念)。もう1つの利点は、列挙型をswitch-caseステートメントの型として使用できることです。また、列挙型でtoString()を使用して、読み取り可能な文字列として出力することもできます。


8
1年のすべての366日間に列挙型を使用しますか?これは定数の固定セット(366)です(日は変わりません)。だから、これはあなたがすべきことを示唆しています。:-/固定セットのサイズを制限します。
モイヌディン2011年

2
@marcog少し賢い考えでは、曜日と各月の日をコンパクトな列挙型で要約することが可能かもしれません。
James P.

1
曜日といえば… DayOfWeekenumが事前定義され、java.timeフレームワークの一部としてJava 8以降に組み込まれています(Java 6および7Androidにバックポートされています)。
バジルブルク

19

さて、なぜそして何のために日々のプログラミングで列挙型を使用すべきですか?

Enumを使用すると、可読性を高めながら、定数の小さな固定セットまたは内部クラスモードを表すことができます。また、列挙型をメソッドパラメータで使用すると、特定の固定を強制できます。これらは、オラクルのサイトにあるPlanetsの例のように、コンストラクターに情報を渡すという興味深い可能性を提供します

例:すべての整数の代わりに区切り記号を追加すると、IDEに表示される固定値のセットLocale.setDefault(Locale.US)よりも読み取りが良くLocale.setDefault(1)、強制的に使用され.ます。


@arnt質問の文法も修正しました。ありがとう。
James P.

13

Enum■自己文書化された方法で、固定された値のセットを列挙します。
これにより、コードがより明確になり、エラーが発生しにくくなります。

定数の代わりにString、またはを使用しないのはなぜですか?intEnum

  1. 列挙型はそれ自体がであるため、コンパイラーはタイプミスを許可しません。また、固定セットの値も許可されません。結果:
    • 引数が有効な範囲にあることを保証するために、前提条件(またはマニュアルif)を記述する必要はありません。
    • 型不変は無料で付属しています。
  2. 列挙型は、他のクラスと同じように動作することができます。
  3. Stringとにかく、を使用するには、おそらく同じ量のメモリが必要になります(これはの複雑さに依存しEnumます)。

さらに、の各Enumインスタンスはクラスであり、その個々の動作を定義できます。

さらに、インスタンスの作成時(列挙型がロードされたとき)のスレッドの安全性を保証します。これは、シングルトンパターンの簡素化に優れたアプリケーションを示しています。

このブログは、パーサー用のステートマシンなど、そのアプリケーションの一部を示しています。


13

フィールドとaをenums持つ他のクラスと同じであることを知っておくと便利です。Constantprivate constructor

例えば、

public enum Weekday
{
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
} 

コンパイラはそれを次のようにコンパイルします。

class Weekday extends Enum
{
  public static final Weekday MONDAY  = new Weekday( "MONDAY",   0 );
  public static final Weekday TUESDAY = new Weekday( "TUESDAY ", 1 );
  public static final Weekday WEDNESDAY= new Weekday( "WEDNESDAY", 2 );
  public static final Weekday THURSDAY= new Weekday( "THURSDAY", 3 );
  public static final Weekday FRIDAY= new Weekday( "FRIDAY", 4 );
  public static final Weekday SATURDAY= new Weekday( "SATURDAY", 5 );
  public static final Weekday SUNDAY= new Weekday( "SUNDAY", 6 );

  private Weekday( String s, int i )
  {
    super( s, i );
  }

  // other methods...
}

12

enum列挙を意味します。つまり、(いくつかのことを)1つずつ言及します。

列挙型は、定数の固定セットが含まれているデータ型です。

または

アンはenum同じようであるclassコンパイル時に知られているインスタンスの固定セットで、。

例えば:

public class EnumExample {
    interface SeasonInt {
        String seasonDuration();
    }

    private enum Season implements SeasonInt {
        // except the enum constants remaining code looks same as class
        // enum constants are implicitly public static final we have used all caps to specify them like Constants in Java
        WINTER(88, "DEC - FEB"), SPRING(92, "MAR - JUN"), SUMMER(91, "JUN - AUG"), FALL(90, "SEP - NOV");

        private int days;
        private String months;

        Season(int days, String months) { // note: constructor is by default private 
            this.days = days;
            this.months = months;
        }

        @Override
        public String seasonDuration() {
            return this+" -> "+this.days + "days,   " + this.months+" months";
        }

    }
    public static void main(String[] args) {
        System.out.println(Season.SPRING.seasonDuration());
        for (Season season : Season.values()){
            System.out.println(season.seasonDuration());
        }

    }
}

列挙型の利点:

  • enumは、実行時のエラーを回避するために、コンパイル時のチェックにおける型の安全性を向上させます。
  • enumはスイッチで簡単に使用できます
  • 列挙型をトラバースできる
  • 列挙型には、フィールド、コンストラクター、およびメソッドを含めることができます
  • enumは多くのインターフェイスを実装できますが、内部的にEnumクラスを拡張するため、どのクラスも拡張できません

以下のためのより多くの


9

列挙型とは

  • enumは、新しいデータ型を列挙するために定義されたキーワードです。タイプセーフな列挙は自由に使用する必要があります。特に、これらは、関連するアイテムのセットを表すためにはるかに古いAPIで使用されている単純なStringまたはint定数の堅牢な代替手段です。

列挙型を使用する理由

  • 列挙型は暗黙的にjava.lang.Enumの最終サブクラスです
  • 列挙型がクラスのメンバーである場合、それは暗黙的に静的です
  • newは、列挙型自体の中であっても、列挙とともに使用することはできません
  • nameとvalueOfは列挙定数のテキストを使用するだけですが、必要に応じてtoStringをオーバーライドしてコンテンツを提供できます。
  • enum定数の場合、equalsおよび==は同じものに相当し、互換的に使用できます
  • 列挙型定数は暗黙的にpublic static finalです

注意

  • 列挙型はクラスを拡張できません。
  • 列挙型をスーパークラスにすることはできません。
  • 列挙型定数の出現順序は「自然順序」と呼ばれ、他の項目でも使用される順序を定義します。compareTo、値の反復順序、EnumSet、EnumSet.range。
  • 列挙には、コンストラクター、静的ブロックとインスタンスブロック、変数、およびメソッドを含めることができますが、抽象メソッドを含めることはできません。

4
列挙型を使用する理由を説明しません。関係のないヘッダーの下に列挙型のいくつかのプロパティをリストするだけです。
ダンカンジョーンズ

@DuncanJones final、staticという用語は、列挙型を使用する目的を与えませんか?
tinker_fairy 2013

8

他の人が言ったことは別として..私が以前使用していた古いプロジェクトでは、エンティティ(独立したアプリケーション)間の多くの通信は、小さなセットを表す整数を使用していました。enum静的メソッドと同様にセットを宣言して、enumオブジェクトを取得したり、valueその逆を行ったりすると便利です。コードは、見た目がすっきりしていて、ケースの使い勝手がよく、ログへの書き込みが簡単に見えました。

enum ProtocolType {
    TCP_IP (1, "Transmission Control Protocol"), 
    IP (2, "Internet Protocol"), 
    UDP (3, "User Datagram Protocol");

    public int code;
    public String name;

    private ProtocolType(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static ProtocolType fromInt(int code) {
    switch(code) {
    case 1:
        return TCP_IP;
    case 2:
        return IP;
    case 3:
        return UDP;
    }

    // we had some exception handling for this
    // as the contract for these was between 2 independent applications
    // liable to change between versions (mostly adding new stuff)
    // but keeping it simple here.
    return null;
    }
}

enum使用ProtocolType.fromInt(2) してログに書き込みを使用して、受信した値(例:1、2)からオブジェクトを作成しますmyEnumObj.name

お役に立てれば。


6

Enumは、Objectクラスと抽象クラスのすべてのメソッドを継承しますEnum。そのため、リフレクション、マルチスレッド、シリアライズ、比較などのメソッドを使用できます。Enumの代わりに静的定数を宣言するだけの場合はできません。さらに、Enumの値をDAOレイヤーに渡すこともできます。

デモするプログラムの例を示します。

public enum State {

    Start("1"),
    Wait("1"),
    Notify("2"),
    NotifyAll("3"),
    Run("4"),
    SystemInatilize("5"),
    VendorInatilize("6"),
    test,
    FrameworkInatilize("7");

    public static State getState(String value) {
        return State.Wait;
    }

    private String value;
    State test;

    private State(String value) {
        this.value = value;
    }

    private State() {
    }

    public String getValue() {
        return value;
    }

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public boolean isNotify() {
        return this.equals(Notify);
    }
}

public class EnumTest {

    State test;

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public State getCurrentState() {
        return test;
    }

    public static void main(String[] args) {
        System.out.println(State.test);
        System.out.println(State.FrameworkInatilize);
        EnumTest test=new EnumTest();
        test.setCurrentState(State.Notify);
        test. stateSwitch();
    }

    public void stateSwitch() {
        switch (getCurrentState()) {
        case Notify:
            System.out.println("Notify");
            System.out.println(test.isNotify());
            break;
        default:
            break;
        }
    }
}

4

ENumは「列挙型」を表します。これは、ユーザーが定義する定数の固定セットを持つデータ型です。


列挙型を使用する理由を説明していません。
ダンカンジョーンズ

4
はい、そうしました。自分で定義した定数の固定セットを格納するために使用します。それの特定のアプリケーションはあなた次第です。いつ、なぜ、どのように使うかというようなことはありません。それは開発者のニーズ次第です。あなたが理解する必要があるすべてはそれが何であるか、そしてそれがどのように機能するかです。
Steve

4

私の意見では、あなたが今までに得た答えはすべて有効ですが、私の経験では、それをいくつかの言葉で表現します。

コンパイラに識別子の値の有効性をチェックさせたい場合は、列挙型を使用します。

それ以外の場合は、いつものように文字列を使用でき(おそらく、アプリケーションに「規約」を定義しました)、非常に柔軟になります...しかし、文字列のタイプミスに対して100%のセキュリティは得られず、それだけが実現されます実行時。


3

TYPE SAFETYには列挙型を使用してください。これは言語機能であるため、通常は次のようになります。

  • コンパイラのサポート(タイプの問題をすぐに確認)
  • IDEでのツールのサポート(スイッチケースのオートコンプリート、欠落ケース、強制デフォルトなど)
  • 場合によっては、列挙型のパフォーマンスも優れています(EnumSet、従来のintベースの「ビットフラグ」のタイプセーフな代替手段)

列挙型にはメソッド、コンストラクターを含めることができ、列挙型の内部で列挙型を使用して、列挙型をインターフェースと組み合わせることができます。

enumは、適切に定義されたint定数のセット(JavaはC / C ++から「継承」)を置き換え、場合によってはビットフラグを置き換えるタイプと考えてください。

本「Effective Java 2nd Edition」には、それらに関する章全体が記載されており、さらに詳しく説明しています。こちらのスタックオーバーフローの投稿もご覧ください。


2

Javaでは、変数をいくつかの事前定義された値の1つだけ、つまり列挙されたリストからの1つの値に制限することができます。を使用enumsすると、コード内のバグを減らすことができます。以下はenumsクラス外の例です。

enums coffeesize{BIG , HUGE , OVERWHELMING }; 
//This semicolon is optional.

この制限しcoffeesize:有するかにBIGHUGEまたはOVERWHELMING変数として。


2

列挙?なぜそれを使用する必要があるのですか?使ってみるともっとわかりやすいと思います。同じ経験があります。

データベースの作成、削除、編集、読み取り操作があるとします。

列挙型を操作として作成する場合:

public enum operation {
    create("1")
    delete("2")
    edit("3")
    read("4")

    // You may have is methods here
    public boolean isCreate() {
        return this.equals(create);
    }
    // More methods like the above can be written

}

ここで、次のように宣言できます。

private operation currentOperation;

// And assign the value for it 
currentOperation = operation.create

したがって、さまざまな方法で使用できます。上記の例のデータベース操作は、currentOperationを確認することで制御できるため、特定の列挙型を用意しておくとよいでしょう。おそらく、これは変数と整数値でも実現できると言えるでしょう。しかし、私はEnumがより安全でプログラマーの方法であると信じています。

別のこと:私はすべてのプログラマーがbooleanを愛していると思いますよね?2つの値、2つの特定の値しか格納できないため。したがって、Enumは同じタイプの機能を備えていると考えることができます。ユーザーは、わずかに異なる方法で、保存する値の数とタイプを定義します。:)


1

これまでのところ、列挙型を使用する必要はありませんでした。彼らが1.5またはバージョンtigerで導入されて以来、それらはその日に呼ばれたので、私はそれらについて読んでいます。彼らは本当に私にとって「問題」を解決したことはありません。それを使用する人(そして私はそれらの多くを使用していると思います)にとって、それが間違いなく何らかの目的に役立つことを確信しています。ちょうど私の2イカ。


1

ここには多くの答えがありますが、特定の2つを指摘したいだけです。

1)Switch-caseステートメントで定数として使用する。スイッチケースでは、ケースにStringオブジェクトを使用できません。列挙型は便利です。もっと: http //www.javabeat.net/2009/02/how-to-use-enum-in-switch/

2)実装Singleton Design Pattern-Enumが再び助けになりました。ここでの使用法:EnumをJavaのシングルトンとして使用するための最良のアプローチは何ですか?


1

Ah-Haの瞬間を私に与えたのは、この認識でした。Enumには、パブリック列挙体を介してのみアクセス可能なプライベートコンストラクターがあります。

enum RGB {
    RED("Red"), GREEN("Green"), BLUE("Blue");

    public static final String PREFIX = "color ";

    public String getRGBString() {
        return PREFIX + color;
    }

    String color;

    RGB(String color) {
        this.color = color;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        String c = RGB.RED.getRGBString();
        System.out.print("Hello " + c);
    }
}

1

私がコードを将来的に読みやすくすることについては、列挙の最も有用な適用可能なケースが次のスニペットに表されています:

public enum Items {
    MESSAGES, CHATS, CITY_ONLINE, FRIENDS, PROFILE, SETTINGS, PEOPLE_SEARCH, CREATE_CHAT
}

@Override
public boolean onCreateOptionsMenu(Menu menuPrm) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menuPrm);
    View itemChooserLcl;
    for (int i = 0; i < menuPrm.size(); i++) {
        MenuItem itemLcl  = menuPrm.getItem(i);
            itemChooserLcl = itemLcl.getActionView();
            if (itemChooserLcl != null) {
                 //here Im marking each View' tag by enume values:
                itemChooserLcl.setTag(Items.values()[i]);
                itemChooserLcl.setOnClickListener(drawerMenuListener);
            }
        }
    return true;
}
private View.OnClickListener drawerMenuListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Items tagLcl= (Items) v.getTag();
        switch (tagLcl){
            case MESSAGES: ;
            break;
            case CHATS : ;
            break;
            case CITY_ONLINE : ;
            break;
            case FRIENDS : ;
            break;
            case  PROFILE: ;
            break;
            case  SETTINGS: ;
            break;
            case  PEOPLE_SEARCH: ;
            break;
            case  CREATE_CHAT: ;
            break;
        }
    }
};

1

私の経験では、Enumを使用すると、システムの変更が非常に困難になることがあります。頻繁に変化する一連のドメイン固有の値にEnumを使用してて、それに依存する他のクラスやコンポーネントがたくさんある場合は、Enumを使用しないことを検討してください。

たとえば、市場/交換にEnumを使用する取引システム。世の中にはたくさんの市場があり、この市場のリストにアクセスする必要のある多くのサブシステムが存在することはほぼ確実です。システムに新しい市場を追加したいとき、または市場を削除したいときはいつでも、太陽の下ですべてを再構築してリリースする必要がある可能性があります。

より良い例は、製品カテゴリタイプのようなものです。あなたのソフトウェアがデパートの在庫を管理しているとしましょう。多くの製品カテゴリがあり、このカテゴリのリストが変更される理由はたくさんあります。管理者は、新しい製品ラインの在庫を確保したり、他の製品ラインを削除したり、場合によってはカテゴリを再編成したりできます。ユーザーが製品カテゴリを追加したいだけの理由ですべてのシステムを再構築および再展開する必要がある場合、シンプルで高速なもの(カテゴリの追加)を採用し、それを非常に困難で低速にしました。

結論として、列挙するデータは、時間の経過とともに非常に静的であり、依存関係の数が限られている場合に適しています。しかし、データが大きく変化し、依存関係が多い場合は、コンパイル時にチェックされない動的なもの(データベーステーブルなど)が必要です。


1

enumベースのシングルトン

古い問題を現代的に見る

このアプローチは、列挙型の値がJavaプログラム内で1回だけインスタンス化され、列挙型がスレッドの安全性を暗黙的にサポートするというJavaの保証を利用して、シングルトンを実装します。Java enum値はグローバルにアクセスできるため、シングルトンとして使用できます。

public enum Singleton {
    SINGLETON; 
    public void method() { }
}

これはどのように作動しますか?さて、コードの2行目は次のようなものと考えることができます。

public final static Singleton SINGLETON = new Singleton(); 

そして、古き良き初期初期化シングルトンを取得します。

これは列挙型なので、いつでもインスタンスにアクセスできますSingleton.INSTANCE

Singleton s = Singleton.INSTANCE;
メリット
  • 逆シリアル化中にシングルトンの別のインスタンスを作成しないようにするには、列挙型のシリアル化がJVMによって処理されるため、列挙型ベースのシングルトンを使用します。列挙型シリアライゼーションとデシリアライゼーションは、通常のJavaオブジェクトとは異なる動作をします。シリアル化される唯一のものは列挙値の名前です。逆シリアル化プロセス中に列挙型valueOfメソッドがされた名前と共に使用され、目的のインスタンスを取得します。
  • Enumベースのシングルトンは、リフレクション攻撃から身を守ることができます。enum型は実際にはjava Enumクラスを拡張します。列挙型のオブジェクトのインスタンス化にリフレクションを使用できない理由は、Java仕様では許可されておらず、そのルールはクラスのnewInstanceメソッドの実装でコーディングされているためですConstructor。これは通常、リフレクションを介してオブジェクトを作成するために使用されます。
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
  • Enumは、各値のインスタンスが1つだけ存在する必要があるため、複製することは想定されていません。
  • すべてのシングルトン実現の中で最も簡潔なコード。
短所
  • enumベースのシングルトンは遅延初期化を許可しません。
  • デザインを変更し、シングルトンをマルチトンに変換したい場合、enumはこれを許可しません。マルチトンパターンは、を使用して管理する複数のインスタンスの制御された作成に使用されますmapアプリケーション(たとえばjava.lang.Runtimeごとに単一のインスタンスを持つのではなく、マルチトンパターンは代わりにキーごとに単一のインスタンスを保証します
  • EnumはJava 5でのみ表示されるため、以前のバージョンでは使用できません。

シングルトンパターンの実現には、それぞれ長所と短所がいくつかあります。

  • シングルトンのローディング
  • ダブルチェックロックシングルトン
  • 初期化オンデマンドホルダーイディオム
  • enumベースのシングルトン

それぞれの詳細な説明は冗長すぎるので、良い記事へのリンクを張るだけです - シングルトンについて知りたいすべてのこと


0

列挙型を便利なマッピング手段として使用if-else し、いくつかのメソッドが実装されている場合は複数を回避します。

public enum Mapping {

    ONE("1"),
    TWO("2");

    private String label;

    private Mapping(String label){
        this.label = label;
    }

    public static Mapping by(String label) {

        for(Mapping m: values() {
            if(m.label.equals(label)) return m;
        }

        return null;
    }

}

だから方法 by(String label)使用すると、列挙されていない値で列挙値を取得できます。さらに、2つの列挙型の間のマッピングを発明できます。「1対1」のデフォルトの関係に加えて、「1対多」または「多対多」を試すこともできます。

最後にenum、Javaクラスです。したがってmain、その中にメソッドを含めることができます。これは、マッピング操作をargsすぐに実行する必要がある場合に役立ちます。


0

一連のconst int宣言を行う代わりに

すべてを1つの列挙型にグループ化できます

つまり、それらが属する共通のグループによってすべて編成されています


0

列挙型はクラスのようなものです。クラスと同様に、メソッドと属性もあります。

クラスとの違いは次のとおりです。1. enum定数はpublic、static、finalです。2. enumはオブジェクトの作成に使用できず、他のクラスを拡張できません。しかし、それはインターフェースを実装することができます。


0

@BradB Answerに加えて:

それは本当です...それがそれを言及する唯一の答えであるのは奇妙です。初心者が列挙型を発見すると、すぐにそれをコンパイラの有効な識別子チェックのための手品と見なします。そして、コードが分散システムでの使用を意図している場合、彼らは泣きます...数か月後。静的でない値のリストを含む列挙型との下位互換性を維持することは、本当に心配であり、苦痛です。これは、既存の列挙型に値を追加すると、その型が変更されるためです(名前は変更されません)。

「ほら、ちょっと待って、同じ型のように見えるかもしれませんね。結局のところ、それらは同じ名前の列挙型であり、列挙型は内部の整数だけではないのですか?」また、これらの理由により、コンパイラーは、型自体の定義の1つに、他の定義が予期されていた場所にフラグを立てない可能性があります。しかし、実際には、それらは(最も重要な意味で)異なるタイプです。最も重要なのは、それらに異なるデータドメインがあることです。つまり、そのタイプで許容される値です。値を追加することで、列挙型を効果的に変更し、下位互換性をなくしました。

結論:必要なときに使用してください。ただし、使用するデータドメインが有限の既知の固定セットであることを確認してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.