2013-05-06 7 views
32

この回答を読んでいる間に質問が発生しました。question - How do I join two lists in javaこのanswerコメントを読むソリューション匿名のクラスを使用する際の害は何ですか?

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } }; 

を与え、ユーザーはそれを悪と醜いだったと生産に使用すべきではないと述べました。

これを使用する際に何が問題になるのですか?なぜそれは生産で使用するのが醜い、悪い、または悪いのですか?


注:参照先が古すぎ(2008年)、回答者が数か月以上離れているため、質問としてください。

+1

が1行ではありませんやっぱそれは、:-)他の開発者を混乱させますかもしれコード。 – Subin

+2

[Javaの効率 "ダブルブレースの初期化"?](http://stackoverflow.com/questions/924285/efficiency-of-java-double-brace-initialization) – assylias

+4

@assylias:リンク先の質問主にパフォーマンスに関するものです。私はそれが重複しているとは思わない。 –

答えて

46

良いプログラミングスタイルと継承の悪用に関する前述の問題を除いて、内部クラスと(非静的な)匿名クラスインスタンスがクロージャとして機能する、もう少し微妙な問題があります。これは、包含するクラスインスタンスへの暗黙の参照を保持していることを意味します()。これはガベージコレクションの防止につながり、最終的にメモリリークを引き起こす可能性があります。ソースコードの例ピースを考える

public interface Inner { 
    void innerAction(); 
} 

public class Outer { 

    public void methodInOuter() {} 

    private Inner inner = new Inner() { 
     public void innerAction() { 
      // calling a method outside of scope of this anonymous class 
      methodInOuter(); 
     } 
    } 
} 

コンパイル時に何が起こるには、コンパイラは、いわゆる合成フィールドを取得Innerの新しい匿名のサブクラスのクラスファイルを作成することですOuterクラスのインスタンスを参照してください。親インスタンスへの参照のような捕捉がさえなど、実際に囲むクラスのメソッドやフィールドのいずれかにアクセスすることはありません匿名クラス、ために起こる

public class Outer$1 implements Inner { 

    private final Outer outer; // synthetic reference to enclosing instance 

    public Outer$1(Outer outer) { 
     this.outer = outer; 
    } 

    public void innerAction() { 
     // the method outside of scope is called through the reference to Outer 
     outer.methodInOuter(); 
    } 
} 

:生成されたバイトコードは次のようなものとほぼ同じになりますあなたの質問に二重ブレース初期化(DBI)リスト。

この結果、DBIリストは、存在する限り、囲むインスタンスへの参照を保持し、囲むインスタンスがガベージコレクションされないようにします。たとえば、MVCパターンのモデルの一部として、DBIリストがアプリケーション内で長時間生き残ったとし、キャプチャされたクラスを囲むことは、例えば、多くのフィールドを持つかなり大きなクラスであるJFrameです。いくつかのDBIリストを作成した場合、非常に迅速にメモリリークが発生します。

可能な解決策の1つは、範囲内で使用可能なそのような囲い込みインスタンスがないため、静的メソッドでのみDBIを使用することです。

一方、DBIの使用は、ほとんどの場合、依然として必要というわけではありません。リスト参加に関しては、私はより安全であるだけでなく、より簡潔で明確な単純な再利用可能なメソッドを作成します。

public static <T> List<T> join(List<? extends T> first, List<? extends T> second) { 
    List<T> joined = new ArrayList<>(); 
    joined.addAll(first); 
    joined.addAll(second); 
    return joined; 
} 

そして、クライアントコードは、単純に次のようになります。

List<String> newList = join(listOne, listTwo); 

さらに読書: https://stackoverflow.com/a/924536/1064809

+2

+1。 **本当の**問題点を指摘する唯一の答えは –

+3

これも当てはまります。継承を濫用すると、完全に使用可能なデータプロパティ(値/コレクションアイテム)を設定するのではなく、徹底的に悪化します。 –

+2

+1は '静的'メソッドでDBIを使用することが害を軽減することを示しています。 – gaborsch

4

別のサブクラスを必要としないので、通常のクラスの新しいArrayListを作成するだけで、addAll()の両方がリストされます。

ので、同じように:

public static List<String> addLists (List<String> a, List<String> b) { 
    List<String> results = new ArrayList<String>(); 
    results.addAll(a); 
    results.addAll(b); 
    return results; 
} 

それは、サブクラスを作成する悪だ、それは必要ありません。 の動作をに拡張またはサブクラスする必要はありません。ちょうどのデータ値をに変更してください。

+0

''を ''に置き換え、 'static'の後に' 'を追加すると、すべてのリストで動作します。また、varargsを追加すればいいので、任意の数のリストに参加することができます。 –

+1

私はこれを私の図書館に持っています:)しかし、誰かが何とか始めるのが間違っている複雑なものを見せてくれることをためらっています。正しさは、シンプルさの青からのようなものでなければなりません。 –

16

匿名クラスのこの特定の使用には、いくつかの問題があります。

  1. それはあまり知られていないイディオムです。それを知らない(またはそれをたくさん使っていないことを知っている)開発者は、それを使用するコードを読んだり変更したりするときには遅くなります。
  2. それは実際に言語機能を悪用だ:あなたはArrayListの新しい種類を定義しようとしていない、それはリソースを占有し、新しいクラスを作成
  3. それにあなただけのいくつかの既存の値を持ついくつかの配列リストが欲しい:ディスクスペースをクラス定義を保持するために、パースジェンはクラス定義を保持するために解析/検証/ ...パーマネント...
  4. 「実際のコード」がわずかに長くても、ユーティリティメソッド(joinLists(listOne, listTwo)

私の意見では、#1はそれを避ける最も重要な理由です。 #3はそれほど大きな問題ではありませんが、忘れてはいけません。

+3

継承が必要ない場合、継承を誤って使用しています。 –

+0

@ThomasW:はい、それは私の#2だと思いますか、それとも違った解釈をしましたか? –

+0

3. [...]、 ".class"ファイルのロード中にJVMがクラスを検証する時間。 –

2

パフォーマンスやそれに類するものではありませんが、アプローチは少し不明です。このようなものを使用すると、常にこのアプローチを説明する必要があります(たとえば99%)。私は、このアプローチを使用しない最大の理由の一つだと思うし、入力中:

​​

は、それが理解やデバッグコードで多くのことができますされ、読み少し簡単ですが、もう少しタイピングです。

17

「醜い」と「プロダクションで使用しない」コメントは、この匿名クラスの特定の使用を参照していますが、一般的な匿名クラスではありません。

この特定の使用はnewListを割り当てArrayList<String>の匿名のサブクラスで、心の中で単一の目的で作成した、まったく新しいクラス - つまり、2つの特定のリストの内容でリストを初期化します。これはあまり読みにくくはありません(経験豊富な読者であっても数秒を費やすことになります)が、もっと重要なことに、同じ数の操作でサブクラス化せずに達成できます。

本質的に、ソリューションは新しいサブクラスを作成することで小さな利便性を提供します。たとえば、コレクションに特定のコレクションを持つことを期待する自動化されたフレームワークを使用してこのコレクションを永続化しようとするとタイプ。

+0

+1は、一般的に匿名のクラスでは問題がないことを指摘しています。 –

1

あなたの例では、少なくとも私にとって少なくとも悪い醜いと思われます。コード内で何が起こっているのかを理解することは難しいです。しかし、私は、ベストプラクティスのケースの上に呼び出します

Arrays.sort(args, new Comparator<String>() { 
     public int compare(String o1, String o2) { 
      return ... 
     }}); 

例えば、人々は、彼らは非常に多くの場合、それらを参照してくださいので、に使用されている匿名クラスを使用してのいくつかのパターンがあります。

関連する問題