Циклы, массивы и ввод данных

Формы циклов

while (condition) {
    step();
}
 
do {
    step();
} while (condition); // минимум одна итерация
 
for (int i = 0; i < limit; i++) {
    step(i);
}
 
for (int value : values) {
    consume(value);
}

Enhanced for дает значение элемента, а не индекс. Для массива примитивов изменение переменной не меняет массив:

for (int value : values) {
    value *= 2; // values не изменился
}

Для записи нужен индекс. Для коллекций структурное изменение внутри enhanced loop обычно приводит к ConcurrentModificationException; используют Iterator.remove() или подходящий метод коллекции.

break, continue и метки

  • break завершает ближайший цикл;
  • continue начинает следующую итерацию;
  • метка позволяет выйти из внешнего цикла, но часто отдельный метод с return читается проще.
outer:
for (int row = 0; row < matrix.length; row++) {
    for (int col = 0; col < matrix[row].length; col++) {
        if (matrix[row][col] == target) break outer;
    }
}

Инвариант цикла

Для суммирования:

long sum = 0;
for (int i = 0; i < values.length; i++) {
    sum += values[i];
}

Перед итерацией i переменная sum равна сумме диапазона [0, i). Инвариант помогает проверить границы и отсутствие off-by-one.

Ввод массива

Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
int[] values = new int[size];
 
for (int i = 0; i < values.length; i++) {
    values[i] = scanner.nextInt();
}

nextInt() не съедает перевод строки. Если после него вызвать nextLine(), сначала вернется остаток текущей строки:

int count = scanner.nextInt();
scanner.nextLine(); // дочитать конец строки
String title = scanner.nextLine();

Для большого форматированного ввода BufferedReader и ручной разбор обычно быстрее Scanner. Закрытие Scanner закроет и System.in, поэтому в небольшом приложении нужно понимать, кто владеет входным потоком.

Рекурсивные обходы вынесены в Рекурсия.

На собеседовании

  • Чем while отличается от do-while? Второй выполняет тело хотя бы раз.
  • Можно ли enhanced for менять int[] через переменную value? Нет.
  • Что делает continue? Пропускает остаток текущей итерации.
  • Почему nextLine() после nextInt() бывает пустым? Остался перевод строки.
  • Как ловить off-by-one? Полуинтервалы и явный инвариант.