不要なオブジェクトの作成を避ける[アイテム6]



  • 通常、同じ機能を持つオブジェクトを作成するたびに、同じ機能を持つオブジェクトを繰り返し使用するよりも、繰り返し使用の方が速く、スタイリッシュで、いつでも変わらないオブジェクトを繰り返し使用することができます.
  • String s = new String("bikini");のような方法では、実行するたびに新しいインスタンスが作成されますが、そうすることはできません.

  • これをString s = "bikini";に改良すると、Stringインスタンスが使用される

  • この方法では、同じ仮想マシンで同じ文字列テキストを使用するすべてのコードが同じオブジェクトを繰り返し使用することを保証します.
  • 同じ仮想マシンで同じ文字列の文字を使用しますか?
    String Constant Pool
    ここでは、上述したようなnew演算子を用いて、同じ内容であっても個別のオブジェクトとして用いることができる.
    したがって、new演算子は使用しないことをお勧めしますが、文字列テキストを使用してこの問題を解決することができます.つまり、文字列テキストの形式で文字列を作成すると、文字列値はHeap領域内のString Constatnt Poolに格納され、以下に示すように再使用されます.

    したがって、Stringは、intern()という名前の方法を使用してこれを検証することができ、Poolにおいてアドレスがない場合、生成されたアドレスを返すことによってこれを検証することができる.
    @DisplayName("이미 Pool에 값이 있다면 같은 주소를 바라본다.")
    @Test
    public void test2_1(){
        String s = new String("aaa");
        String b = "aaa";
        String c = s.intern();
    
        assertThat(b == c);
    }
    したがって、文字列テキストのすべてのコードを使用すると、同じオブジェクトが重複して使用されることを保証できます.

  • ジェネレータではなく静的メソッドを提供する不変クラスでは、静的メソッドを使用して不要なオブジェクトの作成を回避できます.

  • コストのかかるオブジェクトを作成する場合は、キャッシュして再使用することをお勧めします.

  • ここで文字列の有効なチェックを行う場合は、次のように正規表現を使用してこの問題を解決できます.
  • static boolean isRomanNumeral(String s) {
    		return s.matches("^(?=.)M*C[MD|D?C{0,3})"
    						+ "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
    }

  • ただし、パフォーマンスが非常に重要な場合、Patternは入力された正規表現に対応する有限ステートマシンを作成するため、インスタンスを作成するコストが高いため、再使用は正しくありません.

  • この場合、パフォーマンスを改善する必要がある正規表現を示すために、クラス初期化(静的初期化)中にPatternインスタンスを直接作成してキャッシュし、後でisRomanNumeralメソッドを呼び出すときに再使用します.
  • public class RomanNumerals {
    		private static final Pattern ROMAN = Pattern.compile("^(?=.)M*C[MD|D?C{0,3})"
    						+ "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
    
    		static boolean isRomanNumeral(String s) {
    				return ROMAN.matcher(s).matches();
    		}
    }

  • 上記の改良により、頻繁に呼び出されるとパフォーマンスが大幅に向上

  • 存在すら知らないPatternインスタンスをstatic finalフィールドにドラッグして名前を付けることで、コードの意味がより明確になります.

  • このメソッドを呼び出さないと、ROMANフィールドは余分に初期化されます.遅延初期化を使用すると、パフォーマンスが改善されず、コードも複雑になります.

  • オブジェクトが変更されていない場合は、再使用は大幅に安全ですが、明確でない場合や直感性とは逆の場合があります.

  • ここで、アダプタはバックエンドオブジェクトのみを管理し、各バックエンドオブジェクトは1つのアダプタのみを作成します.

  • MapインタフェースのKeySetメソッドは、Setインスタンスが返すすべてのインスタンスにも適用されます.この返されるオブジェクトを変更すると、他のすべてのオブジェクトが変更されます.これは、KeySetが複数のビューオブジェクトを作成できることを意味しますが、メリットはありません.
  • 有限状態機
    ゆうげんじょうたいき
    有限状態機械の定義は、デバイスまたはモデルが有することができる有限状態と、条件に合致するイベントが発生すると、デバイスまたはモデルがこのような状態変化で動作することを意味する.
    この部分については、入力Patternの正規表現に対応する有限ステートマシンを作成すると述べています.これは、正規表現で文字列を決定する形式自体が、決定に使用されるカテゴリで有限ステートマシンでマッチングされ、比較されるためと見なすことができます.

  • オートテッセレーションは、基本タイプとテッセレーションの基本タイプを混合して使用するときに自動的に変換する技術です.

  • 自動アセンブリも不要なオブジェクトを作成する別の例です.

  • オートテッセレーションでは、基本タイプと対応するテッセレーション基本タイプがぼやけますが、完全には除去されません.
  • private static long sum() {
    		Long sum = 0L;
    		for (long i = 0; i <= Integer.MAX_VALUE; i++)
    				sum += i;
    		
    		return sum;
    }

  • sum変数をlongではなくlongとして宣言し、不要なlongインスタンスを作成します.

  • この場合、埋め込みの基本タイプに比べてデフォルトタイプが使用されていることを知っておく必要があります.意外な自動埋め込みを隠すことに注意してください.

  • 重要なのは、オブジェクトの作成にかかるコストが高いため、避けなければならない問題と見なすべきではありません.小さなオブジェクトの作成と回収はあまり負担になりません.プログラムの明確性、簡潔性、機能のために、他のオブジェクトを作成するのは良いことです.

  • ただし、オブジェクトが非常に重い場合を除き、オブジェクトの作成を回避するために独自のオブジェクトプールを作成しないでください.

  • データベース接続では、再使用することが望ましいが、独自のオブジェクトプールではコードが混同され、メモリの使用量が増加し、パフォーマンスが低下する.
  • オブジェクトプールを作成してオブジェクトの作成を回避しますか?
    ここでオブジェクトプールを作成すること自体がオブジェクトプールであり、オブジェクトが必要なときに一連の操作を要求、戻し、実行するためのオブジェクトプールが存在します.
    これにより、ユーザは、予め作成されたプールを介してオブジェクトを受信することができる.すなわち、オブジェクトクラスが存在する場合、オブジェクトを冷却するファクトリを作成し、ファクトリを介してオブジェクトを冷却することができる.
    しかし、この場合、前述したように、Poolの方法自体には、オブジェクトの作成を避けるためだけに使用しないことを意味するプロセスがあります.