switch - ejercicios do while java netbeans
¿Los bucles "while(verdadero)" son tan malos? (21)
1) Nada está mal con un do -while(true)
2) Tu maestro está equivocado.
NSFS !!:
3) La mayoría de los maestros son maestros y no programadores.
He estado programando en Java desde hace varios años, pero recientemente regresé a la escuela para obtener un título formal. Me sorprendió bastante saber que, en mi última tarea, perdí puntos por usar un bucle como el que se muestra a continuación.
do{
//get some input.
//if the input meets my conditions, break;
//Otherwise ask again.
} while(true)
Ahora, para mi prueba, solo estoy buscando información de la consola, pero me dijeron que este tipo de bucle no se recomienda porque el uso de break
es similar a goto
, simplemente no lo hacemos.
Entiendo completamente las trampas de goto
y su primo Java break:label
, y tengo el buen sentido de no usarlas. También me doy cuenta de que un programa más completo brindaría otros medios de escape, por ejemplo, para finalizar el programa, pero esa no fue una razón que mi profesor mencionó, así que ...
¿Qué hay de malo con do-while(true)
?
AFAIK nada, la verdad. Los maestros son alérgicos al goto
, porque escucharon que en algún lugar es realmente malo. De lo contrario usted acaba de escribir:
bool guard = true;
do
{
getInput();
if (something)
guard = false;
} while (guard)
Que es casi lo mismo.
Quizás esto sea más limpio (porque toda la información de bucle está contenida en la parte superior del bloque):
for (bool endLoop = false; !endLoop;)
{
}
Creo que sí, es bastante malo ... o al menos, para muchos desarrolladores. Es sintomático de los desarrolladores que no piensan en sus condiciones de bucle. En consecuencia hay error propenso.
De acuerdo con mi experiencia en la mayoría de los casos, los bucles tienen la condición "principal" para continuar. Esta es la condición que debe escribirse en el operador while (). Todas las demás condiciones que pueden romper el ciclo son secundarias, no son tan importantes, etc. Se pueden escribir como instrucciones adicionales if() {break}
.
while(true)
es a menudo confuso y es menos legible.
Creo que estas reglas no cubren el 100% de los casos, pero probablemente solo el 98% de ellos.
Diría que, en general, la razón por la que no se considera una buena idea es que no está utilizando el constructo en todo su potencial. Además, tiendo a pensar que a muchos instructores de programación no les gusta cuando sus estudiantes vienen con "equipaje". Con eso quiero decir, creo que les gusta ser la principal influencia en el estilo de programación de sus estudiantes. Así que tal vez sea solo un motivo favorito de los instructores.
Douglas Crockford hizo un comentario sobre cómo deseaba que JavaScript contuviera una estructura de loop
:
loop
{
...code...
}
Y tampoco creo que Java sea peor por tener una estructura de loop
.
No hay nada intrínsecamente malo en los bucles while(true)
, pero hay una tendencia a que los maestros los desalienten. Desde la perspectiva de la enseñanza, es muy fácil hacer que los estudiantes creen bucles interminables y no entiendan por qué nunca se escapó el bucle.
Pero lo que rara vez mencionan es que todos los mecanismos de bucle se pueden replicar con bucles while(true)
.
while( a() )
{
fn();
}
es lo mismo que
loop
{
if ( !a() ) break;
fn();
}
y
do
{
fn();
} while( a() );
es lo mismo que:
loop
{
fn();
if ( !a() ) break;
}
y
for ( a(); b(); c() )
{
fn();
}
es lo mismo que:
a();
loop
{
if ( !b() ) break;
fn();
c();
}
Mientras pueda configurar sus bucles de una manera que funcione, la construcción que elija utilizar no es importante. Si sucede que encaja en un bucle for
, use un bucle for
.
Una última parte: mantén tus bucles simples. Si hay muchas funciones que deben suceder en cada iteración, colóquela en una función. Siempre puedes optimizarlo después de que lo tengas funcionando.
En 1967, Dijkstra escribió un artículo en una revista comercial sobre por qué debería eliminarse goto de los idiomas de alto nivel para mejorar la calidad del código. Todo un paradigma de programación llamado "programación estructurada" surgió de esto, aunque ciertamente no todos están de acuerdo en que goto significa automáticamente código malo. El quid de la programación estructurada es esencialmente que la estructura del código debe determinar su flujo en lugar de tener gotos o interrupciones o continúa determinando el flujo, siempre que sea posible. De manera similar, tener múltiples puntos de entrada y salida a un bucle o función también se desaconseja en ese paradigma. Obviamente, este no es el único paradigma de programación, pero a menudo se puede aplicar fácilmente a otros paradigmas como la programación orientada a objetos (ala Java). Es probable que sus maestros hayan sido enseñados, y está tratando de enseñarle a su clase que deberíamos evitar el "código spaghetti" asegurándonos de que nuestro código esté estructurado y siguiendo las reglas implícitas de la programación estructurada. Si bien no hay nada intrínsecamente "incorrecto" con una implementación que usa break, algunos consideran que es mucho más fácil leer el código donde la condición para el bucle se especifica explícitamente dentro de la condición while (), y elimina algunas posibilidades de ser demasiado complicado. Definitivamente, existen fallas en el uso de una condición de tiempo (verdadero) que parece aparecer con frecuencia en el código de los programadores novatos, como el riesgo de crear accidentalmente un bucle infinito, o hacer que el código sea difícil de leer o confunda innecesariamente.
Irónicamente, el manejo de excepciones es un área donde la desviación de la programación estructurada surgirá y se esperará a medida que avanza en la programación en Java.
También es posible que su instructor haya esperado que usted demuestre su capacidad para usar una estructura de bucle particular o la sintaxis que se enseña en ese capítulo o lección de su texto, y si bien el código que escribió es funcionalmente equivalente, es posible que no haya demostrado el habilidad particular que se suponía que estabas aprendiendo en esa lección.
Es más una cuestión estética, mucho más fácil de leer, donde explícitamente sabes por qué el bucle se detendrá en la declaración del bucle.
Es malo en el sentido de que las construcciones de programación estructurada son preferibles a las declaraciones de ruptura y continuación (algo desestructuradas). Son, en comparación, preferidos a "goto" de acuerdo con este principio.
Siempre recomiendo que tu código sea lo más estructurado posible ... aunque, como señala Jon Skeet, ¡no lo hagas más estructurado que eso!
Es tu arma, tu bala y tu pie ...
Es malo porque estás pidiendo problemas. No será usted ni ninguno de los otros pósters en esta página que tengan ejemplos de bucles while cortos / simples.
El problema comenzará en un momento muy aleatorio en el futuro. Puede ser causado por otro programador. Podría ser la persona que instala el software. Puede ser que sea el usuario final.
¿Por qué? Tuve que descubrir por qué una aplicación 700K LOC comenzaría a grabar gradualmente el 100% del tiempo de CPU hasta que se saturara cada CPU. Fue un bucle asombroso mientras (verdadero). Era grande y desagradable pero se reducía a:
x = read_value_from_database()
while (true)
if (x == 1)
...
break;
else if (x ==2)
...
break;
and lots more else if conditions
}
No había ninguna rama else final. Si el valor no coincidía con una condición if, el bucle continuaba ejecutándose hasta el final del tiempo.
Por supuesto, el programador culpó a los usuarios finales por no elegir un valor que el programador esperaba. (Luego eliminé todas las instancias de while (verdadero) en el código).
En mi humilde opinión no es una buena programación defensiva usar constructos como while (verdadero). Volverá para atormentarte.
(Pero sí recuerdo que los profesores calificaron si no comentamos todas las líneas, incluso para i ++;)
La convención de usus de Java para leer entrada es:
import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String strLine;
while ((strLine = br.readLine()) != null) {
// do something with the line
}
Y la convención habitual de C ++ para leer la entrada es:
#include <iostream>
#include <string>
std::string data;
while(std::readline(std::cin, data)) {
// do something with the line
}
Y en C, que es
#include <stdio.h>
char* buffer = NULL;
size_t buffer_size;
size_t size_read;
while( (size_read = getline(&buffer, &buffer_size, stdin)) != -1 ){
// do something with the line
}
free(buffer);
o si está convencido de que sabe cuánto tiempo dura la línea de texto más larga en su archivo, puede hacerlo
#include <stdio.h>
char buffer[BUF_SIZE];
while (fgets(buffer, BUF_SIZE, stdin)) {
//do something with the line
}
Si está realizando pruebas para ver si su usuario ingresó un comando para quit
, es fácil extender cualquiera de estas 3 estructuras de bucle. Lo haré en Java por ti:
import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null && !line.equals("quit") ) {
// do something with the line
}
Entonces, si bien hay casos en los que se justifica break
o goto
, si todo lo que está haciendo es leer un archivo o la consola línea por línea, no debería necesitar un ciclo de while (true)
para lograrlo: su el lenguaje de programación ya le ha proporcionado un idioma apropiado para usar el comando de entrada como condición de bucle.
No diría que es malo , pero igualmente, al menos normalmente buscaría una alternativa.
En situaciones en las que es lo primero que escribo, casi siempre trato de reformularlo para que sea más claro. A veces no se puede evitar (o la alternativa es tener una variable bool
que no haga nada significativo excepto indicar el final del bucle, menos claramente que una declaración de break
), pero vale la pena intentarlo.
Como ejemplo de dónde es más claro usar break
que una bandera, considere:
while (true)
{
doStuffNeededAtStartOfLoop();
int input = getSomeInput();
if (testCondition(input))
{
break;
}
actOnInput(input);
}
Ahora vamos a forzarlo a usar una bandera:
boolean running = true;
while (running)
{
doStuffNeededAtStartOfLoop();
int input = getSomeInput();
if (testCondition(input))
{
running = false;
}
else
{
actOnInput(input);
}
}
Considero que esto último es más complicado de leer: tiene un bloque adicional, el actOnInput
está más sangrado, y si está tratando de averiguar qué sucede cuando testCondition
devuelve true
, debe mirar detenidamente el resto del bloque. para comprobar que no hay nada después del bloque else
que ocurriría si la running
se ha establecido en false
o no.
La declaración de break
comunica el intento con mayor claridad y permite que el resto del bloque continúe con lo que necesita hacer sin preocuparse por las condiciones anteriores.
Tenga en cuenta que este es exactamente el mismo tipo de argumento que las personas tienen sobre varias declaraciones de devolución en un método. Por ejemplo, si puedo calcular el resultado de un método dentro de las primeras líneas (por ejemplo, porque algunas entradas son nulas, vacías o cero), me parece más claro devolver esa respuesta directamente que tener una variable para almacenar el resultado , luego un bloque completo de otro código, y finalmente una declaración de return
.
No es una cosa tan terrible, pero debes tener en cuenta a otros desarrolladores al programar. Incluso en la escuela.
Sus compañeros desarrolladores deberían poder ver la cláusula de salida de su bucle en la declaración de bucle. Usted no hizo eso. Ocultó la cláusula de salida en el medio del bucle, haciendo más trabajo para otra persona que se presente e intente entender su código. Esta es la misma razón por la que se evitan cosas como "romper".
Dicho esto, aún verás cosas como esta en MUCHO código en el mundo real.
No hay ningún problema importante con while(true)
con declaraciones de break
, sin embargo, algunos pueden pensar que reduce ligeramente la legibilidad del código. Trate de dar nombres significativos a las variables, evalúe expresiones en el lugar adecuado.
Para su ejemplo, parece mucho más claro hacer algo como:
do {
input = get_input();
valid = check_input_validity(input);
} while(! valid)
Esto es especialmente cierto si el bucle do while se alarga: usted sabe exactamente dónde está ocurriendo la comprobación para ver si hay una iteración adicional. Todas las variables / funciones tienen nombres apropiados en el nivel de abstracción. La sentencia while(true)
hace es decirle que el procesamiento no está en el lugar que usted pensó.
Tal vez desee una salida diferente en la segunda vez a través del bucle. Algo como
input = get_input();
while(input_is_not_valid(input)) {
disp_msg_invalid_input();
input = get_input();
}
Me parece más legible entonces.
do {
input = get_input();
if (input_is_valid(input)) {
break;
}
disp_msg_invalid_input();
} while(true);
De nuevo, con un ejemplo trivial ambos son bastante legibles; pero si el bucle se hizo muy grande o estaba profundamente anidado (lo que significa que probablemente ya debería haberlo refaccionado), el primer estilo puede ser un poco más claro.
Para mí, el problema es la legibilidad.
Una sentencia while con una condición verdadera no le dice nada sobre el bucle. Hace que el trabajo de entenderlo sea mucho más difícil.
¿Qué sería más fácil de entender de estos dos fragmentos?
do {
// Imagine a nice chunk of code here
} while(true);
do {
// Imagine a nice chunk of code here
} while(price < priceAllowedForDiscount);
Podría ser malo si su bucle se ejecuta en un subproceso en segundo plano, por lo que cuando cierre su aplicación terminando un subproceso de la interfaz de usuario, ese fragmento de código continuará ejecutándose. Como ya han dicho otros, siempre debe usar algún tipo de cheque para proporcionar una forma de cancelación.
Puede usar una bandera booleana para indicar cuándo finalizar el ciclo while. Break
e go to
eran razones por las que el software era difícil de mantener (la crisis del software (tm)), y debería evitarse, y fácilmente puede serlo también.
Es una pregunta si eres pragmático o no. Los codificadores pragmáticos podrían simplemente usar break en esa simple situación.
Pero es bueno tener el hábito de no usarlos, de lo contrario, podría usarlos fuera de habbit en situaciones inadecuadas, como en complicados bucles anidados donde la legibilidad y el mantenimiento de su código se vuelven más difíciles al usar break
.
Si bien no es necesariamente una respuesta sobre por qué no usar while (true)
, siempre he encontrado que esta declaración cómica y de acompañamiento del autor es una explicación sucinta de por qué hacer mientras que en lugar de hacerlo.
Con respecto a su pregunta: No hay problema inherente con
while(true) {
do_stuff();
if(exit_time) {
break;
}
}
... si sabes lo que estás haciendo y asegúrate de que exit_time
en algún momento se evalúe como true
.
Los maestros lo desalientan de usar while(true)
porque hasta que, a menos que esté en el punto en que sepa exactamente lo que está haciendo, es una manera fácil de cometer un error crítico.
Supongo que usar un descanso para tu maestro es como romper una rama de un árbol para obtener la fruta, usa algunos otros trucos (inclinar la rama) para que obtengas la fruta y la rama aún esté viva. :)
Tal vez tenga mala suerte. O tal vez solo me falta una experiencia. Pero cada vez que recuerdo haber tenido break
internas while(true)
, fue posible mejorar el código aplicando el Método de extracción al bloque while , que mantuvo el while(true)
pero (¿por coincidencia?) Transformó todas las break
en return
s.
En mi experiencia, while(true)
sin descansos (es decir, con devoluciones o lanzamientos) son bastante cómodos y fáciles de entender.
void handleInput() {
while (true) {
final Input input = getSomeInput();
if (input == null) {
throw new BadInputException("can''t handle null input");
}
if (input.isPoisonPill()) {
return;
}
doSomething(input);
}
}
Uso algo similar, pero con lógica opuesta, en muchas de mis funciones.
DWORD dwError = ERROR_SUCCESS;
do
{
if ( (dwError = SomeFunction()) != ERROR_SUCCESS )
{
/* handle error */
continue;
}
if ( (dwError = SomeOtherFunction()) != ERROR_SUCCESS )
{
/* handle error */
continue;
}
}
while ( 0 );
if ( dwError != ERROR_SUCCESS )
{
/* resource cleanup */
}