И снова привет! :) На прошлом занятии мы познакомились с такой структурой данных как массив (Java array), научились создавать массивы, наполнять данными, а также узнали, как они хранятся в памяти. Коротко: класс Arrays (java.util.Arrays) содержит готовые методы для типовых операций с массивами: сортировки (sort), вывода на экран (toString), копирования (copyOf, copyOfRange) и сравнения по содержимому (equals). Он избавляет от написания ручных циклов для рутинных задач. Сегодня мы рассмотрим некоторые задачи и примеры работы с массивами, которые часто будут встречаться тебе в реальной работе.

Кратко

  • Класс Arrays (java.util.Arrays) содержит готовые методы для типовых операций с массивами.
  • Arrays.sort() сортирует массив, Arrays.toString() выводит его в читаемом виде.
  • Arrays.copyOf() копирует массив (целиком или первые N элементов), Arrays.copyOfRange() копирует часть по диапазону.
  • Arrays.equals() сравнивает массивы по содержимому (обычный == и Object.equals() сравнивают ссылки).
  • Для двумерных массивов есть Arrays.deepEquals() и Arrays.deepToString().
  • Главная идея: не изобретать велосипед, а использовать готовые методы вместо ручных циклов.
Например, представь себе такую ситуацию: у нас есть массив из 10 чисел, записанных в случайном порядке.

//array Java, example
int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};
Наша задача состоит в том, чтобы отсортировать этот массив по возрастанию: от меньших чисел к большим. В итоге он должен выглядеть так:

[-234, -2, 16, 26, 35, 43, 80, 92, 99, 167]
Как нам это сделать? Задача нетривиальная, такого мы еще не делали :/ Есть какие-то идеи? Попробуй предположить. Вот что, например, мы можем сделать:
  1. Пройтись по всем элементам массива. Сравнивать каждый элемент со следующим ([0] с [1], [1] с [2], [2] с [3] и т.д.). Если текущий элемент массива больше следующего, меняем их местами и переходим к следующему элементу. Если нет, оставляем как есть и идем дальше.
  2. Таким образом, после первого прохождения по элементам массива самое большое значение (167) гарантированно будет в последней ячейке.
  3. Теперь снова пройдем по всем элементам массива начиная с элемента с индексом [0], но до предпоследнего элемента (самое большое число уже на своем месте) и сделаем такие же сравнения и замены местами. В конце в предпоследней ячейке у нас окажется второе самое большое значение (99).
  4. Повторим эту работу столько раз, сколько у нас в массиве элементов минус один.
Пузырьковая сортировка массива: сравнение и обмен соседних элементовИдею мы придумали, осталось только написать код. Выглядеть он будет так:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};

       for (int i = numbers.length - 1; i > 0; i--) {
           for (int j = 0; j < i; j++) {
           /*Сравниваем элементы попарно,
             если они имеют неправильный порядок,
             то меняем местами*/
               if (numbers[j] > numbers[j + 1]) {
                   int tmp = numbers[j];
                   numbers[j] = numbers[j + 1];
                   numbers[j + 1] = tmp;
               }
           }
       }

   }
}
Эээ… Выглядит несколько сложновато -_- Даже если общий принцип работы понятен, приходится писать довольно много кода, чтобы решить такую несложную с виду задачу. Окей, может мы просто переоценили себя? Наверное, задача, которую мы взяли, пока слишком сложна для нас. Давай попробуем сделать что попроще. Например, возьмем тот же массив чисел.

int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};
Наша задача это скопировать его содержимое в другой массив.

int [] numbersCopy = new int[10];
Подумай, как бы ты это сделал, используя те знания о массивах, которые у тебя уже есть? Можно, например, пройтись в цикле по массиву numbers и по очереди записывать его элементы в numbersCopy:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};

       int [] numbersCopy = new int[10];

       for (int i = 0; i < numbers.length; i++) {

           numbersCopy[i] = numbers[i];
       }

   }
}
Ну-у-у, тут мы более-менее справились! Задача вроде как решена, хоть опять же: если ее нужно будет выполнять часто, в коде будет куча одинаковых циклов. На самом деле, эти и другие задачи уже давно решены создателями Java, и нам не нужно "изобретать велосипед" и писать какой-то код собственного решения.

Класс Java Arrays

Решать типовые задачи при работе с массивами тебе поможет специальный класс Java, Arrays. В этот класс были добавлены методы для решения самых распространенных задач, с которыми сталкиваются Java-программисты в работе. Например, задача по сортировке массива, для которой мы сами пытались придумать решения, решается в одну строку:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};

       Arrays.sort(numbers);

       System.out.println(Arrays.toString(numbers));

   }
}
Метод Arrays.sort() выполняет сортировку массива. Причем заложенный в него алгоритм делает это намного эффективнее того кода, который написали мы. Вывод на консоль:

[-234, -2, 16, 26, 35, 43, 80, 92, 99, 167]
Обрати внимание: для преобразования массива в строку мы использовали еще один метод класса Arrays, Arrays.toString(). Сами по себе массивы в Java не переопределяют метод toString(). Поэтому если ты напишешь просто

System.out.println(numbers.toString());
будет вызван метод toString() класса Object. В случае с массивами вывод будет примерно такой:

[I@4554617c
Не будем сейчас подробно разбираться, почему вывод именно такой, главное это явно не то, что нам нужно. А вот Arrays.toString() сделал то, что мы и хотели. Кстати, наша задача с копированием тоже легко решается в классе Arrays:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};

       int [] numbersCopy = Arrays.copyOf(numbers, numbers.length);
       System.out.println(Arrays.toString(numbersCopy));

   }
}
В метод Arrays.copyOf() мы передаем наш оригинальный массив (из которого надо скопировать значения) и длину нового массива, в который мы копируем данные. В данном случае в качестве длины мы указали numbers.length, т.к. хотим скопировать массив целиком. Если же мы хотим скопировать только несколько первых элементов, можно указать длину для нового массива меньше:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};

       int [] numbersCopy = Arrays.copyOf(numbers, 4);
       System.out.println(Arrays.toString(numbersCopy));

   }
}
Здесь мы указали длину нового массива, равного 4. Соответственно, только 4 первых элемента numbers будут скопированы в новый массив. Вывод в консоль:

[167, -2, 16, 99]
Кстати, если нужно скопировать часть массива, но не с начала, а "из середины", Arrays позволяет сделать и это:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {167, -2, 16, 99, 26, 92, 43, -234, 35, 80};

       int [] numbersCopy = Arrays.copyOfRange(numbers, 2,6);
       System.out.println(Arrays.toString(numbersCopy));

   }
}
Вывод:

[16, 99, 26, 92]
В новый массив были скопированы числа из ячеек со второй (включительно) по шестую (не включительно). Кроме того, нам может понадобиться сравнить два массива между собой. Так же, как с методом toString(), сами по себе массивы не переопределяют метод equals(). Поэтому если мы попробуем сравнить их так:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {1, 2, 3};
       int[] numbers2 = {1, 2, 3};

       System.out.println(numbers.equals(numbers2));
   }
}
получим результат false. Ведь будет вызван метод Object.equals(), который сравнивает ссылки. А они, естественно, разные! Подробнее про сравнение объектов по содержимому и по ссылке мы разбирали в статье про методы equals и hashCode. Но нам-то надо сравнить содержимое массивов, а не ссылки. Класс Arrays содержит переопределенный метод equals(), который делает ровно то, что нам нужно:

public class Main {

   public static void main(String[] args) {

       int[] numbers = {1, 2, 3};
       int[] numbers2 = {1, 2, 3};

       System.out.println(Arrays.equals(numbers, numbers2));
   }
}
Вывод:

true
Кстати, класс Arrays успешно работает не только с обычными массивами, но и с двумерными:

public class Main {

   public static void main(String[] args) {

       int[][] numbers = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

       int[][] numbersCopy = Arrays.copyOf(numbers, numbers.length);

       System.out.println("Равны ли эти двумерные массивы между собой?");
       System.out.println(Arrays.deepEquals(numbers, numbersCopy));

       System.out.println(Arrays.deepToString(numbersCopy));
   }
}
Вывод:

Равны ли эти двумерные массивы между собой?
true
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Как видишь, метод Arrays.copyOf() справился с копированием и двумерного массива. Обрати внимание, что в таком случае при копировании двумерного массива происходит так называемое "поверхностное копирование". А для сравнения двумерных массивов и их вывода на консоль предусмотрены специальные методы, deepEquals и deepToString();

Основные методы класса Arrays

Соберем разобранные методы в одну таблицу:
МетодЧто делает
Arrays.sort(array)сортирует массив по возрастанию
Arrays.toString(array)преобразует массив в читаемую строку
Arrays.copyOf(array, length)копирует массив (можно задать другую длину)
Arrays.copyOfRange(array, from, to)копирует часть массива (from включительно, to не включительно)
Arrays.equals(a, b)сравнивает два массива по содержимому
Arrays.deepEquals(a, b)сравнивает многомерные массивы по содержимому
Arrays.deepToString(array)выводит многомерный массив в читаемом виде
В будущем ты еще не раз увидишь (и порадуешься этому), что создатели Java предусмотрели очень много типовых ситуаций, с которыми сталкиваются программисты при работе, и реализовали в языке готовые решения для них. Использовать эти решения гораздо проще и удобнее, чем изобретать велосипеды, верно? :) Обязательно почитай документацию класса Arrays на сайте Oracle. Удачи в обучении!

Читайте также

  • Массивы в Java: что такое массив, как его создать и обращаться к элементам.
  • Класс ArrayList: динамический список, который в отличие от массива расширяется автоматически.
  • Методы equals и hashCode: почему == сравнивает ссылки, а не содержимое.

Вопросы и ответы

Что такое класс Arrays в Java?

Это служебный класс java.util.Arrays с готовыми статическими методами для типовых операций с массивами: сортировки, копирования, сравнения и преобразования в строку.

Как отсортировать массив в Java?

Одной строкой: Arrays.sort(numbers). Метод сортирует по возрастанию и работает эффективнее, чем самописный цикл.

Как вывести массив на экран?

Через Arrays.toString(array). Обычный System.out.println(array) выведет служебную строку с хеш-кодом, потому что массивы не переопределяют toString().

Как скопировать массив?

Arrays.copyOf(array, length) копирует массив целиком или первые length элементов, а Arrays.copyOfRange(array, from, to) копирует часть по диапазону.

Как сравнить два массива по содержимому?

Через Arrays.equals(a, b). Оператор == и array.equals() сравнивают ссылки, а не содержимое, поэтому для одинаковых по данным массивов вернут false.

Как работать с двумерными массивами?

Для сравнения и вывода многомерных массивов используют Arrays.deepEquals() и Arrays.deepToString(), которые заходят вглубь вложенных массивов.