A veces necesito bucles que necesitan un descanso como este:
for(int i=0;i<array.length;i++){
//some other code
if(condition){
break;
}
}
Me siento incómodo escribiendo
if(condition){
break;
}
porque consume 3 líneas de código. Y descubrí que el bucle se puede reescribir como:
↓
for(int i=0;i<array.length && !condition;i++){
//some other code
}
Entonces mi pregunta es, ¿es una buena práctica mover la condición al campo de condición para reducir líneas de códigos si es posible?
coding-style
loops
ocomfd
fuente
fuente

conditionen particular.for(int i=0;i<array.length && !condition;i++)es relativamente poco común y puede ser pasado por alto por alguien que solo está leyendo el código; Este podría ser un buen caso de uso para un buclewhileodo while, que a menudo tiene múltiples condiciones de interrupción en la definición del bucle.Respuestas:
Esos dos ejemplos que dio no son funcionalmente equivalentes. En el original, la prueba de condición se realiza después de la sección "algún otro código", mientras que en la versión modificada, se realiza primero, al comienzo del cuerpo del bucle.
El código nunca debe reescribirse con el único propósito de reducir el número de líneas. Obviamente, es un buen bono cuando funciona de esa manera, pero nunca debe hacerse a expensas de la legibilidad o corrección.
fuente
No compro el argumento de que "consume 3 líneas de código" y, por lo tanto, es malo. Después de todo, podrías escribirlo como:
y solo consume una línea.
Si
ifaparece a la mitad del ciclo, por supuesto tiene que existir como una prueba separada. Sin embargo, si esta prueba aparece al final del bloque, ha creado un bucle que tiene una prueba continua en ambos extremos del bucle, posiblemente aumentando la complejidad del código. Sin embargo, tenga en cuenta que a veces laif (condition)prueba solo puede tener sentido después de que se haya ejecutado el bloque.Pero suponiendo que ese no sea el caso, adoptando el otro enfoque:
las condiciones de salida se mantienen juntas, lo que puede simplificar las cosas (especialmente si " algún otro código " es largo).
No hay una respuesta correcta aquí, por supuesto. Por lo tanto, tenga en cuenta las expresiones idiomáticas del idioma, cuáles son las convenciones de codificación de su equipo, etc. Pero, en general, adoptaría el enfoque de prueba única cuando tenga sentido funcional hacerlo.
fuente
Este tipo de pregunta ha provocado un debate casi tan largo como la programación. Para lanzar mi sombrero al ring, iría por la versión con la
breakcondición y he aquí por qué (para este caso específico ):El
forbucle está allí para especificar los valores de iteración en el bucle. Codificar la condición de ruptura dentro de eso solo enturbia la lógica de la OMI.Tener un elemento separado
breakdeja en claro que durante el procesamiento normal, los valores son los especificados en elforbucle y el procesamiento debe continuar, excepto donde entra la condición.Como antecedentes, comencé a codificar a
break, luego puse la condición en elforbucle durante años (bajo la dirección de un programador excepcional) y luego volví albreakestilo porque se sentía mucho más limpio (y era el estilo predominante en los diversos tomos de código que estaba consumiendo).Es otra de esas guerras santas al final del día: algunos dicen que nunca debes salir de un ciclo artificialmente, de lo contrario no es un ciclo real. Haz lo que sientas que es legible (tanto para ti como para los demás). Si lo tuyo es reducir las pulsaciones de teclas, practica golf de código los fines de semana: cerveza opcional.
fuente
forbucles se usan cuando se conoce el número de iteraciones (por ejemplo, cuando no hay una condición de interrupción pero el final de la matriz / lista) ywhilecuando no. Este parece ser el caso de unwhilebucle. Si la legibilidad es la preocupación,idx+=1es mucho más limpio leer dentro de un bucle que unif/elsebloquefor(int i=0; i<something;i++)bucles que supongo que la mitad de los desarrolladores realmente no recuerdan que losforbucles se pueden usar de manera diferente y, por lo tanto, tienen dificultades para comprender la&&conditionparte.for(;;)...forlos bucles son para la iteración sobre algo 1 : no son solo lol-vamos a sacar algunas cosas al azar del cuerpo y ponerlas en el encabezado del bucle: las tres expresiones tienen muy significados específicos:La idea es separar el manejo de la iteración ( cómo iterar) de la lógica dentro del bucle ( qué hacer en cada iteración). Muchos idiomas generalmente tienen un ciclo para cada uno que lo libera de los detalles de la iteración, pero incluso si su idioma no tiene esa construcción, o si no se puede usar en su escenario, aún debe limitar el encabezado del ciclo a la iteración de manejo.
Entonces, debe preguntarse: ¿es su condición sobre el manejo de la iteración o sobre la lógica dentro del bucle? Lo más probable es que se trata de la lógica dentro del bucle, por lo que debe verificarse dentro del bucle en lugar de en el encabezado.
1 A diferencia de otros bucles, que están "esperando" que algo suceda. Un
for/foreachloop debe tener el concepto de una "lista" de elementos para iterar, incluso si esa lista es perezosa o infinita o abstracta.fuente
someFunction(array[i]). Ahora ambas partes de la condición son sobre lo que estás iterando, y tendría sentido combinarlas con&&el encabezado del bucle.forbucles en el fondo son contadores, no bucles en una lista, y esto es compatible con la sintaxis deforlos idiomas anteriores (estos idiomas a menudo tenían unafor i = 1 to 10 step 2sintaxis y elstepcomando, incluso permitiendo un valor inicial que no es el índice del primero elemento: insinúa un contexto numérico, no un contexto de lista). El único caso de uso que creo que admiteforbucles, ya que solo iterar sobre una lista es paralelizar, y eso requiere una sintaxis explícita ahora de todos modos para no romper el código haciendo, por ejemplo, una ordenación.Recomiendo usar la versión con
if (condition). Es más legible y más fácil de depurar. Escribir 3 líneas adicionales de código no te romperá los dedos, pero facilitará que la siguiente persona entienda tu código.fuente
naming thingspara entender lo que está sucediendo y cuándo se cumple la condición de ruptura.Si está iterando sobre una colección donde se deben omitir ciertos elementos, le recomiendo una nueva opción:
Tanto Java como C # hacen que esto sea relativamente trivial. No me sorprendería si C ++ tuviera una forma de hacer un iterador elegante para omitir ciertos elementos que no se aplican. Pero esta es realmente una opción si su idioma de elección lo admite, y la razón por la que está utilizando
breakes porque hay condiciones sobre si procesa un elemento o no.De lo contrario, hay una muy buena razón para que su condición forme parte del ciclo for, suponiendo que su evaluación inicial sea correcta.
He trabajado en el código donde su bucle for toma unos cientos de líneas con varios condicionales y algunas matemáticas complejas que están sucediendo allí. Los problemas que encuentra con esto son:
breaklos comandos enterrados en la lógica son difíciles de encontrar y a veces sorprendentesEn esa situación, recomiendo las siguientes pautas en orden de preferencia:
breakposiblebreaken la parte superior del bucle si es posibleEstas pautas siempre están sujetas a la corrección de su código. Elija la opción que mejor represente la intención y mejore la claridad de su código.
fuente
continuedeclaraciones, pero no veo cómo ayudan muchobreak.takeWhilefiltro puede reemplazarbreakdeclaraciones. Si tiene uno, Java, por ejemplo, solo los obtiene en Jave 9 (no es que sea tan difícil implementarlo usted mismo)Recomiendo encarecidamente adoptar el enfoque de menor sorpresa a menos que obtenga un beneficio significativo al hacer lo contrario.
Las personas no leen todas las letras cuando leen una palabra, y no leen todas las palabras cuando leen un libro; si son expertos en la lectura, miran los contornos de las palabras y oraciones y dejan que su cerebro complete el resto .
Entonces, es probable que el desarrollador ocasional suponga que esto es solo un estándar para el bucle y ni siquiera lo mire:
Si quiere usar ese estilo independientemente, le recomiendo cambiar las partes
for(int i=0;i<y;i++)que le digan al cerebro del lector que este es un estándar para el bucle.Otra razón para ir con
if-breakes que no siempre se puede utilizar el enfoque con elforinnecesaria cualquier condición. Usted tiene que utilizarif-breakcuando la condición de rotura es demasiado complejo para ocultar dentro de unafordeclaración, o se basa en variables que sólo se puede acceder en el interior delforbucle.Así que si usted decide ir con
if-break, que está cubierto. Pero si usted decide ir confor-condiciones, usted tiene que utilizar una mezcla deif-breakyfor-condiciones. Para ser coherente, que tendrá que mover las condiciones de ida y vuelta entre lasfor-condiciones yif-breakcada vez que cambian las condiciones.fuente
Su transformación está asumiendo que todo lo que
conditionse evalúa atruemedida que ingresa al bucle. No podemos comentar la corrección de eso en este caso porque no está definido.Después de tener éxito en "reducir las líneas de código" aquí, puede continuar mirando
y aplicar la misma transformación, llegando a
Lo cual es una transformación no válida, como ahora haces incondicionalmente
further codedonde antes no lo hacías.Un esquema de transformación mucho más seguro es extraer
some other codey evaluarconditionuna función separadafuente
TL; DR Haz lo que se lea mejor en tu circunstancia particular
Tomemos este ejemplo:
En este caso, no queremos que se ejecute ninguno de los códigos del bucle for si
somethinges verdadero, por lo quesomethinges razonable mover la prueba al campo de condición.Por otra parte, dependiendo de si
somethingse puede establecertrueantes del ciclo, pero no dentro de él, esto podría ofrecer más claridad:Ahora imagina esto:
Estamos enviando un mensaje muy claro allí. Si
somethingse cumple mientras se procesa la matriz, abandone toda la operación en este punto. Para mover el cheque al campo de condición que necesita hacer:Podría decirse que el "mensaje" se ha enlodado, y estamos verificando la condición de falla en dos lugares: ¿qué sucede si la condición de falla cambia y olvidamos uno de esos lugares?
Por supuesto, hay muchas más formas diferentes para un bucle y una condición, todas con sus propios matices.
Escriba el código para que se lea bien (esto es obviamente algo subjetivo) y de manera concisa. Fuera de un conjunto draconiano de pautas de codificación, todas las "reglas" tienen excepciones. Escriba lo que siente que expresa mejor la toma de decisiones y minimice las posibilidades de errores futuros.
fuente
Si bien puede ser atractivo porque ve todas las condiciones en el encabezado del bucle y
breakpuede ser confuso dentro de bloques grandes, unforbucle es un patrón en el que la mayoría de los programadores esperan bucles en algún rango.Especialmente porque lo hace, agregar una condición de descanso adicional puede causar confusión y es más difícil ver si es funcionalmente equivalente.
A menudo, una buena alternativa es usar un bucle
whileodo {} whileque verifique ambas condiciones, suponiendo que su matriz tenga al menos un elemento.Al usar un bucle que solo verifica una condición y no ejecuta código desde el encabezado del bucle, deja muy claro cuándo se verifica la condición y cuál es la condición real y cuál es el código con efectos secundarios.
fuente
for(...; i <= n; ...)) hace que el código sea más difícil de leer porque tengo detenerse y pensar en lo que está sucediendo aquí y podría pasar por alto la condición en la primera pasada porque no espero que esté allí. Para mí, unforbucle implica que está recorriendo un rango, si hay una condición de salida especial, debe hacerse explícito con unif, o puede usar awhile.Esto es malo, ya que el código está destinado a ser leído por humanos: los
forbucles no idiomáticos a menudo son confusos de leer, lo que significa que es más probable que los errores se escondan aquí, pero el código original pudo haber sido posible mientras se mantenía ambos Corto y legible.Si lo que desea es encontrar un valor en una matriz (el ejemplo de código proporcionado es algo genérico, pero también puede ser este patrón), puede intentar explícitamente utilizar una función proporcionada por un lenguaje de programación específicamente para ese propósito. Por ejemplo (pseudocódigo, como no se especificó un lenguaje de programación, las soluciones varían según un lenguaje en particular).
Esto debería acortar notablemente la solución y simplificarla, ya que su código dice específicamente lo que necesita.
fuente
Pocas razones en mi opinión que dice, no deberías.
do...whilebucle (nowhile) ya que la condición se verifica después de una ejecución de código.Pero además de eso, considera esto,
Ahora, ¿realmente puedes lograrlo agregando estas condiciones a esa
forcondición?fuente
Creo que eliminarlo
breakpuede ser una buena idea, pero no para guardar líneas de código.La ventaja de escribir sin él
breakes que la condición posterior del bucle es obvia y explícita. Cuando finaliza el ciclo y ejecuta la siguiente línea del programa, su condición de cicloi < array.length && !conditiondebe haber sido falsa. Por lo tanto,iera mayor o igual que la longitud de su matriz, oconditiones cierto.En la versión con
break, hay una trampa oculta. La condición del bucle dice que el bucle termina cuando ha ejecutado algún otro código para cada índice de matriz válido, pero de hecho hay unabreakdeclaración que podría terminar el bucle antes de eso, y no lo verá a menos que revise el código del bucle. muy cuidadosamente. Y los analizadores estáticos automáticos, incluida la optimización de compiladores, también podrían tener problemas para deducir cuáles son las condiciones posteriores del bucle.Esta fue la razón original por la que Edgar Dijkstra escribió "Goto Considerado Dañino". No fue una cuestión de estilo: romper un círculo hace que sea difícil razonar formalmente sobre el estado del programa. He escrito muchas
break;declaraciones en mi vida, y una vez como adulto, incluso escribí ungoto(para salir de múltiples niveles de un ciclo interno crítico para el rendimiento y luego continuar con otra rama del árbol de búsqueda). Sin embargo, es mucho más probable que escriba unareturndeclaración condicional desde un bucle (que nunca ejecuta el código después del bucle y, por lo tanto, no puede acumular sus condiciones posteriores) que abreak.Posdata
De hecho, refactorizar el código para dar el mismo comportamiento podría necesitar más líneas de código. Su refactorización podría ser válida para algún otro código en particular o si podemos demostrar que
conditioncomenzará en falso. Pero su ejemplo es equivalente en el caso general a:Si algún otro código no es de una sola línea, puede moverlo a una función para que no se repita, y casi ha refactorizado su bucle en una función recursiva de cola.
Sin embargo, reconozco que este no era el punto principal de su pregunta, y lo mantenía simple.
fuente
breakdeclaración, entonces sabes cuál es la condición del bucle y que el bucle se detiene cuando esa condición es falsa. Si hay unbreak? Luego, hay varias formas en que el ciclo podría terminar, y en el caso general, descubrir cuándo una de ellas podría detener el ciclo es, literalmente, resolver el problema de detención. En la práctica, mi mayor preocupación es que el bucle parece que hace una cosa, pero en realidad, quien escribió el código después del bucle pasó por alto un caso marginal oculto en su lógica compleja. Las cosas en la condición de bucle son difíciles de perder.Sí, pero su sintaxis no es convencional y, por lo tanto, es mala (tm)
Esperemos que tu idioma sea compatible con algo como
fuente
whileenfatiza el monstruo en el código, la excepción oculta en el código de rutina / mundano. La lógica de negocios es frontal y central, la mecánica de bucle está subsumida. Evita la reacción de "espera un minuto ..." a laforalternativa del bucle. Esta respuesta soluciona el problema. Absolutamente voto.Si le preocupa que una
fordeclaración demasiado compleja sea difícil de leer, definitivamente es una preocupación válida. El desperdicio de espacio vertical también es un problema (aunque menos crítico).(Personalmente, no me gusta la regla de que las
ifdeclaraciones siempre deben tener llaves, que es en gran parte la causa del desperdicio de espacio vertical aquí. Tenga en cuenta que el problema es desperdiciar espacio vertical. Usar espacio vertical con líneas significativas no debería ser un problema).Una opción es dividirlo en varias líneas. Esto es definitivamente lo que debe hacer si está usando
fordeclaraciones realmente complejas , con múltiples variables y condiciones. (Esto es para mí un mejor uso del espacio vertical, dando tantas líneas como sea posible algo significativo).Un mejor enfoque podría ser tratar de usar una forma más declarativa y menos imperativa. Esto variará según el idioma, o puede que necesite escribir sus propias funciones para habilitar este tipo de cosas. También depende de lo que
conditionrealmente es. Presumiblemente, debe poder cambiar de alguna manera, dependiendo de lo que esté en la matriz.fuente
fordeclaración compleja o inusual en varias líneas es la mejor idea en toda esta discusiónUna cosa que se olvidó: cuando rompo un bucle (no hago todas las iteraciones posibles, sin importar cómo se implemente), generalmente es el caso de que no solo quiero salir del bucle, también querré saber por qué sucedió esto . Por ejemplo, si busco un elemento X, no solo rompo el ciclo, también quiero saber si se encontró X y dónde está.
En esa situación, tener una condición fuera del circuito es bastante natural. Entonces empiezo con
y en el bucle escribiré
con el bucle for
Ahora comprobar la condición en el bucle es bastante natural. Si hay una declaración de "interrupción" depende de si hay más procesamiento en el ciclo que desea evitar. Si se necesita algún procesamiento y otro no, es posible que tenga algo como
en algún lugar de tu circuito.
fuente