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

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

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

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

Я также понимаю, что петли foreach превосходят производительность, но это скорее вопрос "почему он существует".

EDIT: Реализовано, что я говорил только о коллекциях, а не о массивах. В этой ситуации циклы Foreach не имеют ограничений.

Ответ 1

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

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

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

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

При доступе к коллекциям 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://stackoverflow.com/questions/180158/how-do-i-time-a-methods-execution-in-java">https://stackoverflow.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 процентами быстрее.

Однако при a List of Integers итераторы быстрее. Просто измените int-array в приведенном выше коде на

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)

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

Ответ 2

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

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

Ответ 3

Ну, язык Java 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

Ответ 4

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

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

Ответ 5

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