2014-01-31 4 views
7

Я часто встречаю случаи, когда я хочу использовать закодированный цикл for для некоторой коллекции или массива, которые я получаю от некоторого объекта.Enhanced for loop

например.

items = basket.getItems(); 
for (int item : items) { 
    // Do something 
} 

Другой способ сделать это:

for (int item : basket.getItems()) { 
    // Do something 
} 

Второй является более компактным и улучшает читаемость на мой взгляд, особенно когда переменная item не будет использоваться в любом другом месте.

Я хотел бы знать, влияет ли получатель в выражении for на производительность. Будет ли он оптимизирован для чего-то похожего на 1-й? Или он будет получать доступ к геттеру каждый раз? Конечно, getItems() может сделать что-то довольно медленное (например, доступ к сети и т. Д.)

Вопрос аналогичен некоторым другим, но относится к получателю самого массива collection/array, а не к его размеру. Однако в конечном итоге это может быть один и тот же случай.

+0

Почему бы вам не проверить его? Просто поставьте 'println' в этот getter. –

+0

Тестирование в моей конкретной конфигурации и для конкретного объекта не приведет к правильному ответу, так как было бы неправильно обобщать мои конкретные результаты. – LyK

+0

@tobias_k, хорошее мышление. но может ли быть (теоретически), что компилятор не заменит вызов 'basket.getItems()' ссылкой, когда метод фактически делает что-то большее, чем просто возвращает ссылку? – GameDroids

ответ

9

Метод getItems() будет вызываться только один раз в обоих случаях. Между ними нет никакой разницы, кроме одной, использующей дополнительную локальную переменную, которую вы могли бы использовать где-то еще.

Как вы можете прочитать в JLS 14.14.2, улучшенный цикл переводится примерно в этот традиционный цикл:

for (I #i = Expression.iterator(); #i.hasNext();) { 
    TargetType Identifier = (TargetType) #i.next(); 
    Statement 
} 

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

Отсюда ясно, что Expression оценивается только один раз.

0

Да, второй улучшает читаемость кода.

Если вы получаете объекты из сети, а затем итерации по нему в цикле for, то я думаю, что да, это влияет на производительность, потому что вы каждый раз делаете доступ к сети, и это неэффективно, а также для небольшого/одиночного объекта сетевой доступ не рекомендуется. вместо этого получить его один раз из сетевого доступа, сохранить его локально и перебрать по нему.

Таким образом, 1-й вариант - это оптимизированная по производительности в случае сетевого доступа , если ваш объект является локальным, тогда любой метод будет работать. там не будет большой разницы в производительности.

2

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

package test; 

public class Main { 

     static class Basket { 
      int[] items = { 1, 2, 3 }; 

     public int[] getItems() { 
       System.out.println("in getItems()"); 
      return items; 
     } 

    } 

    public static void main(String[] args) { 
     Basket basket = new Basket(); 
     for (int item : basket.getItems()) { 
      System.out.println(item); 
     } 

    } 
} 
0

Я не думаю, что он будет называть геттер каждый раз. Если это произойдет, он будет получать новый список каждый раз, и Loop не будет ломаться. Вы можете проверить это, поставив простой метод getter Sysout. Производительность будет одинаковой в этих двух случаях.

Смежные вопросы