2013-03-03 5 views
2

У меня есть кусок кода на Java (Android), который иногда генерирует ArrayIndexOutOfBoundsException.Почему этот код генерирует ArrayIndexOutOfBoundsException?

String characterLevel = mCharacterModel.CharacterLevel() >= 
     MessageModel.CharacterLevels.length ? "Hyperion Overlord" : 
     MessageModel.CharacterLevels[mCharacterModel.CharacterLevel()]; 

Метод mCharacterModel.CharacterLevel() всегда равно 1 или более.

Массив MessageModel.CharacterLevels определяется следующим образом и содержит около 50 элементов.

public static final String[] CharacterLevels = { "Title", "Title" };

Суть вопроса о грациозно недобросовестный к другому источнику данных, если размер массива был превышен.

Должно быть, что-то не хватает. Это неправильный способ установить строку по умолчанию в строку?

Я искал решения повсюду, о которых я могу думать, и я обеспокоен. Я просто пропустил некоторые основные недостатки в логике выше.

Любая помощь или предложения оценены.

+0

Так что мне интересно - если вы решили, что это проблема, что оказалось проблемой? – Krease

+0

Крушение происходит от Star Traders RPG на консоли разработчика Google Play, поэтому я только предполагаю, что исправил ее. Я так и не смог воспроизвести крах. Я внес изменения, как было предложено - теперь я называю mCharacterModel.CharacterLevel() один раз, в случае, если другие потоки обновляют статистику персонажа. Я также добавил проверку, чтобы гарантировать, что уровень не является отрицательным. CharacterLevels [] никогда не изменяется, поэтому я пропустил это. Я также переработал код, похожий на предложение, которое вы сделали ниже. Теперь я смотрю «Отчеты об ошибках» и держу пальцы. Еще раз спасибо! –

ответ

1

Ваш код выглядит логически эквивалентно следующему:

int level = mCharacterModel.CharacterLevel(); 
String[] arr = MessageModel.CharacterLevels; 
String characterLevel = level < arr.length ? 
     arr[level] : 
     "Hyperion Overlord"; 

который будет ясно только индекс в массиве, если оно находится в пределах границ. Я не согласен с другими ответами о модификаторе -1 на ваш индекс массива, поскольку ваша логическая проверка должна помешать слишком большому уровню для массива.

Единственное различие я вижу в исходном коде (или вещи, которые я не могу видеть), что может вызвать проблемы являются (в порядке убывания вероятности):

  1. Вы звоните более mCharacterModel.CharacterLevel(), чем когда-то - если это изменяется с последующими вызовами, это может быть источником ошибок. Возможно, это 1 на первый вызов и 3 на втором?
  2. mCharacterModel.CharacterLevel() может возвращать отрицательное число - я бы добавил чек, чтобы убедиться, что это также >= 0 перед индексированием в массив.
  3. MessageModel.CharacterLevels может быть доступным для нескольких потоков, и он изменяется между проверкой длины и доступом, что вызывает проблему.
0
String characterLevel = mCharacterModel.CharacterLevel() >= MessageModel.CharacterLevels.length-1 ? "Hyperion Overlord" : MessageModel.CharacterLevels[mCharacterModel.CharacterLevel()]; 

Это должно работать, длина не основана на 0, поэтому при вычислении на основе длины вы должны идти '-1'.

+0

Не будет ли '> =' обложки? Если длина равна 50, она будет индексироваться только в массив, если 'CharacterLevel()' равно 49 или меньше, что должно быть достоверным ... – Krease

0

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

int index = mCharacterModel.CharacterLevel() - 1; 
String characterLevel = index >= MessageModel.CharacterLevels.length ? "Hyperion Overlord" : MessageModel.CharacterLevels[index]; 

Если значение всегда 1 или больше, вы должны начать с 0. Другой вопрос - лучше не вызывать функцию CharacterLevel() дважды и используя результат. Лучше сохранить значение в локальной переменной и использовать его в обоих местах.

+0

Не согласен с модификатором -1 до уровня. Логика правильна для того, чтобы уровень уверенности не превышал длину массива (при условии, что функция всегда возвращает одно и то же значение). См. [Мой ответ] (http://stackoverflow.com/a/15183844/836214) ниже для слегка переписанной версии, которая делает это более очевидным. – Krease

+0

-1 поможет ему получить значение 0, так как он говорит, что значение всегда 1 или больше. Как указано в моем ответе, необходимо объединить вызовы CharacterLevel. – BobTheBuilder

+0

Но если значение CharacterLevel всегда строго меньше длины массива, т. Е. Not> =, то превышение границ массива (где -1 было бы полезно) не является проблемой. – Krease

Смежные вопросы