2011-02-26 12 views
4

私は興味があります:この2つのループ実装の間には速度とパフォーマンスに違いはありますか? size()メソッドは、要素のグループを扱う配列、コレクション、またはオブジェクトの長さを返します(実際はXOM apiからです)。Java - forループ終了式の違い

実装1:

int size = someArray.size(); 
for (int i = 0; i < size; i++) { 
    // do stuff here 
} 

実装2:それはsize()一度だけ呼び出されますので、第一スニペットを高速に実行するためにバインドされている

for (int i = 0; i < someArray.size(); i++) { 
    // do stuff here 
} 

答えて

3

パフォーマンスの観点からは、ほとんど違いはありません。これは、size()ルックアップがインライン化されるようにループを最適化することができ、パフォーマンスの差がほとんどないためです。

主な違いは、ループ中にサイズが変更された場合です。最初のケースでは、一定の回数だけ反復しようとします。後者の場合、反復回数は最終的なサイズ()に依存します。

1

。 2番目のスニペットはsize()をN回呼び出します。インプラントに応じて。それは重大なペナルティを引き起こす可能性があります。など、コンパイラがメソッドをインライン化するのは難しい見つけおよび/またはsize()方法は、単に非揮発性の変数を返さない場合

私はfor(int i=0, s=someCollection.size(); i<s; i++)

ノートのようにそれを書き換えていると思います:配列はありませんsize()メソッド。

+0

@bestssだから私はそれを一般的に(要素のグループのために)指定しました:) – Jairo

+0

@Jairo、配列とコレクションの間には大きな違いがあります。どのような状況でも配列のサイズを変更することはできません。 'for(int i = 0; i bestsss

+0

@bestsss:確かに、ArrayListは* size()*メソッドを持ち、何とか配列です;) – SyntaxT3rr0r

1

はい、違いがあります。最初のループでは、size()メソッドは1回だけ呼び出されます。 2番目の方法では、各反復で呼び出されます。

繰り返しがコレクションのサイズを変更する場合(これは非常にまれです)、2番目のコレクションが必要です。ほとんどの場合、あなたが最初のものを好むが、サイズ変数の範囲を限定する必要があります

for (int i = 0, size = someArray.size(); i < size; i++) { 
    // ... 
} 

しかし、ほとんどの時間、あなたはとにかくのforeach構文を好む必要があります。その意志

for (Foo foo : collection) { 
    // ... 
} 

をインデックス付きアクセスが最適ではないLinkedListの場合でも、配列やコレクションを効率的に反復処理します。

+0

私の場合は** foreach **を使うことはできないと思う。 XOM APIの要素の機能は、そのようにトラバースすることはできません。 (XOMはJava用のXML処理ライブラリです) – Jairo

+1

サイズが反復処理中に変わる場合は、重大な深刻な設計/同期の問題が考えられます。さらに、このようなループでは、get(i)*が存在する可能性は非常に高いですし、サイズが変更された場合、サイズを変更した後* get *を*前に*コードは例外をスローします。 – SyntaxT3rr0r

+0

@ SyntaxT3rr0r:同意します。私は反復(マルチスレッドなし)の中でアイテムをコレクションに追加/削除するループについて考えていました。しかし、私はそれが非常にまれであることに同意します。私は私の答えをより明確に編集します。 –

0

最近、JVMの最適化は非常に積極的です。

第2の形式を使用してください。読みやすく、高速である可能性が高いためです。時期尚早最適化を行う。

スピードを上げる必要がある場合は、常に最初にプロファイルして、推測しないでください。

ローカル変数のsize()をキャッシングすることで、あなたのアプリケーションに大きなメリットがもたらされる可能性は非常に低いです。そうであれば、巨大なデータセットに対して簡単な操作を行う必要があります。その場合、ArrayListを使用しないでください。

0

は、多分この構文ことに注意することは価値がある:

for (String s : getStringsList()) { 
    //... 
} 

は一度だけgetStringsList()を呼び出した後、舞台裏イテレータ上で動作します。したがって、長時間の操作を実行するか、getStringsList()の内部の状態を変更することは安全です。

+0

*長時間の操作を実行したり、getStringsList()内で状態を変更したりするのは安全です。* ConcurrentModificationExceptionが発生した場合(erm stack) – bestsss

+0

私はあまり理解していません。私が意味することは、 'getStringsList()'はループが始まる前に一度だけ呼び出されるので、(DAOなどの)高価なメソッドである可能性があるということです。その後、forループは、返されたリスト、またはより正確にはイテレータで動作します。 'ConcurrentModificationException'の場所はどこですか?私はgetStringsList()は返されたリストへの参照を保持していないと仮定します。 –

0

メソッド呼び出し、変数への値の代入、または条件のテストのように、ループの外側で実行できるものは、常に避けてください。

メソッド呼び出しは、呼び出しのない同等コードよりもコストがかかり、メソッド呼び出しを何度も繰り返すことで、アプリケーションにオーバーヘッドを追加するだけです。

コードの書き換えが必要な場合でも、ループからメソッド呼び出しを移動します。

利点: -

コンパイラはそれを最適化していない限り、ループ条件は、ループ上で反復ごとに計算されます。

条件値が変更されない場合、メソッド呼び出しがループ外に移動されると、コードはより速く実行されます。

注: -

方法は、ループの前に一時変数にその値を格納し、その後、ループ中に変更されない値を返す場合。

したがって、その値はループ外の一時変数サイズに格納され、ループ終了条件として使用されます。

関連する問題