Утилитный класс Java Arrays
Используйте класс java.util.Arrays для сортировки, поиска, заполнения, сравнения и преобразования массивов в Java.
java.util.Arrays — это набор вспомогательных методов для работы с массивами из стандартной библиотеки. Это final-класс, содержащий только static-методы — вы никогда не создаёте его экземпляр, а просто вызываете методы напрямую: Arrays.sort(...), Arrays.toString(...) и так далее. Зная, что в нём есть, вы сможете писать гораздо более компактный код для работы с массивами.
Эта глава — экскурсия по классу. Сортировка и копирование рассматриваются в отдельных главах; здесь мы сосредоточимся на остальном.
Импорт
import java.util.Arrays;Почти все примеры ниже предполагают наличие этого импорта.
toString и deepToString
Превращают массив в читаемую строку. toString работает с одномерными массивами:
int[] data = {3, 1, 4};
String s = Arrays.toString(data); // "[3, 1, 4]"deepToString рекурсивно форматирует вложенные массивы:
int[][] grid = {{1, 2}, {3, 4}};
String s = Arrays.deepToString(grid); // "[[1, 2], [3, 4]]"Оба метода работают как с примитивными типами элементов, так и с объектами.
equals и deepEquals
== сравнивает ссылки на массивы. Чтобы сравнить содержимое:
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
boolean same = Arrays.equals(a, b); // trueДля вложенных массивов используйте deepEquals:
int[][] g1 = {{1, 2}, {3, 4}};
int[][] g2 = {{1, 2}, {3, 4}};
boolean same = Arrays.deepEquals(g1, g2); // trueОба метода считают null == null равным true.
hashCode и deepHashCode
Хеши, основанные на содержимом, полезны, когда класс оборачивает массив и требует реализации equals/hashCode:
int[] data = {1, 2, 3};
int h = Arrays.hashCode(data);Если вы переопределяете equals с использованием Arrays.equals, то должны переопределить hashCode с использованием Arrays.hashCode, чтобы соблюсти контракт.
fill
Установить все элементы в заданное значение или заполнить диапазон:
int[] data = new int[5];
Arrays.fill(data, 7); // {7, 7, 7, 7, 7}
Arrays.fill(data, 1, 4, 0); // zero indexes 1..3sort и parallelSort
Сортировка на месте по возрастанию:
int[] data = {3, 1, 4, 1, 5};
Arrays.sort(data); // {1, 1, 3, 4, 5}Для очень больших массивов можно использовать parallelSort, чтобы распределить работу по нескольким ядрам. Подробнее о сортировке — примитивы, объекты, произвольный порядок — рассказано в главе Сортировка массивов.
binarySearch
Найти элемент в отсортированном массиве за O(log n):
int[] sorted = {1, 3, 5, 7, 9};
int idx = Arrays.binarySearch(sorted, 5); // 2
int miss = Arrays.binarySearch(sorted, 6); // negative — encodes insertion pointЕсли элемент не найден, возвращаемое значение равно -(insertionPoint) - 1. Таким образом, miss == -4 означает, что 6 должно стоять на индексе 3. Если входной массив не отсортирован, результат не определён — сначала отсортируйте.
copyOf и copyOfRange
Возвращают новый массив, копируя значения из существующего:
int[] data = {1, 2, 3, 4, 5};
int[] all = Arrays.copyOf(data, data.length); // exact copy
int[] grown = Arrays.copyOf(data, 8); // padded with zeros
int[] slice = Arrays.copyOfRange(data, 1, 4); // {2, 3, 4}Подробнее об этом рассказано в главе Копирование массивов.
asList
Обернуть массив ссылочных типов в List фиксированного размера:
String[] arr = {"a", "b", "c"};
List<String> list = Arrays.asList(arr);Список опирается на массив — list.set(0, "z") изменяет и arr[0]. Размер фиксирован, поэтому add/remove выбрасывают исключение. С примитивными массивами поведение отличается от ожидаемого: Arrays.asList(new int[]{1, 2, 3}) создаёт List<int[]> длиной один элемент. Для примитивов сначала выполните боксинг через стримы.
stream
Получить стрим из числового или объектного массива:
int[] nums = {3, 1, 4, 1, 5};
int sum = Arrays.stream(nums).sum();
double avg = Arrays.stream(nums).average().orElse(0);Для массивов объектов Arrays.stream(arr) возвращает Stream<T>. Также есть формы с ограничением диапазона — Arrays.stream(arr, from, to).
setAll и parallelSetAll
Заполнить массив с помощью функции от индекса:
int[] squares = new int[6];
Arrays.setAll(squares, i -> i * i);
// {0, 1, 4, 9, 16, 25}Используйте setAll, когда хотите получить производную последовательность, а цикл for был бы лишним.
compare и mismatch (Java 9+)
Arrays.compare(a, b) возвращает отрицательное, нулевое или положительное число — лексикографический порядок по элементам:
int[] a = {1, 2, 3};
int[] b = {1, 2, 4};
int cmp = Arrays.compare(a, b); // negative — a is smallerArrays.mismatch(a, b) возвращает индекс первого отличающегося элемента или -1, если массивы равны:
int diff = Arrays.mismatch(a, b); // 2Если один массив является собственным префиксом другого, более короткий считается «меньшим» по compare, а mismatch возвращает длину более короткого массива:
int[] s = {1, 2};
int[] l = {1, 2, 3};
Arrays.compare(s, l); // negative — s is a prefix, so it sorts first
Arrays.mismatch(s, l); // 2 — they agree up to index 2, then s runs outЭти методы удобны, когда нужен порядок или информация о месте расхождения без написания цикла вручную.
Распространённые ловушки
Несколько подводных камней встречаются достаточно часто, чтобы перечислить их в одном месте:
==— не сравнение содержимого.a == bравноtrueтолько тогда, когда оба имени указывают на один и тот же объект-массив. ИспользуйтеArrays.equals(илиArrays.deepEqualsдля вложенных массивов) для сравнения содержимого.toStringповерхностный.Arrays.toString(grid)наint[][]выведет что-то вроде[[I@1b6d3586, ...]— внутренние массивы используют свой стандартныйObject.toString. ИспользуйтеArrays.deepToString, когда массив содержит другие массивы.asListс примитивным массивом удивляет.Arrays.asList(new int[]{1, 2, 3})— это одноэлементныйList<int[]>, а неList<Integer>длиной три, потому чтоint[]является единым объектом. ИспользуйтеArrays.stream(arr).boxed().toList()(Java 16+), чтобы получить нужный список.asListимеет фиксированный размер. Это представление исходного массива, поэтомуsetработает, ноaddиremoveвыбрасываютUnsupportedOperationException. Оберните вnew ArrayList<>(Arrays.asList(...)), если нужна возможность добавления элементов.binarySearchтребует отсортированного массива. На неотсортированных данных результат не определён — исключение не будет выброшено, просто вернётся неверный индекс. Сначала отсортируйте.
Практический пример
Приведённый ниже пример объединяет большинство методов. Запустите его и сравните вывод с комментариями выше — binarySearch возвращает 5 для значения 5, отрицательный результат для отсутствующего элемента и список [red, green, blue] из asList:
Что дальше
Мы рассмотрели Arrays.sort лишь вскользь. Следующая глава, Сортировка массивов, подробно разбирает, как работает сортировка для примитивов и объектов, по возрастанию и убыванию, а также как задавать собственный порядок с помощью Comparator.