У меня есть ситуация, когда return
оператор, вложенный в два цикла for
, всегда будет достигнут теоретически.
Компилятор не согласен и требует return
утверждения вне for
цикла. Я хотел бы знать элегантный способ оптимизации этого метода, который выходит за рамки моего текущего понимания, и ни одна из моих попыток реализации break, похоже, не работает.
Прикрепленный - это метод из присваивания, который генерирует случайные целые числа и возвращает итерации, циклически выполняемые до тех пор, пока не будет найдено второе случайное целое число, сгенерированное в пределах диапазона, переданного в метод как параметр int.
private static int oneRun(int range) {
int[] rInt = new int[range+1]; // Stores the past sequence of ints.
rInt[0] = generator.nextInt(range); // Inital random number.
for (int count = 1; count <= range; count++) { // Run until return.
rInt[count] = generator.nextInt(range); // Add randint to current iteration.
for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
if (rInt[i] == rInt[count]) {
return count;
}
}
}
return 0; // Never reached
}
while(true)
цикл, а не индексированный. Это сообщает компилятору, что цикл никогда не вернется.oneRun(0)
), и вы увидите, что быстро достигнете своего недостижимого местаreturn
nextInt
генерирует исключение дляrange < 0
Единственный случай, когда достигается возврат, когдаrange == 0
Ответы:
Эвристика компилятора никогда не позволит пропустить последнее
return
. Если вы уверены, что этого никогда не произойдет, я бы заменил егоthrow
на, чтобы прояснить ситуацию.источник
throw new AssertionError("\"unreachable\" code reached");
throw
, который никогда не будет достигнут. Слишком часто люди просто хотят быстро применить «одно решение, чтобы управлять всеми ими», не слишком задумываясь о глубинной проблеме. Но программирование - это гораздо больше, чем просто кодирование. Особенно если речь идет об алгоритмах. Если вы (внимательно) изучите данную проблему, вы поймете, что можете исключить последнюю итерацию внешнегоfor
цикла и, следовательно, заменить «бесполезный» возврат на полезный (см. Этот ответ ).Как указал @BoristheSpider, вы можете убедиться, что второй
return
оператор семантически недоступен:Компилируется и работает нормально. И если вы когда-нибудь получите сообщение,
ArrayIndexOutOfBoundsException
вы узнаете, что реализация была семантически неверной, без необходимости явно бросать что-либо.источник
for(int count = 0; true; count++)
вместо этого я бы написал это как .true
:for(int count = 0; ; count++) …
while(true)
, я подумал, что, возможно, java немного строже в этом отношении. Приятно знать, что волноваться не о чем ... На самом деле, мнеtrue
гораздо больше нравится пропущенная версия: она дает визуально ясно, что нет абсолютно никаких условий, на которые можно смотреть :-)Поскольку вы спросили о выходе из двух
for
циклов, вы можете использовать для этого метку (см. Пример ниже):источник
returnValue
его можно использовать без инициализации?Хотя assert - хорошее быстрое решение. В общем, такого рода проблемы означают, что ваш код слишком сложен. Когда я смотрю на ваш код, становится очевидно, что вы действительно не хотите, чтобы массив содержал предыдущие числа. Вы хотите
Set
:Теперь обратите внимание, что на самом деле мы возвращаем размер набора. Сложность кода снизилась с квадратичной до линейной, и он сразу стал более читаемым.
Теперь мы можем понять, что нам даже не нужен этот
count
индекс:источник
Поскольку ваше возвращаемое значение основано на переменной внешнего цикла, вы можете просто изменить условие внешнего цикла,
count < range
а затем вернуть это последнее значение (которое вы только что пропустили) в конце функции:Таким образом, вам не нужно вводить код, который никогда не будет достигнут.
источник
...
цикла for (я просто пропустил второй ), но внешний цикл был сокращен к его последней итерации. Случай, соответствующий этой последней итерации, обрабатывается отдельно самым последним оператором return. Хотя это элегантное решение для вашего примера, существуют сценарии, в которых этот подход становится труднее читать; если, например, возвращаемое значение зависело от внутреннего цикла, тогда - вместо единственного оператора возврата в конце - у вас останется дополнительный цикл (представляющий внутренний цикл для последней итерации внешнего цикла).Используйте временную переменную, например «результат», и удалите внутренний возврат. Измените цикл for на цикл while с правильным условием. Для меня всегда более элегантно иметь только один возврат в качестве последнего оператора функции.
источник
return result
разбросаны по нему, а затем думают, что теперь хотят сделать еще одну проверку найденного,result
прежде чем возвращать его, и это всего лишь пример). Могут быть и минусы, но такое широкое утверждение, как «В общем, нет веских причин иметь только один возврат» не выдерживает критики.Может быть, это признак того, что вам следует переписать свой код. Например:
источник
Методы, которые имеют оператор возврата и внутри них цикл / циклы, всегда требуют оператора возврата вне цикла (ов). Даже если этот оператор вне цикла никогда не достигается. В таких случаях, чтобы избежать ненужных операторов возврата, вы можете определить переменную соответствующего типа, целое число в вашем случае, в начале метода, то есть до и за пределами соответствующего цикла (ов). Когда желаемый результат внутри цикла будет достигнут, вы можете присвоить соответствующее значение этой предопределенной переменной и использовать его для оператора возврата вне цикла.
Поскольку вы хотите, чтобы ваш метод возвращал первый результат, когда rInt [i] равняется rInt [count], реализации только вышеупомянутой переменной недостаточно, потому что метод вернет последний результат, когда rInt [i] равно rInt [count]. Один из вариантов - реализовать два «оператора прерывания», которые вызываются, когда мы получаем желаемый результат. Итак, метод будет выглядеть примерно так:
источник
Я согласен с тем, что следует генерировать исключение при возникновении недостижимого оператора. Просто хотел показать, как тот же метод может сделать это более читаемым (требуются потоки java 8).
источник
источник
result == -1
проверок , которые могут быть опущены сreturn
внутренней стороны петли ...