Ошибка "Index -1 out of bounds for length 2"?
Подскажите, пожалуйста, почему компилятор выдает ошибку:
"Index -1 out of bounds for length 2"
Как ее исправить?
Вот код:
public void merge(int[] nums1, int m, int[] nums2, int n) {
if (m == 0) {
System.out.println("Обратите внимание, что поскольку m = 0, в nums1 нет элементов. 0 присутствует только для того, чтобы результат слияния мог поместиться в nums1.");
}
ArrayList<Integer> w1 = new ArrayList<>();
ArrayList<Integer> w2 = new ArrayList<>();
if (nums2.length == 0) {
System.out.println(Arrays.toString(new String[]{Arrays.toString(nums1)}));
} else {
for (int el : nums1) {
w1.add(el);
}
int r = nums1.length;
for (int i = m; w1.size() != m; i++) {
w1.removeLast();
}
for (int el : nums2) {
w2.add(el);
}
int z = nums1.length;
for (int i = n; w2.size() != n; i--) {
w2.remove(i - 1);
}
Collections.sort(w1);
Collections.sort(w2);
System.out.println(w1.toString());
System.out.println(w2.toString());
}
}
Ответы (2 шт):
Компилятор не может выдавать указанную ошибку, так как она возникает при выполнении программы.
Судя по коду, она возникает в строке w2.remove(i - 1);
при удалении некоторых элементов из списка w2
, так как переменная цикла i
быстро уменьшается, а условие i > 0
в цикле не проверяется.
Другие проблемы в представленном коде:
- переменные
r
,z
проинициализированы одним и тем же значением, но нигде не используются. - переменные
m
,n
не сопоставляются с размерами соответствующих массивовnums1
,nums2
в том смысле, что они могут превышать размеры массивов. - в списки
w1
,w2
зачем-то полностью копируется содержимое массивовnums1
,nums2
, а затем начинаются циклы для удаления элементов из конца спискаw1
и начала спискаw2
-- значительно проще было бы сразу скопировать нужное число элементов - несмотря на название метода
merge
и текст сообщения о неком слиянии, данный метод в лучшем случае распечатает содержимое двух отсортированных списковw1
иw2
.
Вариант исправленного кода может выглядеть так:
public void merge(int[] nums1, int m, int[] nums2, int n) {
if (m == 0) {
System.out.println("Обратите внимание, что поскольку m = 0, в nums1 нет элементов. 0 присутствует только для того, чтобы результат слияния мог поместиться в nums1.");
}
if (nums2.length == 0) {
System.out.println(Arrays.toString(nums1));
return;
}
// создадим списки с нужной ёмкостью
List<Integer> w1 = new ArrayList<>(m);
List<Integer> w2 = new ArrayList<>(n);
// копируем не больше первых m элементов nums1 в список w1
for (int i = 0, r = Math.min(nums1.length, m); i < r; i++) {
w1.add(nums1[i]);
}
// копируем не больше последних n элементов nums2 в список w2
for (int z = nums2.length, i = Math.max(z - n, 0); i < z; i++) {
w2.add(nums2[i]);
}
Collections.sort(w1);
Collections.sort(w2);
// метод toString() вызывается по умолчанию при выводе каждого списка
System.out.println(w1);
System.out.println(w2);
}
Вообще, для подобного рода преобразований подходит Stream API, позволяющий реализовать нужную функциональность в более лаконичном и декларативном стиле.
Пример реализации:
public void merge(int[] nums1, int m, int[] nums2, int n) {
if (m == 0) {
System.out.println("Обратите внимание, что поскольку m = 0, в nums1 нет элементов. 0 присутствует только для того, чтобы результат слияния мог поместиться в nums1.");
}
if (nums2.length == 0) {
System.out.println(Arrays.toString(nums1));
return;
}
// создадим нужные списки
var w1 = Arrays.stream(nums1)
.limit(m)
.sorted().boxed().toList();
var w2 = Arrays.stream(nums2)
.skip(Math.max(nums2.length - n, 0))
.sorted().boxed().toList();
System.out.println(w1);
System.out.println(w2);
}
Эта ошибка происходит при выходе индекса из границ массива. То есть, если вы создаёте массив с размером 5, то индексы у этого массива от 0 до 4. Если вы укажете индекс отрицательный или число больше 4 то выскочит эта ошибка. Она определяется классом ArrayIndexOutOfBoundsException
. Её можно поймать в блоке try-catch.