javacが私が思うことを実行した場合、次の行で同じパフォーマンスが得られます。
for (Object o: getObjects()) {}
List<Object> os = getObjects(); for (Object o: os) {}
そうですか?それとも、おそらく実装固有ですか?もしそうなら:GWTについて知っている人はいますか?
パフォーマンスは同じになります。
Javaコンパイラは、ループするオブジェクトのメソッドをIterator
呼び出すことにより、for-eachループをオブジェクトの周りのループに変換します。
したがって、実際のリストインスタンスは1回だけ使用されます。(呼び出すには)iterator()
iterator()
Java言語仕様から:
14.14.2拡張されたforステートメント
拡張forステートメントの形式は次のとおりです。
EnhancedForStatement: for ( VariableModifiersopt Type Identifier: Expression) Statement
式は型
Iterable
であるか、配列型(§10.1)である必要があります。そうでない場合、コンパイル時エラーが発生します。
for
拡張ステートメント(§14.14)のFormalParameter部分で宣言されたローカル変数のスコープは、含まれているステートメントです。拡張ステートメントの意味は
for
、基本ステートメントへの翻訳によって与えられfor
ます。
Expression
のタイプがのサブタイプである場合、式のタイプとIterable
しI
ます 。iterator()
。拡張ステートメントは、次の形式for
の基本ステートメントと同等です。for
for (I #i = Expression.iterator(); #i.hasNext(); ) { VariableModifiersopt Type Identifier = #i.next(); Statement }
#i
拡張forステートメントが発生する時点でスコープ(§6.3)にある他の識別子(コンパイラー生成またはその他)とは異なるコンパイラー生成識別子はどこにありますか。
ご覧のExpression
とおり、forループ式の最初の部分でのみ言及されているため、一度だけ評価されます。したがって、2つのラインで同じパフォーマンスが得られます。
これらの答えはすべて、純粋なJavaの観点からは正しいように思われます。さらに、可能であれば、GWTコンパイラーは、JavaScriptを生成する前に、拡張されたforループを通常のforループに実際に書き換えます。したがって、実際には次のようになります。
for (int i = 0; i < getObjects().size(); i++) {
Object o = getObjects().get(i);
// ...
}
理由?Listイテレータオブジェクトが参照されない場合、デッドコードとして宣言でき、JavaScriptで書き換えられないため、ダウンロードサイズが小さくなります。この最適化は、コードの実際の実行にはまったく影響しません。
GWTコンパイラがJSサイズを縮小するために行うその他のクレイジーなことの詳細については、今年のGoogle I/Oの「GWTコンパイラを使用したアプリの最適化」を参照してください。
実用的な観点から、両方のバイトコードを検査して比較することができます。
m1()V
L0
ALOAD 0
INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 2
GOTO L1
L2
FRAME FULL [it/funge/Console T java/util/Iterator] []
ALOAD 2
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
ASTORE 1
L1
FRAME SAME
ALOAD 2
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L2
L3
RETURN
m2()V
L0
ALOAD 0
INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
ASTORE 1
L1
ALOAD 1
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 3
GOTO L2
L3
FRAME FULL [it/funge/Console java/util/List T java/util/Iterator] []
ALOAD 3
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
ASTORE 2
L2
FRAME SAME
ALOAD 3
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L3
L4
RETURN
それらは等しく、唯一の違いは、2番目のスニペットがList
イテレータをロードして取得するための2つの別個の部分を持っていることです。これはまた、クラスのより多くのローカルを消費します。実際には、さらに多くのローカルがあり、ALOAD
最初のスニペットでは直接使用しますが、2行のコードを介して結果ASTORE
を格納するために使用されます。getObjects
違いはありません。foreach構造Iterator
は、オブジェクトからをフェッチするだけです。そのため、Iterable
インターフェイスを実装する必要があります。