2016-10-06 6 views
0

新しいクラスのコンストラクタを含む関数を提供する列挙型が必要です。 Java8の前に私はこのコードを書いていました:関数を含むjava enum - メンバー変数としてスイッチまたはサプライヤを使用する

enum Fruit1 { 
    APPLE, BANANA; 

    public Tree getTree() { 
     switch (this) { 
      case APPLE: 
       return new AppleTree(); 
      case BANANA: 
       return new BananaTree(); 
      default: 
       throw new IllegalStateException(); 
     } 
    } 
} 

ここではラムダ式を使用できます。利点は、新しいenumエントリを追加するときに、switch文にsthを追加することを忘れることができないことです。しかし、私はコードがもっと複​​雑に見えてしまうのではない。

enum Fruit2 { 
    APPLE(AppleTree::new), BANANA(BananaTree::new); 

    Supplier<Tree> treeSupplier; 

    Fruit2(Supplier<Tree> treeSupplier) { 
     this.treeSupplier = treeSupplier; 
    } 

    public Tree getTree() { 
     return treeSupplier.get(); 
    } 
} 

それは単なる味の問題か、それ以上のものですか?ラムダ式を使ってより良い方法でそれを行うことはできますか?

これはother questions comparing lambda expressions to abstract methodsと関連の深いものですが、スイッチの表現に焦点を当てたいと思います。ラムダ式と比較してもかなり快適です。

+0

コードがもっと複​​雑に見えたら、なぜそれを使いたいのですか?私はそれがより簡単でより良いことがわかります。しかし、あなたがより良く考えるものを定義します。 – Tunaki

+2

[Java 8のenumsでメソッドをオーバーライドする理由はありますか?](http://stackoverflow.com/questions/28277562/is-there-any-reason-to-override-methods-in-enums-in) -java-8) – sprinter

+0

ラムダ式の変種は条件付きではありませんが、ホットスポットオプティマイザは、 'switch'ステートメントバリアントをパフォーマンスに関連するものにする場合、同様の結果に最適化できるはずです。そして、唯一の違いは、 'switch'文に' default:throw IllegalStateException(); 'を書く必要があることです。ラムダバリアントはそれを必要としません... – Holger

答えて

3

あなたの2番目のスニペットはうまく見えます。あなたがそうでないと感じた場合は、列挙型、一定のレベルで、あなたのメソッドの実装をもたらすことによって同様の何かを行うことができます:あなた自身に尋ねるべきで

enum Fruit1 { 
    APPLE { 
    public Tree getTree() { return new AppleTree(); } 
    }, BANANA { 
    public Tree getTree() { return new BananaTree(); } 
}; 

    public abstract Tree getTree(); 
} 
+0

これは素晴らしい解決策です - 私はしばしば、関数型ではなく関数を使用することがあなたにどちらかのオプションを与えることが分かった。このソリューションでは、依然としてサプライヤが必要な場合、 'myFruit :: getTree'や' APPLE :: getTree'のようなメソッド参照を使ってサプライヤを作成することができます。 –

1

ことの一つは、間のこのような密結合を持つことは良い考えであるかどうかでありますFruitの列挙型とTreeのクラス階層があります。代替手段を考えてみましょう:

public enum Fruit { APPLE, BANANA } 

public class TreeFactory { 
    static EnumMap<Fruit,Supplier<Tree>> SUPPLIERS=new EnumMap<>(Fruit.class); 
    static { 
     SUPPLIERS.put(Fruit.APPLE, AppleTree::new); 
     SUPPLIERS.put(Fruit.BANANA, BananaTree::new); 
     assert SUPPLIERS.keySet().containsAll(EnumSet.allOf(Fruit.class)); 
    } 
    public static Tree getTree(Fruit f) { 
     return SUPPLIERS.getOrDefault(
      Objects.requireNonNull(f),()->{throw new AssertionError();}).get(); 
    } 
} 

enum特化したコレクションは、switch文またはenum定数自身でデータを保存するようにハードコーディングされた代替手段として効率的です。しかし、この解決策は、タイプについて何かを知るためにFruitタイプを必要とせずに機能します。

+0

大変感謝しています。果物と樹木の切り離し、サプライヤーのアサーションチェックが好きです。 – user954923

関連する問題