2017-05-11 4 views
1

私はJavaプロジェクトに取り組んでいます。変数はwhileループの内部で何度もローカル変数としてインスタンス化されています。Javaでは、オブジェクトをループで複数回インスタンス化するのは悪い習慣ですか?

while ((inputLine = in.readLine()) != null){ 
    Matcher matcher = pattern.matcher(inputLine); 
    isFound = matcher.find(); 
    if(isFound){ 
     break; 
    } 
} 

ローカル変数マッチャーは、whileループで毎回ループの終了までインスタンス化しています。

これは処理時間が遅くなるのだろうと思いましたか?

+0

ユースケースによって異なります。場合によっては、ループ内で新しいオブジェクトをインスタンス化せずに処理を進めることはできません。 – TheLostMind

+0

ループ内で実際に何もインスタンス化していないことに注意してください。 Matcherオブジェクト参照を宣言して、pattern.matcher()呼び出しから戻り値を受け取るようにしています。 I.あなたが投稿したコードには「新」はありません。 – geneSummons

+1

@geneSummons彼は 'new'キーワードを直接使用しませんが、' Pattern'内の 'matcher'メソッドは'新しいMatcher(this、input) 'を作成して返します。技術的には、そこに新しいインスタンスを作成しています。 – Jimmy

答えて

2

一般に、しばしば、このようなことをする必要があります。もちろん、あなたは自由ではないので、偽の過剰なスタック割り当てを避けたいのですが、ループ内にオブジェクトを作成する必要がある完全に良い状況がたくさんあります。

インスタンス化と宣言の違いもあります。あなたの例では、pattern.matcher(inputLine)がオブジェクトインスタンス化です。そのステートメントだけで新しいMatcherを作成しています。 Matcher matcher = ...があなたの宣言です。ループ内で変数を複数回宣言してもよいかどうかを確認するには、コンテキストにも依存します。通常、これはうまくいき、ループの外側で変数を宣言するほうが実際には好ましいです。なぜなら、そのMatcherのすべてのインスタンスのスコープは(おそらく)ループの1回の反復に限定されるためです。このスコープのメカニズムは、アプリケーションで後でバグを作成するのを避けるのに役立ちます。

0

Matcherオブジェクトを使用する方法は、ループ外でインスタンス化して使用する必要があるようです。

+2

とMatcherオブジェクトはどのようにループ外のinputLineを取得しますか? – toongeorges

+0

@toongeorges理論的には、マッチャーはダミーストリングでインスタンス化できます。ループ内でMatcher#reset(inputLine)を呼び出すだけで十分です。 – Nevay

0

です。

この特定のケースでは、これを実行しても問題ありません。これは、ループの各繰り返しでinputLineが変化しているためです。新しい反復をそれぞれMatcher作成せずにこれを行うことはできません。また、Matcherのコンストラクタはちょうどこれを行うようだ:

Matcher(Pattern parent, CharSequence text) { 
    this.parentPattern = parent; 
    this.text = text; 

    // Allocate state storage 
    int parentGroupCount = Math.max(parent.capturingGroupCount, 10); 
    groups = new int[parentGroupCount * 2]; 
    locals = new int[parent.localCount]; 

    // Put fields into initial states 
    reset(); 
} 

私はそれはたくさんだと言うではないでしょう。

インスタンスを作成できない場合は、インスタンスを作成しないでください。これの良い例は、ループ内の文字列連結です。

例:

String s = ""; 
for(int i = 0 ; i < 100 ; i++) { 
    s += Integer.toString(i); // string is immutable so this creates a new string every time. 
} 

あなたが代わりにStringBuilderを使用する必要があります。

0

ジャワhereでパターンマッチングを行うための規範的なパターンである:あなたがあるとして

  1. は、試験される各入力文字列sのためのパターン
  2. をインスタンス化は、.match(S)を介して整合器Mを作成しますやって
  3. Matcherでm.matches()/ find()メソッドを使って一致をテストします。
0

によって異なります。この特定のケースでは、他の人があなたの質問に対処しています。一般的には、ループ内でオブジェクトをインスタンス化して若い世代のコレクションでクリーンアップする方がよい場合がありますが、常にそうであるとは限りません。 JavaのGCは、短命のオブジェクトに最適化されています。

変数のスコープは状況の論理に合致する必要がありますが、「より良い」というドグマはありません。オブジェクトのようなループの例と同様に、変数をより長生きかもしれない:ここ

Result result = null; 
for (int ix = 0; ix < limit; ++ix) { 
    Result candidate = new Result(); 
    if (condition()) { 
    result = candidate; 
    break; 
    } 
} 
if (result != null) { ... 

は、candidate変数がループの後範囲外です。非nullの値が割り当てられている場合、result変数は元の参照よりも寿命の長いオブジェクトを指します。その他の候補者はすべてGCの資格があります。 (この例は設計されていますが、そのポイントを示すために調整されています)。

例外は、初期化オーバーヘッドが大きく、ループ内で繰り返されない場合です。オブジェクトの構築が大規模で、ループが大規模な作業を繰り返さずにオブジェクト状態の小さな部分のみを変更する場合は、ループ外にオブジェクトを作成することを検討することもできます。

「大量」はどれぐらいですか?それは知るのは難しいです。しかし、オブジェクトの作成はほとんど無料で、若い世代のGCも無料です。死んだオブジェクトは、若いGCのオーバーヘッドには貢献しません。オブジェクトが保護されている場合、GCのオーバーヘッドが増加するため、必要に応じて寿命を短く保つ必要があります。

ライフタイムマネジメントは、Javaプログラミングのダークアーツの1つです。できるだけ早くオブジェクトを投げ捨てることを好むなら、あなたはほとんど間違っていません。この経験則から逸脱するには、さまざまなライフサイクル戦術の違いを測定する必要があります。オブジェクトを長持ちさせるとパフォーマンスが大幅に向上する場合もありますが、それらを勉強すれば、多くの実験と正確なメトリックで結果が達成されています。

関連する問題