Обход массива и Arrays
Массив редко читают по одному элементу. Обычно нужно что-то сделать со всеми элементами сразу: сложить, напечатать, отсортировать.
Вернёмся к ряду шкафчиков. Чтобы проверить все шкафчики, вы идёте вдоль ряда от первого к последнему и открываете каждый по очереди. Для массива такую прогулку делает цикл: на каждом круге он берёт следующий индекс. Посчитаем сумму баллов:
public class Main {
public static void main(String[] args) {
int[] scores = {90, 75, 60};
int sum = 0;
for (int i = 0; i < scores.length; i++) {
sum = sum + scores[i];
}
System.out.println(sum); // 225
}
}Давайте разберём программу по строкам:
int sum = 0;заводит сумму, пока нулевую.for (int i = 0; i < scores.length; i++)проходит индексы0,1и2: ровно столько кругов, сколько элементов в массиве.sum = sum + scores[i];прибавляет к сумме элемент с текущим индексом.- После цикла
System.out.println(sum)печатает225.
Цикл по индексам
У такого цикла три правила:
- счёт начинается с
0, с первого индекса; - условие —
i < scores.length, строго меньше: последний индекс на единицу меньше длины; - через индекс элементы можно не только читать, но и менять:
scores[i] = scores[i] * 2;удваивает очередной элемент.
С условием i <= scores.length цикл сделает лишний круг. На нём i станет равной 3, и чтение scores[3] бросит исключение ArrayIndexOutOfBoundsException.
Цикл for-each
Когда индекс не нужен, есть запись короче. Цикл for-each по очереди кладёт в переменную каждый элемент массива, от первого до последнего. Та же сумма с ним выглядит так:
int total = 0;
for (int x : scores) {
total = total + x;
}
System.out.println(total); // 225Заголовок for (int x : scores) читается как «для каждого x из scores»:
int x— переменная для очередного элемента, её тип совпадает с типом элементов;- двоеточие отделяет переменную от массива;
scores— массив, который обходит цикл.
Счётчика, условия и шага здесь нет: цикл сам знает, где начало и конец массива. Поэтому выйти за границу в нём нельзя.
Переменная x получает копию элемента, как b в int b = a получает копию числа. Это обычная переменная: её можно изменить, например написать x = 0. Но массив от этого не изменится. Это как переписать число из шкафчика в блокнот: исправление в блокноте не меняет того, что лежит в шкафчике. Поэтому for-each подходит, чтобы читать элементы, а менять их нужно циклом по индексам.
Импорт и класс Arrays
Стандартная библиотека Java — это тысячи готовых классов. Они разложены по пакетам, как книги по полкам: у каждого класса есть полное имя из названия пакета и своего имени. Класс Arrays с инструментами для массивов лежит в пакете java.util, и его полное имя — java.util.Arrays.
Классы System, String и Integer лежат в пакете java.lang. Его Java подключает в каждую программу сама, поэтому до сих пор нам ничего подключать не приходилось. Для класса из другого пакета в начале файла, до public class Main, пишут импорт:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] scores = {90, 75, 60};
System.out.println(Arrays.toString(scores)); // [90, 75, 60]
Arrays.sort(scores);
System.out.println(Arrays.toString(scores)); // [60, 75, 90]
}
}Здесь картинка с полками неточна: импорт не снимает класс с полки и не копирует его код в программу. Он только сообщает компилятору, что короткое имя Arrays означает java.util.Arrays. Без этой строки компилятор не узнает имя Arrays и остановится с ошибкой cannot find symbol — той же, что для необъявленной переменной.
Arrays.toString
Arrays.toString(scores) собирает из элементов строку в квадратных скобках через запятую: [90, 75, 60]. Её удобно печатать, когда нужно увидеть весь массив сразу.
Без этого метода не обойтись. Строка System.out.println(scores) печатает не элементы, а служебную запись вида [I@ с набором цифр и букв. Это обозначение типа и внутренний номер массива, и этот номер может меняться от запуска к запуску.
Arrays.sort
Arrays.sort(scores) сортирует элементы по возрастанию. Метод меняет сам массив, а не создаёт новый, и ничего не возвращает. Поэтому вызов пишут отдельной инструкцией, а результат смотрят через Arrays.toString. Запись System.out.println(Arrays.sort(scores)) не скомпилируется.
Частая ошибка
Хотели удвоить все цены и записали новое значение в переменную for-each:
int[] prices = {10, 20, 30};
for (int p : prices) {
p = p * 2; // ✗
}
System.out.println(Arrays.toString(prices)); // [10, 20, 30]Программа компилируется и печатает [10, 20, 30]: цены не изменились. Каждый круг удваивал копию элемента в переменной p, а массив оставался прежним. Чтобы изменить элементы, нужен цикл по индексам: prices[i] = prices[i] * 2;.
Главное
- Цикл по индексам идёт от
0при условииi < a.length; черезa[i]элементы можно читать и менять. - Цикл for-each
for (int x : a)кладёт вxкопию каждого элемента: запись вxмассив не меняет. - Класс из другого пакета подключают импортом в начале файла:
import java.util.Arrays;. Arrays.toStringпревращает массив в строку[90, 75, 60], аArrays.sortсортирует сам массив по возрастанию.