2016-06-30 22 views
4

null値のテストを避けるために、JavaのArrayListフィールドを初期化するためのベストプラクティスは何ですか?宣言でJavaのArrayListフィールドを初期化するためのベストプラクティス

は、次のように:

private List<String> myList = new ArrayList<String>(); 

またはゲッターでは、このような:

public List<String> getMyList() { 
    if(myList == null) { 
     myList = new ArrayList<String>(); 
    } 
    return myList; 
} 

あるいは、コンストラクタで:

public Test(){ 
    myList = new ArrayList<String>(); 
} 

多分それは同じだが、しかし私は知りたいと思う。

+1

最初のもの。遅延初期化は大規模にオーバーレイされ、スレッドの安全性の問題が発生する可能性が非常に高くなります。 –

+0

@ cricket_007私はコンストラクタオプションの質問を編集しました – JavaDev

答えて

6

最初のオプションを使用すると、このように誤っ後に完全に新しいリストを作成してからあなたを防ぐ

private final List<String> myList = new ArrayList<>(); 

を行うことができます。マルチスレッドの問題を解決することができます。それに加えて、今コンパイラは、フィールドがのように、一度だけに初期化されていることを確認するのに役立ちます。

それを超えると、2番目のオプションは「遅延初期化」と見ることができます。そしてその意味では、それは「最適化の選択」と見ることができます!そこから:早期の最適化を避けることを擁護する多くの人々がいる!

あなたは既に作成されているリストに頼ることができないとき、それは多くの問題を引き起こす可能性があります。その視点から来ても、オプション1を好む別の議論があります!

コンパイラオプションに関する編集:セマンティクスポイントからオプション1と3は多かれ少なかれ同等です[ヒント:オプション1またはオプション3を選択した場合、コードに違いがあることがわかっている場合。 ..それはあなたのコードで何かがひどく間違っているという良い兆候になります)。それにもかかわらず

、違いを作ることができます一つのこと - あなたのような、「依存性注入」コンストラクタを持っている場合:

public YourClass() { this(new ArrayList<String>); } 
YourClass(List<String> incomingList) { myList = incomingList; } 

このソリューションは、あなたが「コントロール」する必要のあるオブジェクトのこれらの種類の意味があります;という意味で:ユニットテストを可能にするには、クラスにモックを渡す必要があります。

かいつまん:可能であれば

  • は、オプション1を好む:最終
  • 使用オプション3を使用して、あなたはそれのために行くには本当に十分な理由がない限り、依存性注入を
  • 避けオプション2を必要とする場合
+1

オプション3でも 'final'が可能 –

+0

オプション1のfinalを使う理由を説明できますか? – JavaDev

+1

@JavaDev簡単に言えば:私がそこに上場しているものはすべて無料で入手できるからです。申し訳ありませんが、私はあなたの質問を得ることはありません:私はなぜoption1 + finalが "最良の選択"であるのかについてかなりの理由を付けたと思いました。 – GhostCat

0

これは用途によって異なりますが、私は最初のオプションを優先します。

private List<String> myList = new ArrayList<String>();

あなたのクラスは、クラスのユーザーがnullmyList変数を設定することができる場合のArrayListを再作成することが予想される場合は、2番目のオプションは、いくつかの利点を有することができます。それは私には悪い練習のように思えるでしょう。

1

ゲッターの一般的な遅延初期化は、それが価値があるよりも面倒です。あなたは(あなたはそれがほとんどの場合に空であることを期待しているため)リストで使用されるメモリを最小限にしたい深刻な問題が発生した場合は、ゼロの初期容量でそれを初期化することができます:

private List<String> myList = new ArrayList<String>(0); 

があります可読性を除いて、インスタンス変数宣言とコンストラクターの初期化の間に実際的な違いはありません。初期化をインスタンス宣言に置くと、コンストラクタの初期化をインスタンス変数に戻して、それらが確実にカバーされていることを確認する必要があります。

現実世界のコードの多くは、サードパーティのライブラリとフレームワークで動作する必要があります。 HibernateやSpringのようなライブラリやフレームワークで動作するクラスを作成すると、ゲッターの遅延初期化が問題になることはありません。これは、Springがこれらの処理を引き継ぐか、クラスを使用するライブラリがスワップアウトするからですあなたのList実装はさまざまな理由で独自に実装されています(Hibernateは遅延ロードを実装するためにこれを行います)。したがって、getterとsetterを、それらを使用するサードパーティのコードによって行われる前提を無効にしないために、できるだけシンプルで直接的にしてください。

+0

容量を0に設定するのはなぜですか?デフォルトでは、空のリストサイズは0です。 – JavaDev

+1

@ JavaDev:デフォルトは10です。capacityは、リスト内の要素の数であるsizeとは対照的に、事前に割り当てられた領域です。 –

関連する問題