> Как избежать ошибки IndexOutOfBoundsException при итерации по JSON-массиву в Java (Java)

Уровень: senior · Роль: backend · Язык: Java · Категория: Технические вопросы

Компании: ИТ-Экспертиза

Стек: Java

> Пример ответа

Короткий ответ

Ошибка IndexOutOfBoundsException при итерации по JSON-массиву в Java возникает из-за выхода за границы при ручном управлении индексом. Чтобы её избежать, используйте итераторы, цикл for-each или Stream API вместо доступа по индексу. Всегда проверяйте размер массива через size() перед доступом к элементам. Для библиотек вроде Jackson или Gson применяйте типизированные коллекции, а не сырые JsonArray с произвольным индексом.

Подробное объяснение

На уровне senior важно понимать, что JSON-массив в Java может быть представлен по-разному: как org.json.JSONArray, com.google.gson.JsonArray, com.fasterxml.jackson.databind.JsonNode или как обычный List<T> после десериализации. В каждом случае риск IndexOutOfBoundsException связан с прямым обращением по индексу без проверки границ. Итерация через for (int i = 0; i < array.length(); i++) безопасна, если условие строгое, но уязвима при изменении размера во время обхода или при использовании <=. Senior-подход предполагает отказ от ручных индексов в пользу абстракций: Iterator, Iterable, Stream. Это устраняет класс ошибок, связанных с выходом за границы. Кроме того, при работе с внешними JSON-источниками необходимо учитывать, что массив может быть null или отсутствовать, поэтому проверка на null и isEmpty() обязательна. Для Jackson рекомендуется использовать JsonNode.elements() или JsonNode.forEach(), для Gson - JsonArray.iterator(). Если требуется доступ по индексу, всегда проверяйте index >= 0 && index < size(). В многопоточной среде даже проверка размера не гарантирует безопасность, поэтому нужна синхронизация или иммутабельные коллекции.

На практике

При десериализации JSON в List<MyDto> через Jackson используйте TypeReference и затем обычный for-each. Если работаете с JsonNode, вызывайте node.isArray() и node.size(), а обход делайте через for (JsonNode element : node). Для JSONArray из org.json применяйте for (int i = 0; i < array.length(); i++) с обязательной проверкой array.length() перед циклом. В Gson используйте JsonArray и его метод iterator(). Никогда не полагайтесь на try-catch вокруг IndexOutOfBoundsException как на основной механизм - это антипаттерн, скрывающий логические ошибки. Вместо этого проектируйте код так, чтобы индексы не использовались вовсе. Если JSON-массив приходит из ненадёжного источника, добавьте валидацию схемы или используйте Optional для элементов.

Пример кода

JAVA
// Плохо: ручной индекс без проверки
JSONArray array = new JSONArray(jsonString);
for (int i = 0; i <= array.length(); i++) { // ошибка: <=
System.out.println(array.get(i));
}
// Хорошо: итератор
for (Object item : array) {
System.out.println(item);
}
// Хорошо: Stream API для Jackson
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(jsonString);
if (root.isArray()) {
root.forEach(node -> System.out.println(node.asText()));
}
// Хорошо: типизированная коллекция
List<MyDto> list = mapper.readValue(jsonString, new TypeReference<List<MyDto>>() {});
for (MyDto dto : list) {
// обработка
}

Как отвечать на собеседовании

Начните с того, что IndexOutOfBoundsException - это следствие ручного управления индексом. Предложите использовать итераторы или Stream API как основной способ обхода. Упомяните, что для разных JSON-библиотек есть свои идиомы: Jackson - JsonNode.forEach, Gson - JsonArray.iterator, org.json - цикл с length(). Подчеркните необходимость проверки на null и пустой массив. Если спросят про производительность, отметьте, что for-each и Stream не создают дополнительных накладных расходов по сравнению с индексами, но безопаснее. В конце добавьте, что try-catch вокруг исключения - плохая практика, так как маскирует баги.

Что проверяет интервьюер

Интервьюер хочет убедиться, что кандидат понимает разницу между безопасной и небезопасной итерацией, знает особенности популярных JSON-библиотек и умеет выбирать правильную абстракцию. Также проверяется навык defensive programming: проверка границ, null-safe подходы, отказ от антипаттернов. Для senior-уровня важно умение объяснить trade-off между гибкостью ручного индекса и безопасностью итераторов, а также знание о потенциальных проблемах в многопоточной среде.

Типичные ошибки

Использование <= вместо < в условии цикла. Обращение к array.get(i) без предварительной проверки i < array.length(). Игнорирование того, что JSON-массив может быть null или отсутствовать. Применение try-catch для IndexOutOfBoundsException как основного способа обработки. Предположение, что размер массива не меняется во время итерации. Работа с сырыми типами JSONArray или JsonArray без приведения к типизированным коллекциям. Попытка доступа к элементу по индексу после удаления элементов в цикле.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью