Если javac делают то, что я думаю, следующие строки привели бы к той же производительности:
for (Object o: getObjects()) {}
List<Object> os = getObjects(); for (Object o: os) {}
Это так или нет? Или это является, возможно, определенным для реализации? Раз так: кто-либо знает о GWT?
Все эти ответы кажутся правильными с точки зрения чистой Java. Более того, если это возможно, компилятор GWT фактически перепишет расширенный цикл for дальше в обычный цикл for, прежде чем он сгенерирует JavaScript. Так что на самом деле это будет выглядеть примерно так:
for (int i = 0; i < getObjects().size(); i++) {
Object o = getObjects().get(i);
// ...
}
Причина? Если объект List итератора никогда не упоминается, он может быть объявлен как мертвый код и не будет переписан в JavaScript, что приведет к уменьшению размера загрузки. Эта оптимизация никак не должна влиять на фактическое выполнение вашего кода.
См. Оптимизация приложений с помощью компилятора GWT из Google I / O в этом году, чтобы узнать больше о других безумных вещах, которые компилятор GWT делает для уменьшения размера JS.
Производительность будет идентичной.
Компилятор Java превращает циклы for-each в цикл вокруг объекта Iterator
, вызывая метод iterator ()
для объекта, который вы перебираете.
Следовательно, фактический экземпляр списка используется только один раз. (Для вызова итератора ()
)
Нет никакой разницы. Конструкция foreach просто извлекает из объекта Iterator
. Вот почему он должен реализовать интерфейс Iterable
.
С практической точки зрения вы можете проверить оба байт-кода и сравнить их:
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
Они равны, с той лишь разницей, что ваш второй фрагмент состоит из двух отдельных частей для загрузки Перечислите
, а затем получите итератор. Это также потребует больше локальных переменных класса, фактически у него также есть ALOAD
и еще ASTORE
, он используется для хранения результата getObjects
в двух строках кода, а в первом фрагменте он напрямую использует его ..
Из спецификаций языка Java:
14.14.2 Расширенный оператор for
Расширенный оператор for имеет форма:
EnhancedForStatement: for (Идентификатор типа VariableModifiersopt: выражение)
Выражение должно иметь тип
Итерируемый
, иначе он должен иметь тип массива (§10.1) или время компиляции возникает ошибка.Объем объявленной локальной переменной в части FormalParameter расширенный
для
утверждения (§14.14) Содержимое ЗаявлениеЗначение расширенного
для
заявление дается переводом на основной оператордля
.Если тип
Выражение
является подтипIterable
, тогда пустьI
будет тип выражения Выражение.итератор ()
. Расширенный оператордля
эквивалентен к основномудля
утверждению форма:for (I #i = Expression.iterator (); # i.hasNext ();) { Идентификатор типа VariableModifiersopt = # i.next (); Заявление }
Где
#i
- созданный компилятором идентификатор, отличный от любого другие идентификаторы (сгенерированные компилятором или иначе), которые входят в сферу действия (§6.3) в точке, где усилено для заявление происходит.
Как видите, Выражение
упоминается только в первой части выражения цикла for и поэтому вычисляется только один раз. Таким образом, ваши две линии будут давать одинаковую производительность.