Мы оказываемся во вселенной, которая, по-видимому, развивается по измерению, которое мы называем «временем». Мы не понимаем, какое время, но мы разработали абстракции и словарный запас, которые позволяют рассуждать и говорить об этом: «прошлое», «настоящее», «будущее», «до», «после».
Компьютерные системы, которые мы строим - все больше и больше - имеют время как важное измерение. В будущем будут созданы определенные вещи. Тогда другие вещи должны произойти после того, как эти первые вещи в конечном итоге произойдут. Это основное понятие, называемое «асинхронность». В нашем мире с более сложной сетью наиболее распространенный случай асинхронности ожидает, что какая-то удаленная система ответит на какой-то запрос.
Рассмотрим пример. Вы называете молочника и заказываете молоко. Когда это произойдет, вы хотите положить его в свой кофе. Вы не можете положить молоко в свой кофе прямо сейчас, потому что его еще нет. Вы должны подождать, пока это произойдет, прежде чем положить его в свой кофе. Другими словами, следующее не будет работать:
var milk = order_milk();
put_in_coffee(milk);
Поскольку JS не знает, что ему нужно дождаться окончания order_milk
, прежде чем он выполнит put_in_coffee
. Другими словами, он не знает, что order_milk
является асинхронным - это то, что не приведет к молоку до некоторого будущего времени. JS и другие декларативные языки, выполняйте один оператор за другим, не ожидая.
Классический подход JS к этой проблеме, используя тот факт, что JS поддерживает функции как объекты первого класса, которые могут быть переданы, заключается в передаче функции в качестве параметра для асинхронного запроса, который затем будет вызываться, когда он будет выполнять свою задачу в будущем. Это подход «обратного вызова». Это выглядит так:
order_milk(put_in_coffee);
order_milk
запускает, заказывает молоко, тогда, когда и только когда он прибывает, он вызывает put_in_coffee
.
Проблема с этот подход обратного вызова состоит в том, что он загрязняет нормальную семантику функции, сообщающей свой результат с помощью return
; вместо этого функции должны сообщать свои результаты, вызывая обратный вызов, заданный как параметр. Кроме того, этот подход может быстро стать громоздким при работе с более длинными последовательностями событий. Например, предположим, что я хочу дождаться, когда молоко будет помещено в кофе, а затем и только затем выполните третий шаг, а именно - выпить кофе. В конце концов мне нужно написать что-то вроде этого:
order_milk(function(milk) { put_in_coffee(milk, drink_coffee); }
, где я перехожу к put_in_coffee
как к молоку, чтобы положить в него, так и к действию (drink_coffee
), чтобы выполнить как только молоко был введен. Такой код становится трудно писать, читать и отлаживать.
В этом случае мы могли бы переписать код в вопросе как:
var answer;
$.ajax('/foo.json') . done(function(response) {
callback(response.data);
});
function callback(data) {
console.log(data);
}
. Это была мотивация для понятия «обещание», которое является особым типом ценности, представляющим собой будущий или асинхронный результат какого-то рода. Он может представлять что-то, что уже произошло, или это произойдет в будущем, или, возможно, никогда не произойдет вообще. Обещания имеют один метод, названный then
, которому вы передаете действие, которое должно быть выполнено, когда был достигнут результат, представленный обещанием.
В случае нашего молока и кофе мы создаем order_milk
, чтобы вернуть обещание о прибытии молока, затем укажите put_in_coffee
как действие then
следующим образом:
order_milk() . then(put_in_coffee)
. Одно из преимуществ этого заключается в том, что мы можем объединить их вместе для создания последовательностей будущие вхождения («цепочка»):
order_milk() . then(put_in_coffee) . then(drink_coffee)
Давайте применим обещания к вашей конкретной проблеме. Мы завершим нашу логику запроса внутри функции, которая возвращает обещание:
function get_data() {
return $.ajax('/foo.json');
}
На самом деле, все, что мы сделали, добавлено к return
к вызову $.ajax
. Это работает, потому что jQuery $.ajax
уже возвращает вид обетоподобной вещи. (На практике, не вдаваясь в подробности, мы предпочли бы обернуть этот вызов, чтобы вернуть реальное обещание, или использовать некоторую альтернативу $.ajax
, которая делает это.) Теперь, если мы хотим загрузить файл и дождаться его завершите, а затем сделайте что-нибудь, мы можем просто сказать
get_data() . then(do_something)
, например,
get_data() .
then(function(data) { console.log(data); });
. При использовании обещаний мы заканчиваем передачу множества функций в then
, поэтому часто полезно использовать более компактные функции стрелок в стиле ES6:
get_data() .
then(data => console.log(data));
async
Но все еще есть что-то неопределенное в том, что нужно писать код одним способом, если синхронно и совершенно по-другому, если асинхронно. Для синхронного мы пишем
a();
b();
, но если a
является асинхронным, с обещаниями мы должны написать
a() . then(b);
Выше, мы сказали: «JS не имеет никакого способа узнать что ему нужно дождаться завершения первого вызова, прежде чем он выполнит второй ». Было бы неплохо, если бы можно было сказать JS? Оказывается, существует ключевое слово await
, используемое внутри специального типа функции, называемого функцией «async». Эта функция является частью предстоящей версии ES, но уже доступна в транспилерах, таких как Babel, с учетом правильных настроек. Это позволяет нам просто написать
async function morning_routine() {
var milk = await order_milk();
var coffee = await put_in_coffee(milk);
await drink(coffee);
}
. В вашем случае вы могли бы написать что-то вроде
async function foo() {
data = await get_data();
console.log(data);
}
Ваш первый порт вызова должен быть документацией , который объясняет это разумно ясно:
Брошено, чтобы указать, что к массиву был обращен незаконный индекс. Индекс является либо отрицательным, либо большим или равным размеру массива.
blockquote>Так, например:
int[] array = new int[5]; int boom = array[10]; // Throws the exception
Как избежать этого. ., не делайте этого. Будьте осторожны с вашими индексами массива.
Одной из проблем, с которыми иногда сталкиваются люди, является то, что массивы 1-индексируются, например
int[] array = new int[5]; // ... populate the array here ... for (int index = 1; index <= array.length; index++) { System.out.println(array[index]); }
Это пропустит первый элемент (индекс 0 ) и выдают исключение, когда индекс равен 5. Действующие индексы здесь 0-4 включительно. Правильный, идиоматический оператор
for
здесь будет:for (int index = 0; index < array.length; index++)
(Предполагается, что вы нуждаетесь в индексе, конечно. Если вы можете использовать расширенный для цикла, сделайте это.)
Согласно вашему коду:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n');
}
Если вы проверите System.out.print (name.length),
, вы получите 3;
, что означает, что длина вашего имени равна 3
, ваш цикл работает от 0 до 3, который должен работать либо от «0 до 2», либо от «1 до 3»
Ответ
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
System.out.print(name[i] +'\n');
}
ArrayIndexOutOfBoundsException
означает, что вы пытаетесь получить доступ к индексу массива, который не существует или не связан с границей этого массива. Индексы массива начинаются с 0 и заканчиваются на длину - 1.
В вашем случае
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n'); // i goes from 0 to length, Not correct
}
ArrayIndexOutOfBoundsException
происходит, когда вы пытаетесь получить доступ к элементу index.length, который делает не существует (индекс массива заканчивается на -1). просто заменяя & lt; = с & lt; решит эту проблему.
for(int i = 0; i < name.length; i++) {
System.out.print(name[i] +'\n'); // i goes from 0 to length - 1, Correct
}
if (index < 0 || index >= array.length) {
// Don't use this index. This is out of bounds (borders, limits, whatever).
} else {
// Yes, you can safely use this index. The index is present in the array.
Object element = array[index];
}
Обновление: в соответствии с вашим фрагментом кода,
for(int i = 0; i<=name.length; i++) {
Индекс содержит длину массива. Это за гранью. Вы должны заменить <=
на <
.
for(int i = 0; i < name.length; i++) {
Для многомерных массивов может быть сложно получить доступ к свойству length
правого измерения. Возьмем следующий код, например:
int [][][] a = new int [2][3][4];
for(int i = 0; i < a.length; i++){
for(int j = 0; j < a[i].length; j++){
for(int k = 0; k < a[j].length; k++){
System.out.print(a[i][j][k]);
}
System.out.println();
}
System.out.println();
}
Каждое измерение имеет разную длину, поэтому тонкая ошибка заключается в том, что средняя и внутренняя петли используют свойство length
той же размерности (поскольку a[i].length
(f5)).
Вместо этого внутренний цикл должен использовать a[i][j].length
(или a[0][0].length
для простоты).
Эта ошибка возникает при переполнении циклов цикла. Давайте рассмотрим простой пример:
class demo{
public static void main(String a[]){
int[] numberArray={4,8,2,3,89,5};
int i;
for(i=0;i<numberArray.length;i++){
System.out.print(numberArray[i+1]+" ");
}
}
Сначала я инициализировал массив как «numberArray». то некоторые элементы массива печатаются с использованием цикла. Когда цикл запускает время «i», напечатайте элемент (numberArray [i + 1] .. (когда значение i равно 1, будет напечатан элемент numberArray [i + 1].) Предположим, что, когда i = (numberArray. length-2), последний элемент массива печатается. Когда значение «i» переходит к (numberArray.length-1), нет значения для печати. В этот момент происходит «ArrayIndexOutOfBoundsException». Я надеюсь, что вы можете получить idea.thank you!
Чтобы исключить исключительное исключение индекса массива, следует использовать инструкцию расширенный- for
, где и когда они могут.
Основная мотивация (и использовать), когда вы выполняете итерацию, и вам не требуются сложные шаги итерации. Вы не могли бы использовать расширенный for
для перемещения назад в массиве или только для итерации на каждом другом элементе.
Вы гарантированно не исчерпали элементы для повторения при этом, а ваш [исправленный] пример легко конвертируется.
Код ниже:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i< name.length; i++) {
System.out.print(name[i] + "\n");
}
... эквивалентен этому:
String[] name = {"tom", "dick", "harry"};
for(String firstName : name) {
System.out.println(firstName + "\n");
}
Для вашего массива длина массива равна 3 (например, name.length = 3). Но поскольку он хранит элемент, начинающийся с индекса 0, он имеет максимальный индекс 2.
Итак, вместо 'i ** & lt; = name.length' вы должны написать 'i & lt; ** name.length' чтобы избежать «ArrayIndexOutOfBoundsException».
Это означает, что вы пытаетесь получить доступ к индексу массива, который недопустим, поскольку он не находится между границами.
Например, это инициализировало бы примитивный целочисленный массив с верхней границей 4 .
int intArray[] = new int[5];
Программисты подсчитываются с нуля. Таким образом, это, например, выбрало бы ArrayIndexOutOfBoundsException
, поскольку верхняя граница равна 4, а не 5.
intArray[5];
Вы не могли итерировать или хранить больше данных, чем длина вашего массива. В этом случае вы можете сделать так:
for (int i = 0; i <= name.length - 1; i++) {
// ....
}
Или это:
for (int i = 0; i < name.length; i++) {
// ...
}
Так много для этого простого вопроса, но я просто хотел выделить новую функцию на Java, которая позволит избежать всех путаниц в индексировании в массивах даже для новичков. Java-8 абстрагировал задачу итерации для вас.
int[] array = new int[5];
//If you need just the items
Arrays.stream(array).forEach(item -> { println(item); });
//If you need the index as well
IntStream.range(0, array.length).forEach(index -> { println(array[index]); })
В чем польза? Ну, с одной стороны, это читаемость, как английский. Во-вторых, вам не нужно беспокоиться о ArrayIndexOutOfBoundsException
ArrayIndexOutOfBoundsException
само имя объясняет, что если вы пытаетесь получить доступ к значению в индексе, который выходит за рамки размера массива, возникает такое исключение.
В вашем случае вы можете просто удалить знак равенства из цикла for.
for(int i = 0; i<name.length; i++)
Лучшим вариантом является итерация массива:
for(String i : name )
System.out.println(i);
Короче говоря:
В последней итерации
for(int i = 0; i<=name.length; i++) {
i
будет равно name.length
, что является незаконным индексом, так как индексы массива равны нулю, основанный.
Ваш код должен читать
for(int i = 0; i < name.length; i++)
^
Что вызывает ArrayIndexOutOfBoundsException
?
Если вы думаете о переменной как о «поле», где вы можете поместить значение, то массив представляет собой ряд ящиков, расположенных рядом с eachother, где число Ячейки представляют собой конечное и явное целое число.
Создание такого массива:
final int[] myArray = new int[5]
создает строку из 5 полей, каждая из которых имеет int
. Каждый из ящиков имеет индекс, позицию в ряду ящиков. Этот индекс начинается с 0 и заканчивается на N-1, где N - размер массива (количество ящиков).
Чтобы получить одно из значений из этой серии ящиков, вы можете обратиться к нему через его индекс, например:
myArray[3]
Который даст вам значение 4-го ящика в серии (так как в первом поле есть индекс 0).
ArrayIndexOutOfBoundsException
вызвано попыткой извлечь «ящик», который не существует, передав индекс, который выше индекса последнего «поля» или отрицательный.
В моем примере работы эти фрагменты кода приведут к такому исключению:
myArray[5] //tries to retrieve the 6th "box" when there is only 5
myArray[-1] //just makes no sense
myArray[1337] //waay to high
Как избежать ArrayIndexOutOfBoundsException
Чтобы предотвратить ArrayIndexOutOfBoundsException
, необходимо рассмотреть некоторые ключевые моменты:
Looping
При переходе по массиву всегда убедитесь, что индекс, который вы извлекаете, строго меньше длины массива (количество ящиков). Например:
for (int i = 0; i < myArray.length; i++) {
Обратите внимание на <
, никогда не смешивайте там =
.
Возможно, вам захочется сделать что-то вроде этого:
for (int i = 1; i <= myArray.length; i++) {
final int someint = myArray[i - 1]
Просто нет. Придерживайтесь одного выше (если вам нужно использовать индекс), и это сэкономит вам много боли.
По возможности используйте foreach:
for (int value : myArray) {
Таким образом, вы вообще не придется вообще обдумывать индексы.
Когда вы выполняете цикл, что бы вы ни делали, НИКОГДА не изменяйте значение итератора цикла (здесь: i
). Единственное место, которое должно изменить значение, это сохранить цикл. Изменение в противном случае просто рискует исключением и в большинстве случаев не является обязательным.
Retrieval / update
При извлечении произвольного элемента массива всегда проверяйте его действительность индекс по длине массива:
public Integer getArrayElement(final int index) {
if (index < 0 || index >= myArray.length) {
return null; //although I would much prefer an actual exception being thrown when this happens.
}
return myArray[index];
}