Java для каждого на добытчике - PullRequest
5 голосов
/ 04 июня 2010

Если javac сделает то, что я думаю, следующие строки приведут к той же производительности:

for (Object o: getObjects()) {}
List<Object> os = getObjects(); for (Object o: os) {}

Это так или нет? Или это, возможно, зависит от реализации? Если так: кто-нибудь знает о GWT?

Ответы [ 5 ]

7 голосов
/ 04 июня 2010

Из спецификации языка Java:

14.14.2 Усовершенствованный оператор

Усовершенствованный оператор for имеет форма:

EnhancedForStatement:
        for ( VariableModifiersopt Type Identifier: Expression) Statement

Выражение должно иметь тип Iterable или это должно быть тип массива (§10.1) или время компиляции возникает ошибка.

Область локальной переменной объявлена в части FormalParameter расширенный оператор for (§14.14) Содержимое заявление

Значение расширенного for заявление дается переводом на базовое for утверждение.

Если тип Expression является подтип Iterable, тогда пусть I будет тип выражения Expression. iterator(). Расширенный оператор for эквивалентен к основному for утверждению форма:

for (I #i = Expression.iterator(); #i.hasNext(); ) {

        VariableModifiersopt Type Identifier = #i.next();
   Statement
}

Где #i - генерируется компилятором идентификатор, отличный от любого другие идентификаторы (генерируемые компилятором или иным образом), которые находятся в сфере действия (§6.3) в точке, где улучшено для заявление происходит.

Как видите, Expression упоминается только в первой части выражения цикла for и, таким образом, оценивается только один раз. Таким образом, ваши две строки будут иметь одинаковую производительность.

7 голосов
/ 04 июня 2010

Производительность будет идентичной.

Компилятор Java превращает цикл for-each в цикл вокруг объекта Iterator, вызывая метод iterator() для объекта, над которым вы зацикливаетесь. Следовательно, фактический экземпляр списка используется только один раз. (Звонить iterator())

5 голосов
/ 04 июня 2010

Все эти ответы кажутся правильными с точки зрения чистой 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.

3 голосов
/ 04 июня 2010

С практической точки зрения вы можете проверить оба байт-кода и сравнить их:

 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

Они равны, единственное отличие состоит в том, что ваш второй фрагмент имеет две отдельные части для загрузки List и получения итератора. Это также потребляет больше локальных классов, в действительности у него также ALOAD и ASTORE больше, оно используется для хранения getObjects результата через две строки кода, в то время как в вашем первом фрагменте он непосредственно использует его. .

2 голосов
/ 04 июня 2010

Нет никакой разницы.Конструкция foreach просто извлекает Iterator из объекта.Вот почему он должен реализовывать интерфейс Iterable.

...