今日、私はこのサイトでいくつかの質問を拾い読みしていました、そして、私はenum
シングルトンパターンで使われている そのような解決策に対するスレッド安全性の利益についての言及について見つけました。
私はenum
sを一度も使ったことがなく、今から2年以上Javaでプログラミングしています。そしてどうやら彼らは大きく変わった。今や彼らはOOPを本格的にサポートしています。
変数(特にメソッドパラメータ)が少数の可能な値から1つしか取り得ない場合は、常に列挙型を使用する必要があります。例としては、型定数(契約ステータス: "permanent"、 "temp"、 "apprentice")、フラグ( "execute now"、 "defer execution")などがあります。
整数(または文字列コード)の代わりに列挙型を使用する場合は、コンパイル時のチェックを強化し、無効な定数を渡すことによるエラーを回避し、どの値を使用するのが正しいかを文書化します。
ところで、列挙型の使い過ぎはあなたのメソッドがやり過ぎることを意味するかもしれません(それがすることを変更するいくつかのフラグを取る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)
versus
/** 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);
もうできません。
プログラミング言語機能を使用する理由言語がある理由は
列挙型は、大量の定型文を書くことなく、正確性と読みやすさの両方を向上させます。定型文を作成する場合は、列挙型を「シミュレート」できます。
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
enumシミュレーションがnotを提供することの1つは、Nice 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;
}
ただし、色を保持する変数の型はint
でなければなりません。列挙型およびstatic final
シミュレーションのNiceコンパイラーチェックはなくなりました。満足していない。
妥協案は、シミュレーションでスカラー値のメンバーを使用することです。
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 enumareが完全なクラスとして実装されているため、これを回避できます。これも定型的ではありませんが、イディオムに慣れていない限り明白ではありません。 ord
やvalues
など、シングルトンにはあまり意味がありませんが、さまざまな列挙関数を取得するという事実も嫌いです(実際には、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
}
getInstance
がまだnullであるときに多くのスレッドがINSTANCE
を同時に呼び出す場合、任意の数のインスタンスを作成できます。これは悪いです。唯一の解決策は、変数synchronized
を保護するためにINSTANCE
アクセスを追加することです。
ただし、上記のstatic final
コードにはこの問題はありません。クラスのロード時にインスタンスを積極的に作成します。クラスの読み込みは同期されます。
enum
シングルトンは、最初に使用するまで初期化されないため、事実上レイジーです。 Java初期化も同期されるため、複数のスレッドはINSTANCE
の複数のインスタンスを初期化できません。非常に少ないコードで遅延初期化されたシングルトンを取得しています。唯一のマイナスは、かなり曖昧な構文です。何が起こっているのかを知るには、イディオムを知るか、クラスの読み込みと初期化がどのように機能するかを完全に理解する必要があります。
すでに述べたユースケース以外にも、基本的なOOPガイドラインに従って、戦略パターンを実装するために列挙型が役立つことがよくあります。
最も簡単な例は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());
}
};
}
この「パターン」ははるかに複雑なシナリオで使用することができ、enumに付随するすべての機能を幅広く利用できます。インスタンスの反復、それらの暗黙の順序による信頼、名前によるインスタンスの取得、正しいインスタンスを提供する静的メソッドそれでも特定のコンテキストなどのために、これはすべてインターフェースの背後に隠されているので、「デフォルトオプション」の中で使用できないものが必要な場合に備えて、コードは変更なしでカスタム実装で機能します。
これは、すべてのロジックが列挙型にカプセル化されている時間単位(毎日、毎週など)の概念のモデリングにうまく適用されていることがわかりました。方法など)。それでも、サービス層から見たGranularity
は単なるインターフェースでした。
列挙型を特に強力にする他の答えのどれもカバーしていないものは、 テンプレートメソッド を持つ機能です。メソッドはベース列挙型の一部であり、各タイプによってオーバーライドされます。そして、列挙型にアタッチされた動作により、多くの場合、if-elseコンストラクトやswitchステートメントの必要がなくなります。これは、 ブログ投稿が示すように -ここで、enum.method()
は、条件付き。同じ例は、enumsを使用した静的インポートの使用と、コードのようなはるかにクリーンなDSLの生成も示しています。
他の興味深い性質には、enumがequals()
、toString()
およびhashCode()
の実装を提供し、Serializable
およびComparable
を実装するという事実が含まれます。
列挙型が提供しなければならないすべての完全な要約については、ブルース・エッケルの Thinking in Java 4th edition をお勧めします。特に光を放つのは、ロック、ペーパー、ハサミ(つまりRoShamBo)ゲームを列挙した例です。
Javaから ドキュメント -
あなたが定数の固定セットを表す必要があるときはいつでもenum型を使うべきです。これには、太陽系の惑星や、コンパイル時にすべての可能な値を知っているデータセット(メニューの選択、コマンドラインフラグなど)などの自然な列挙型が含まれます。
一般的な例は、クラスをenum型の(妥当な数の定数内の)プライベートな静的final int定数のセットで置き換えることです。基本的に、コンパイル時に "something"のすべての可能な値を知っていると思うなら、それを列挙型として表すことができます。列挙型は、定数を持つクラスよりも読みやすさと柔軟性を提供します。
列挙型について考えることができる他の利点はほとんどありません。それらは常に特定の列挙型クラスの1つのインスタンスです(したがって、シングルトンが到着するときに列挙型を使用するという概念)。もう1つの利点は、switch-caseステートメントで列挙型を型として使用できることです。また、enumに toString() を使用して、それらを読みやすい文字列として表示することもできます。
それではなぜ、そして何のために私は毎日のプログラミングでenumを使用すべきですか?
読みやすさを向上させながら、定数の小さな固定されたセットまたは内部クラスモードを表すためにEnumを使用することができます。また、メソッドパラメータで使用すると、Enumは一定の剛性を強制することができます。 Oracleのサイトの Planetsの例のように、コンストラクタに情報を渡すという興味深い可能性があります そして、シングルトンパターンを作成する簡単な方法も可能にします。
例:Locale.setDefault(Locale.US)
はLocale.setDefault(1)
より読みやすく、すべての整数の代わりに.
区切り文字を追加するときにIDEに表示される固定値のセットの使用を強制します。
Enum
sは、自己文書化の方法で、固定値のセットを列挙します。
それらはあなたのコードをより明確にし、エラーを起こしにくくします。
なぜ定数にString
の代わりにint
やEnum
を使わないのですか?
if
)を書く必要はありません。String
sを使うためにはおそらく同じような量のメモリが必要になるでしょう(これはEnum
の複雑さに依存します)。さらに、それぞれのEnum
のインスタンスはクラスであり、その個々の振る舞いを定義することができます。
さらに、それらはインスタンスの作成時(enumがロードされたとき)にスレッドセーフティを保証します。これは シングルトンパターン を単純化するのに素晴らしい応用を見ました。
このブログ は ステートマシンなどのそのアプリケーションのいくつかを示しています パーサのためのものです。
enums
がConstant
フィールドとprivate 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...
}
enum
は enum erationを意味します。
enum は、定数の固定セットを含むデータ型です。
OR
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の利点:
more の場合
私が以前働いていた古いプロジェクトでは、エンティティ間の多くのコミュニケーション(独立したアプリケーション)は小さなセットを表す整数を使っていました。静的メソッドを使用してセットを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;
}
}
ProtocolType.fromInt(2)
を使用して受信した値(例1,2)からenum
オブジェクトを作成します。myEnumObj.name
を使用してログに書き込みます
お役に立てれば。
EnumはObject
クラスと抽象クラスEnum
のすべてのメソッドを継承しています。そのため、リフレクション、マルチスレッド、serilization、比較などにこのメソッドを使用できます。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;
}
}
}
ENumは "列挙型"を表します。それはあなたがあなた自身で定義する定数の固定セットを持つデータ型です。
列挙型?なぜそれを使うべきですか?あなたがそれを使うとき、私はそれがもっと理解していると思います。私は同じ経験をしています。
データベースの作成、削除、編集、および読み取り操作があるとします。
今度は操作としてenumを作成するとします。
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を持つことは常に良いことです。おそらくこれは変数と整数値でも達成できると言えるでしょう。しかし、私はEnumがより安全でプログラマーの道であると信じています。
もう一つのこと:私はすべてのプログラマが ブール値 を愛していると思います、私たち? 2つの値、2つの特定の値しか格納できないためです。そのため、Enumは、ユーザーが保存する値の種類と種類をわずかに異なる方法で定義する、同じ種類の機能を持つと考えることができます。 :)
私の考えでは、あなたが今までに得たすべての答えは有効ですが、私の経験では、私はいくつかの言葉でそれを表現するでしょう。
コンパイラに識別子の値の有効性をチェックさせる場合は、enumを使用します。
そうでなければ、あなたはいつものように文字列を使うことができ(おそらくあなたのアプリケーションのためにいくつかの "規約"を定義した)そしてあなたは非常に柔軟になるでしょう…実行時に。
TYPE SAFETYには列挙型を使用します。これは言語機能なので、通常は次のようになります。
列挙型はメソッド、コンストラクタを持つことができます、あなたは列挙型の中で列挙型を使用することができて、そしてインタフェースと列挙型を結合することさえできます。
列挙型は、(JavaがC/C++から「継承」した)明確に定義されたint定数のセットを置き換えるための型として考えてください。
効果的なJava 2nd Edition という本には、それらについての全章があり、さらに詳細に説明されています。 このStack Overflow post もご覧ください。
Javaでは、いくつかの定義済みの値、つまり列挙型リストからの1つの値のみを持つように変数を制限できます。 enums
を使うことはあなたのコードのバグを減らすのに役立ちます。これはクラス外のenums
の例です:
enums coffeesize{BIG , HUGE , OVERWHELMING };
//This semicolon is optional.
これはcoffeesize
が、変数としてBIG
、HUGE
、またはOVERWHELMING
のいずれかを持つことに制限されます。
これまでのところ、私は列挙型を使用する必要はありませんでした。 1.5またはバージョンtigerで導入されて以来、私はそれらについて読んできました。彼らは私にとって本当に「問題」を解決したことはありません。それを使う人にとっては(そして私は彼らの多くがそうするのを見ます)、それが間違いなく some 目的に役立つことを確信しています。私の2人だけです。
ここにはたくさんの答えがありますが、2つの具体的な答えを挙げたいと思います。
1)Switch-case
ステートメントで定数として使用する。大文字と小文字の切り替えでは、大文字と小文字の区別にStringオブジェクトを使用できません。 Enumは役に立ちます。もっと: http://www.javabeat.net/2009/02/how-to-use-enum-in-switch/ /
2)Singleton Design Pattern
の実装 - 再びEnum、救済する。使用法は、ここ: JavaでシングルトンとしてEnumを使用するための最良の方法は何ですか?
私が将来コードを読みやすくするために、列挙の最も有用で適切なケースは次のスニペットで表されます:
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;
}
}
};
私に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);
}
}
私の経験では、Enumを使用するとシステムの変更が非常に困難になることがあります。頻繁に変更される一連のドメイン固有の値にEnumを使用していて、それに依存する他のクラスやコンポーネントが多数ある場合は、Enumの使用ではなくを検討することをお勧めします。
たとえば、市場/取引所にEnumを使用する取引システムです。そこにたくさんの市場があります、そしてそれは市場のこのリストにアクセスする必要がある多くのサブシステムがあることはほぼ確実です。システムに新しい市場を追加したい場合、または市場を削除したい場合は、太陽の下ですべてを再構築して解放する必要があります。
より良い例は、商品カテゴリタイプのようなものです。あなたのソフトウェアがデパートの在庫を管理しているとしましょう。多くの製品カテゴリがあり、このカテゴリのリストが変わる可能性がある多くの理由があります。管理者は、新しい製品ラインを仕入れ、他の製品ラインを取り除き、場合によってはカテゴリを再編成したいと思うかもしれません。ユーザーが製品カテゴリを追加するだけの理由ですべてのシステムを再構築および再展開する必要がある場合は、単純で高速なもの(カテゴリの追加)を選択し、それを非常に困難で低速にします。
つまり、Enumは、表現しているデータが時間の経過とともに非常に静的であり、依存関係の数が限られている場合に適しています。しかし、データが大幅に変更され、多くの依存関係がある場合は、コンパイル時にチェックされない動的なもの(データベーステーブルなど)が必要です。
いくつかのメソッドが実装されている場合は、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つのenum間のマッピングを発明することができます。 「1対1」のデフォルトの関係に加えて、「1対多」または「多対多」を試すこともできます。
結局、enum
はJavaクラスです。そのため、その中にmain
メソッドを含めることができます。これは、args
に対してすぐにマッピング操作を行う必要がある場合に便利です。
たくさんのconst int宣言をする代わりに
あなたはそれらすべてを1つの列挙型にまとめることができます。
それで、そのすべては彼らが属する共通のグループによって組織されました