Java for-each on getter
If javac do what I think, the following lines would yield the same performance:
for (Object o: getObjects()) {}
List<Object> os = getObjects(); for (Object o: os) {}
Is it so or not? Or is it perhaps implementation-specific? If so: an开发者_C百科ybody know about GWT?
From the Java Language Specifications:
14.14.2 The enhanced for statement
The enhanced for statement has the form:
EnhancedForStatement: for ( VariableModifiersopt Type Identifier: Expression) StatementThe Expression must either have type
Iterableor else it must be of an array type (§10.1), or a compile-time error occurs.The scope of a local variable declared in the FormalParameter part of an enhanced
forstatement (§14.14) is the contained StatementThe meaning of the enhanced
forstatement is given by translation into a basicforstatement.If the type of
Expressionis a subtype ofIterable, then letIbe the type of the expression Expression.iterator(). The enhancedforstatement is equivalent to a basicforstatement of the form:for (I #i = Expression.iterator(); #i.hasNext(); ) { VariableModifiersopt Type Identifier = #i.next(); Statement }Where
#iis a compiler-generated identifier that is distinct from any other identifiers (compiler-generated or otherwise) that are in scope (§6.3) at the point where the enhanced for statement occurs.
As you can see, Expression is mentioned only in the first part of the for loop expression and is thus only evaluated once. So your two lines would yield the same performance.
The performance will be identical.
The Java compiler turns for-each loops into a loop around an Iterator object by calling the iterator() method on the object that you loop over.
Therefore, the actual list instance is only used once. (To call iterator())
These answers all seem correct from a pure Java perspective. Furthermore, if it can, the GWT compiler will actually rewrite the enhanced for loop further, into a regular for loop before it generates the JavaScript. So it will actually end up looking something like:
for (int i = 0; i < getObjects().size(); i++) {
Object o = getObjects().get(i);
// ...
}
The reason? If the List iterator object is never referenced, it can be declared as dead code and won't be rewritten in JavaScript, resulting in a smaller download size. This optimization should have no effect whatsoever on the actual execution of your code.
See Optimizing apps with the GWT compiler, from this year's Google I/O, for more details about other crazy things the GWT compiler does to reduce JS size.
From a practical point of view you can inspect both bytecodes and compare them:
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
They are equal, the only difference is that your second snippet has two separate parts to load the List and then obtain the iterator. This will also consume more locals of the class, infact it has also an ALOAD and an ASTORE more, it is used to store getObjects result through the two lines of code while in your first snippet it directly uses it..
There's no difference. The foreach construct just fetches an Iterator from the object. That's why it has to implement the Iterable interface.
加载中,请稍侯......
精彩评论