Массивы в Java: справочное руководство

Массивы в Java: справочное руководство

1. Вступление

В этом руководстве мы углубимся в основную концепцию языка Java - массивы.

Сначала мы увидим, что такое массив, а затем как их использовать; в целом мы расскажем, как:

  • Начните с массивов

  • Чтение и запись элементов массива

  • Цикл над массивом

  • Преобразование массивов в другие объекты, напримерList илиStreams

  • Сортировка, поиск и объединение массивов

2. Что такое массив?

Прежде всего, нам нужно определить, что такое массив? Согласноthe Java documentation, массив равенan object containing a fixed number of values of the same type. Элементы массива индексируются, что означает, что мы можем обращаться к ним с помощью чисел (называемыхindices).

Мы можем рассматривать массив как нумерованный список ячеек, каждая ячейка является переменной, содержащей значение. В Java нумерация начинается с 0.

Существуют массивы примитивных типов и массивы типов объектов. Это означает, что мы можем использовать массивыint, float, boolean, …, а также массивыString, Object и пользовательские типы.

3. Настройка массива

Теперь, когда массивы четко определены, давайте рассмотрим их использование.

Мы рассмотрим множество тем, которые научат нас использовать массивы. Мы изучим некоторые основы, например, как объявлять и инициализировать массив, но мы также затронем более сложные темы, такие как сортировка и поиск массивов.

Начнем с объявления и инициализации.

3.1. декларация

Начнем с декларации. Есть два способа объявить массив в Java:

int[] anArray;

or:

int anOtherArray[];

The former is more widely used than the latter.

3.2. инициализация

Теперь пора посмотреть, как инициализировать массивы. Опять же, есть несколько способов инициализации массива. Здесь мы увидим основные из них, ноthis article подробно описывает инициализацию массивов.

Начнем с простого:

int[] anArray = new int[10];

Используя этот метод, мы инициализировали массив из десяти элементовint. Обратите внимание, что нам нужно указать размер массива.

При использовании этого методаwe initialize each element to its default value, здесь 0.. При инициализации массиваObject элементами по умолчанию являютсяnull.

Теперь мы рассмотрим другой способ, дающий нам возможность устанавливать значения в массив непосредственно при его создании:

int[] anArray = new int[] {1, 2, 3, 4, 5};

Здесь мы инициализировали массив из пяти элементов, содержащий числа от 1 до 5. При использовании этого метода нам не нужно указывать длину массива, это количество элементов, объявленных в фигурных скобках.

4. Доступ к элементам

Давайте теперь посмотрим, как получить доступ к элементам массива. Мы можем достичь этого, требуя положение ячейки массива.

Например, этот небольшой фрагмент кода выведет 10 на консоль:

anArray[0] = 10;
System.out.println(anArray[0]);

Обратите внимание, как мы используем индексы для доступа к ячейкам массива. The number between the brackets is the specific position of the array we want to access.с

При доступе к ячейке, если переданный индекс отрицательный или выходит за пределы последней ячейки, Java выдастArrayIndexOutOfBoundException.

Тогда мы должны быть осторожны,not to use a negative index, or an index greater than or equal to the array size.

5. Итерация по массиву

Доступ к элементам один за другим может быть полезен, но нам может потребоваться перебрать массив. Посмотрим, как нам этого добиться.

Первый способ - использовать циклfor:

int[] anArray = new int[] {1, 2, 3, 4, 5};
for (int i = 0; i < anArray.length; i++) {
    System.out.println(anArray[i]);
}

Это должно вывести номера с 1 по 5 на консоль. As we can see we made use of the length property. This is a public property giving us the size of the array.с

Конечно, можно использовать другие механизмы цикла, такие какwhile илиdo while. Но, что касается коллекций Java, можно перебирать массивы с помощью циклаforeach:

int[] anArray = new int[] {1, 2, 3, 4, 5};
for (int element : anArray) {
    System.out.println(element);
}

Этот пример эквивалентен предыдущему, но мы избавились от стандартного кода индексов. The foreach loop is an option when:с

  • нам не нужно изменять массив (добавление другого значения в элемент не изменит элемент в массиве)

  • нам не нужны индексы для чего-то другого

6. списки параметры

Мы уже рассмотрели основы создания массивов и управления ими. Теперь мы перейдем к более сложным темам, начиная сvarargs. Напоминаем, чтоvarargs используются для передачи произвольного количества аргументов методу:

void varargsMethod(String... varargs) {}

Этот метод может принимать от 0 до произвольного количества аргументовString. Статью оvarargs можно найтиhere.

Здесь мы должны знать, что внутри тела метода параметрvarargs превращается в массив. Но,we can also pass an array directly as the argument. Давайте посмотрим, как повторно использовать метод, описанный выше:

String[] anArray = new String[] {"Milk", "Tomato", "Chips"};
varargsMethod(anArray);

Будет вести себя так же, как:

varargsMethod("Milk", "Tomato", "Chips");

7. Преобразование массива в список

Массивы - это здорово, но иногда удобнее иметь дело сList. Здесь мы увидим, как преобразовать массив вList.

Сначала мы сделаем это наивным способом, создав пустой список и перебирая массив, чтобы добавить его элементы в список:

int[] anArray = new int[] {1, 2, 3, 4, 5};

List aList = new ArrayList<>();
for (int element : anArray) {
    aList.add(element);
}

Но есть и другой способ, более краткий:

Integer[] anArray = new Integer[] {1, 2, 3, 4, 5};
List aList = Arrays.asList(anArray);

The static method Arrays.asList takes a varargs argument and creates a list with the passed values. К сожалению, у этого метода есть некоторые недостатки:

  • Невозможно использовать массив примитивных типов.

  • Мы не можем добавлять или удалять элементы из созданного списка, так как это вызоветUnsupportedOperationException

8. Из массива в поток

Теперь мы можем преобразовывать массивы в списки, но начиная с Java 8 у нас есть доступ кStream API, и мы можем захотеть превратить наши массивы вStream. Java предоставляет нам для этого методArrays.stream:

String[] anArray = new String[] {"Milk", "Tomato", "Chips"};
Stream aStream = Arrays.stream(anArray);

При передаче массиваObject в метод он вернетStream соответствующего типа (например, Stream<Integer> для массиваInteger). При передаче примитива он вернет соответствующий примитивStream.

Также возможно создать поток только для части массива:

Stream anotherStream = Arrays.stream(anArray, 1, 3);

Это создастStream<String> только с «Помидорами» и «Чипсы»Strings (первый индекс включающий, а второй - исключающий).

9. Сортировка массивов

Давайте теперь посмотрим, как сортировать массив, то есть переставлять его элементы в определенном порядке. The Arrays class provides us with the sort method. Немного похоже на методstream,sort имеет много перегрузок.

Есть перегрузки для сортировки:

  • Массивы примитивного типа: сортируются в порядке возрастания

  • МассивыObject (этиObject должны реализовывать интерфейсComparable): которые сортируются в соответствии с естественным порядком (на основе методаcompareTo изComparable)

  • Общие массивы: сортируются в соответствии с заданнымComparator

Кроме того, можно отсортировать только определенную часть массива (передав методу начальный и конечный индексы).

Алгоритмы, лежащие в основе методаsort, - этоquick sort иmerge sort для примитивных и других массивов соответственно.

Давайте посмотрим, как все это работает, на нескольких примерах:

int[] anArray = new int[] {5, 2, 1, 4, 8};
Arrays.sort(anArray); // anArray is now {1, 2, 4, 5, 8}

Integer[] anotherArray = new Integer[] {5, 2, 1, 4, 8};
Arrays.sort(anotherArray); // anotherArray is now {1, 2, 4, 5, 8}

String[] yetAnotherArray = new String[] {"A", "E", "Z", "B", "C"};
Arrays.sort(yetAnotherArray, 1, 3,
  Comparator.comparing(String::toString).reversed()); // yetAnotherArray is now {"A", "Z", "E", "B", "C"}

10. Поиск в массиве

Поиск в массиве довольно прост, мы можем циклически перемещаться по массиву и искать наш элемент среди элементов массива:

int[] anArray = new int[] {5, 2, 1, 4, 8};
for (int i = 0; i < anArray.length; i++) {
    if (anArray[i] == 4) {
        System.out.println("Found at index " + i);
        break;
    }
}

Здесь мы искали номер 4 и нашли его по индексу 3.

If we have a sorted array though, we can use another solution: the binary search. Принцип двоичного поиска объясняется вthis article.

Fortunately, Java provides us with the Arrays.binarySearch method. Мы должны предоставить ему массив и элемент для поиска.

В случае универсального массива мы также должны указать емуComparator, которые использовались для сортировки массива в первую очередь. Опять есть возможность вызывать метод для подмножества массива.

Давайте посмотрим на пример использования метода двоичного поиска:

int[] anArray = new int[] {1, 2, 3, 4, 5};
int index = Arrays.binarySearch(anArray, 4);
System.out.println("Found at index " + index);

Поскольку мы сохранили число 4 в четвертой ячейке, в результате мы получим индекс 3. Обратите внимание, что мы использовали уже отсортированный массив.

11. Конкатенация массивов

Наконец, давайте посмотрим, как объединить два массива. The idea is to create an array which length is the sum of the two arrays to concatenate. После этого мы должныadd the elements of the first one and then the elements of the second one:

int[] anArray = new int[] {5, 2, 1, 4, 8};
int[] anotherArray = new int[] {10, 4, 9, 11, 2};

int[] resultArray = new int[anArray.length + anotherArray.length];
for (int i = 0; i < resultArray.length; i++) {
    resultArray[i] = (i < anArray.length ? anArray[i] : anotherArray[i - anArray.length]);
}

Как мы видим, когда индекс все еще меньше, чем длина первого массива, мы добавляем элементы из этого массива. Затем мы добавляем элементы из второго. Мы можем использовать методArrays.setAll, чтобы избежать написания цикла:

int[] anArray = new int[] {5, 2, 1, 4, 8};
int[] anotherArray = new int[] {10, 4, 9, 11, 2};

int[] resultArray = new int[anArray.length + anotherArray.length];
Arrays.setAll(resultArray, i -> (i < anArray.length ? anArray[i] : anotherArray[i - anArray.length]));

Этот метод установит все элементы массива в соответствии с заданной функцией. Эта функция связывает индекс с результатом.

Вот третий вариант объединения в массивы:System.arraycopy. Этот метод принимает исходныйarray, исходную позицию, целевойarray, целевую позицию иint , определяющий количество элементов для копирования:

System.arraycopy(anArray, 0, resultArray, 0, anArray.length);
System.arraycopy(anotherArray, 0, resultArray, anArray.length, anotherArray.length);

Как мы видим, мы копируем первый массив, затем второй (после последнего элемента первого).

12. Заключение

В этой подробной статье мы рассмотрели базовое и некоторые расширенные способы использования массивов в Java.

Мы видели, что Java предлагает множество методов для работы с массивами черезArrays utility class. Также существуют служебные классы для управления массивами в библиотеках, напримерApache Commons илиGuava.

Полный код этой статьи можно найти наour GitHub.