Самый быстрый способ перебора массива в Java:Переменная цикла и расширенный оператор for [дубликат]

StackOverflow https://stackoverflow.com/questions/1006395

  •  06-07-2019
  •  | 
  •  

Вопрос

На этот вопрос уже есть ответ здесь:

В Java быстрее ли перебирать массив по старинке?

for (int i = 0; i < a.length; i++)
    f(a[i]);

Или, используя более краткую форму,

for (Foo foo : a)
    f(foo);

Для ArrayList ответ тот же?

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

Это было полезно?

Решение

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

Например, рассмотрим этот код:

public static void main(String[] args)
{
    for (String x : args)
    {
        System.out.println(x);
    }
}

При декомпиляции с помощью javap -c Test мы получаем (для main метод):

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return

Теперь измените его, чтобы использовать явный доступ к массиву:

public static void main(String[] args)
{
    for (int i = 0; i < args.length; i++)
    {
        System.out.println(args[i]);
    }
}

Это декомпилируется в:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   aload_0
   4:   arraylength
   5:   if_icmpge   23
   8:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  aload_0
   12:  iload_1
   13:  aaload
   14:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   17:  iinc    1, 1
   20:  goto    2
   23:  return

В расширенном цикле for немного больше кода настройки, но по сути они делают то же самое.Никакие итераторы не задействованы.Более того, я ожидаю, что они получат JIT-компиляцию еще более похожего кода.

Предположение:если вы действительно думаете, что это может иметь существенное значение (а это будет только всегда do, если тело цикла совсем крошечное), то вам следует сравнить его с вашим реальным приложением.Это единственная ситуация, которая имеет значение.

Другие советы

Это относится непосредственно к сфере микрооптимизация.Это действительно не имеет значения.Стилистически я всегда предпочитаю второй вариант, потому что он более краток, если только вам не нужен счетчик циклов для чего-то еще.И это гораздо важнее, чем такая микрооптимизация:читабельность.

При этом для ArrayList большой разницы не будет, но LinkedList будет намного эффективнее со вторым.

Измерьте это.Ответ на все вопросы производительности может зависеть от версии виртуальной машины, процессора, скорости памяти, кешей и т. д.Поэтому вам нужно измерить его для вашей конкретной платформы.

Лично я бы предпочел второй вариант, потому что цель более ясна.Если производительность станет проблемой, я в любом случае смогу оптимизировать ее позже — если этот код действительно важен для производительности всего приложения.

Для LinkedList:

for(ClassOfElement element : listOfElements) {
  System.out.println(element.getValue());
}

Ранее был ответ:

Есть ли разница в производительности между циклом for и циклом for-each?

В массиве или коллекции RandomAccess вы можете немного увеличить скорость, выполнив следующие действия:

List<Object> list = new ArrayList<Object>();

for (int i=0, d=list.size(); i<d; i++) {
    something(list.get(i));
}

Но в целом я бы не волновался.Подобные оптимизации не изменят ваш код более чем на 0,1%.Попробуйте вызвать Java с помощью -профессор чтобы увидеть, где ваш код на самом деле тратит свое время.

Еще быстрее — использовать ParallelArray платформы fork-join (если у вас достаточно большой набор данных).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top