Должен ли я использовать итератор или forloop для итерации?

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

Только если вам нужно вытащить это из списка? Или, если вы берете одну вещь из списка и вынуждены делать это в течение неизмеримого времени? Я не смог найти это в Google или в стеке, пожалуйста, помогите мне.

Я не говорю конкретно о расширенном цикле for (для каждого цикла).

Я также понимаю, что циклы foreach превосходны по производительности, но это больше вопрос "почему он существует"?

РЕДАКТИРОВАТЬ: понял, что я говорил только о коллекциях, а не массивы, а. Foreach петли не имеют ограничений в этой ситуации.

5 ответов

Решение

foreach эквивалентно итератору - это синтаксический сахар для того же. Поэтому вы всегда должны выбирать foreach через итератор, когда вы можете, просто потому, что это удобно и приводит к более лаконичному коду.

Я написал об этом в другом ответе: https://stackru.com/questions/22110482/uses-and-syntax-for-for-each-loop-in-java/22110517

Как заявляет @RonnyShapiro, бывают ситуации, когда вам нужно использовать итератор, но во многих случаях foreach должно хватить. Обратите внимание, что foreach это не нормально for петля. Нормальный for Цикл необходим, когда требуется доступ к индексу. Хотя вы можете вручную создать отдельную переменную индекса с помощью foreach это не идеально, с точки зрения переменной области.

Вот еще немного информации: что является более эффективным: цикл для каждого или итератор?

При доступе к коллекциям foreach значительно быстрее, чем основной for доступ к массиву цикла. Однако при доступе к массивам - по крайней мере с массивами примитивов и оболочек - доступ через индексы намного быстрее. Увидеть ниже.


Индексы на 23-40 процентов быстрее, чем итераторы при доступе int или же Integer массивы. Вот вывод из приведенного ниже класса тестирования, который суммирует числа в массиве primitive-int из 100 элементов (A - итератор, B - индекс):

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 358,597,622 nanoseconds
Test B: 269,167,681 nanoseconds
B faster by 89,429,941 nanoseconds (24.438799231635727% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 377,461,823 nanoseconds
Test B: 278,694,271 nanoseconds
B faster by 98,767,552 nanoseconds (25.666236154695838% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 288,953,495 nanoseconds
Test B: 207,050,523 nanoseconds
B faster by 81,902,972 nanoseconds (27.844689860906513% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,373,765 nanoseconds
Test B: 283,813,875 nanoseconds
B faster by 91,559,890 nanoseconds (23.891659337194227% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,790,818 nanoseconds
Test B: 220,770,915 nanoseconds
B faster by 155,019,903 nanoseconds (40.75164734599769% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 326,373,762 nanoseconds
Test B: 202,555,566 nanoseconds
B faster by 123,818,196 nanoseconds (37.437545972215744% faster)

Полный класс тестирования:

   import  java.text.NumberFormat;
   import  java.util.Locale;
/**
   <P>{@code java TimeIteratorVsIndexIntArray 1000000}</P>

   @see  <CODE><A HREF="https://stackru.com/questions/180158/how-do-i-time-a-methods-execution-in-java">https://stackru.com/questions/180158/how-do-i-time-a-methods-execution-in-java</A></CODE>
 **/
public class TimeIteratorVsIndexIntArray  {
   public static final NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
   public static final void main(String[] tryCount_inParamIdx0)  {
      int testCount;
      //Get try-count from command-line parameter
         try  {
            testCount = Integer.parseInt(tryCount_inParamIdx0[0]);
         }  catch(ArrayIndexOutOfBoundsException | NumberFormatException x)  {
            throw  new IllegalArgumentException("Missing or invalid command line parameter: The number of testCount for each test. " + x);
         }

      //Test proper...START
         int[] intArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100};

         long lStart = System.nanoTime();
            for(int i = 0; i < testCount; i++)  {
               testIterator(intArray);
            }
         long lADuration = outputGetNanoDuration("A", lStart);

         lStart = System.nanoTime();
            for(int i = 0; i < testCount; i++)  {
               testFor(intArray);
            }
         long lBDuration = outputGetNanoDuration("B", lStart);

         outputGetABTestNanoDifference(lADuration, lBDuration, "A", "B");
   }
      private static final void testIterator(int[] int_array)  {
         int total = 0;
         for(int i = 0; i < int_array.length; i++)  {
            total += int_array[i];
         }
      }
      private static final void testFor(int[] int_array)  {
         int total = 0;
         for(int i : int_array)  {
            total += i;
         }
      }
      //Test proper...END

//Timer testing utilities...START
   public static final long outputGetNanoDuration(String s_testName, long l_nanoStart)  {
      long lDuration = System.nanoTime() - l_nanoStart;
      System.out.println("Test " + s_testName + ": " + nf.format(lDuration) + " nanoseconds");
      return  lDuration;
   }

   public static final long outputGetABTestNanoDifference(long l_aDuration, long l_bDuration, String s_aTestName, String s_bTestName)  {
      long lDiff = -1;
      double dPct = -1.0;
      String sFaster = null;
      if(l_aDuration > l_bDuration)  {
         lDiff = l_aDuration - l_bDuration;
         dPct = 100.00 - (l_bDuration * 100.0 / l_aDuration + 0.5);
         sFaster = "B";
      }  else  {
         lDiff = l_bDuration - l_aDuration;
         dPct = 100.00 - (l_aDuration * 100.0 / l_bDuration + 0.5);
         sFaster = "A";
      }
      System.out.println(sFaster + " faster by " + nf.format(lDiff) + " nanoseconds (" + dPct + "% faster)");
      return  lDiff;
   }
//Timer testing utilities...END
}

Я также запустил это для Integer Массив и индексы по-прежнему явный победитель, но только на 18-25% быстрее.

Для List из Integers Однако итераторы работают быстрее. Просто измените массив int в приведенном выше коде на

List<Integer> intList = Arrays.asList(new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100});

и внесите необходимые изменения в тест-функцию (int[] в List<Integer>, length в size(), так далее)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,429,929,976 nanoseconds
Test B: 5,262,782,488 nanoseconds
A faster by 1,832,852,512 nanoseconds (34.326681820485675% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,907,391,427 nanoseconds
Test B: 3,957,718,459 nanoseconds
A faster by 1,050,327,032 nanoseconds (26.038700083921256% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,566,004,688 nanoseconds
Test B: 4,221,746,521 nanoseconds
A faster by 1,655,741,833 nanoseconds (38.71935684115413% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,770,945,276 nanoseconds
Test B: 3,829,077,158 nanoseconds
A faster by 1,058,131,882 nanoseconds (27.134122749113843% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,467,474,055 nanoseconds
Test B: 5,183,149,104 nanoseconds
A faster by 1,715,675,049 nanoseconds (32.60101667104192% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,439,983,933 nanoseconds
Test B: 3,509,530,312 nanoseconds
A faster by 69,546,379 nanoseconds (1.4816434912159906% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,451,101,466 nanoseconds
Test B: 5,057,979,210 nanoseconds
A faster by 1,606,877,744 nanoseconds (31.269164666060377% faster)

В одном тесте они почти эквивалентны, но все же итератор побеждает.

Для каждого был добавлен Java 5 для более легкой итерации по коллекциям. Тем не менее, он не заменяет итераторы, поскольку только с помощью итераторов вы можете изменять коллекцию во время итерации по ней (через интерфейс итератора). Попытка добавить \ удалить объект из коллекции в пределах для каждого вызовет исключение ConcurrentModificationException.

Если вы просто читаете значения, foreach, вероятно, лучше.

Ну, Java Language Spec 8 ( http://docs.oracle.com/javase/specs/jls/se8/jls8.pdf), 14.14.2:

Расширенный оператор for эквивалентен основному для оператора формы:

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

Итак, для компилятора это то же самое. Более ранние версии этого стандарта содержат одно и то же описание выражения foreach

Частично это связано с историей развития Java с течением времени. Итераторы были языковой функцией как способ работы с коллекциями объектов начиная с Java 1.2. Java 1.5 добавил итеративный интерфейс и циклы for-each.

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

Обычно Iterator немного быстрее, чем делать цикл for, используя objects.get(i), но разница не оказывает реального влияния на ваш код. Основным преимуществом Iterator является то, что вы можете удалить объект из списка во время его пересечения, вызвав метод remove на итераторе.

Другие вопросы по тегам