Tengo una situación en la que siempre se alcanzará la return
declaración anidada en dos for
bucles, en teoría.
El compilador no está de acuerdo y requiere una return
declaración fuera del for
ciclo. Me gustaría conocer una forma elegante de optimizar este método que está más allá de mi comprensión actual, y ninguna de mis implementaciones de ruptura intentadas parece funcionar.
Attached es un método de una asignación que genera enteros aleatorios y devuelve las iteraciones recorridas hasta que se encuentra un segundo entero aleatorio, generado dentro de un rango pasado al método como un parámetro 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)
bucle en lugar de un bucle indexado. Esto le dice al compilador que el bucle nunca regresará.oneRun(0)
) y verá que rápidamente alcanza su inalcanzablereturn
nextInt
arroja una excepción pararange < 0
El único caso en el que se alcanza el retorno es cuandorange == 0
Respuestas:
La heurística del compilador nunca le permitirá omitir la última
return
. Si está seguro de que nunca se alcanzará, lo reemplazaría con unthrow
para aclarar la situación.fuente
throw new AssertionError("\"unreachable\" code reached");
throw
que nunca se alcanzará. Con demasiada frecuencia, la gente solo quiere aplicar rápidamente "una solución para gobernarlos a todos" sin pensar demasiado en el problema subyacente. Pero programar es mucho más que codificar. Especialmente cuando se trata de algoritmos. Si inspecciona (cuidadosamente) el problema dado, se dará cuenta de que puede factorizar la última iteración delfor
bucle externo y, por lo tanto, reemplazar el retorno "inútil" por uno útil (consulte esta respuesta ).Como señaló @BoristheSpider, puede asegurarse de que la segunda
return
declaración sea semánticamente inalcanzable:Se compila y funciona bien. Y si alguna vez obtiene un
ArrayIndexOutOfBoundsException
, sabrá que la implementación fue semánticamente incorrecta, sin tener que arrojar nada explícitamente.fuente
for(int count = 0; true; count++)
lugar.true
:for(int count = 0; ; count++) …
while(true)
, pensé que quizás Java sea un poco más estricto en este sentido. Es bueno saber que no hay necesidad de preocuparse ... En realidad, me gustatrue
mucho más la versión omitida : deja visualmente claro que no hay absolutamente ninguna condición para mirar :-)Como preguntaste sobre cómo romper dos
for
bucles, puedes usar una etiqueta para hacerlo (mira el ejemplo a continuación):fuente
returnValue
se puede usar sin inicializar?Mientras que una aserción es una buena solución rápida. En general, este tipo de problemas significa que su código es demasiado complicado. Cuando miro su código, es obvio que realmente no desea que una matriz contenga números anteriores. Quieres un
Set
:Ahora tenga en cuenta que lo que estamos devolviendo es en realidad el tamaño del conjunto. La complejidad del código ha disminuido de cuadrática a lineal y es inmediatamente más legible.
Ahora podemos darnos cuenta de que ni siquiera necesitamos ese
count
índice:fuente
Como su valor de retorno se basa en la variable del ciclo externo, simplemente puede alterar la condición del ciclo externo
count < range
y luego devolver este último valor (que acaba de omitir) al final de la función:De esta forma, no es necesario introducir un código que nunca se alcanzará.
fuente
...
) pero el bucle exterior se ha reducido en su última iteración. El caso correspondiente a esta última iteración es manejado por separado por la última declaración de retorno. Aunque esta es una solución elegante para su ejemplo, hay escenarios en los que este enfoque se vuelve más difícil de leer; si, por ejemplo, el valor de retorno dependiera del ciclo interno, entonces, en lugar de una declaración de retorno única al final, se quedaría con un ciclo adicional (que representa el ciclo interno para la última iteración del ciclo externo).Utilice una variable temporal, por ejemplo, "resultado", y elimine el retorno interno. Cambie el bucle for por un bucle while con la condición adecuada. Para mí, siempre es más elegante tener solo un retorno como última declaración de la función.
fuente
return result
esparcieron dentro de él y luego piensan en querer hacer una verificación más en el encontradoresult
antes de devolverlo, y esto es solo un ejemplo). También puede haber contras, pero una afirmación tan amplia como "En general, no hay una buena razón para tener una sola devolución" no es válida.Tal vez esto sea una indicación de que debería reescribir su código. Por ejemplo:
fuente
Los métodos que tienen una declaración de retorno y tienen un bucle / bucles dentro de ellos siempre requieren una declaración de devolución fuera del bucle (s). Incluso si esta declaración fuera del ciclo nunca se alcanza. En tales casos, para evitar declaraciones de retorno innecesarias, puede definir una variable del tipo respectivo, un entero en su caso, al comienzo del método, es decir, antes y fuera de los bucles respectivos. Cuando se alcanza el resultado deseado dentro del ciclo, puede atribuir el valor respectivo a esta variable predefinida y usarlo para la declaración de retorno fuera del ciclo.
Como desea que su método devuelva el primer resultado cuando rInt [i] es igual a rInt [count], implementar solo la variable mencionada anteriormente no es suficiente porque el método devolverá el último resultado cuando rInt [i] es igual a rInt [count]. Una opción es implementar dos "sentencias de interrupción" que se llaman cuando tenemos el resultado deseado. Entonces, el método se verá así:
fuente
Estoy de acuerdo en que se debería lanzar una excepción cuando ocurra una declaración inalcanzable. Solo quería mostrar cómo el mismo método puede hacer esto de una manera más legible (se requieren secuencias de Java 8).
fuente
fuente
result == -1
controles que se pueden omitir con elreturn
interior del bucle ...