2010-08-18 8 views
17

Soy un estudiante de informática, por lo tanto, no sé mucho.¿Diferentes estilos de flujo de programa?

Hace poco estuve hablando con un amigo que acaba de conseguir un trabajo como desarrollador de software (java). Me dijo que en su trabajo hay un tipo que tiene mucha experiencia en C++, pero lamentablemente cada vez que escribe código en Java, usa el try-catch para controlar el flujo del programa. Según mi amigo, este es un estilo incorrecto en Java. ¿Es esto cierto? ¿Cuáles son las diferencias (si las hay) en el uso de try-catch (-finalmente en java) entre C++ y Java?

+1

+1 a la respuesta de John Weldon. Tenga en cuenta que uno de los aspectos realmente desagradables de parte del ecosistema de Java (y que es una especificidad de Java) es el uso excesivo de excepciones ** verificadas ** por parte de algunas API/framework. Básicamente obliga a los usuarios de la API a controlar el flujo de su programa mediante la captura de excepción inmaculada sin sentido para cosas que no son excepcionales en absoluto. Algunos marcos, como Spring, están diseñados correctamente y realmente fruncen el ceño ante esa terrible mala práctica. Joshua Bloch en su * Effective Java * recomienda preferir un "método de prueba estatal" para lanzar innecesariamente excepciones (no) controladas. – NoozNooz42

+0

Hola, gracias por la respuesta. "Básicamente obliga a los usuarios de la API a controlar el flujo de su programa mediante la captura de excepción inmaculada sin sentido para cosas que no son excepcionales en absoluto". Entonces, ¿esta es la diferencia en try-catch entre C++/Java? Además, ¿qué quiere decir excepciones "controladas"? Cheers – Muggen

+1

Vea http://www.javapractices.com/topic/TopicAction.do?Id=129. Las excepciones controladas son esencialmente un abuso de excepciones para el control de flujo no excepcional. También son una pesadilla de mantenimiento. –

Respuesta

28

El uso de try-catch para controlar el flujo del programa está mal en cualquier lugar ... El manejo de excepciones es lo que dice: Manejo de circunstancias excepcionales.

Por supuesto, para cada regla hay una docena de contraejemplos de desviaciones necesarias, pero en general: No controle el flujo del programa con excepciones.

El uso de excepciones para controlar el flujo de un programa ocurre cuando anticipa que se lanzan ciertas excepciones en un entorno operativo normal, y toma decisiones lógicas basadas en esas excepciones.

Por ejemplo controlar el flujo del programa en pseudo código:

try { 
    write update to file 
} catch (IOException) { 
    write update to alternate file 
} 

En este caso, sería mejor para probar la existencia de hecho de ruta antes de realizar la escritura ciegamente.

que eliminan la comprobación de permisos notas porque es un mal ejemplo

Un buen uso de manejo de excepciones: (pseudo código de nuevo)

try { 
    do stuff 
} catch(OutOfMemoryException) { 
    fail gracefully (don't try and do something else to achieve the same result) 
} 
+1

Hola. Gracias por responder. ¿Sería posible mostrar algún código donde un try-catch está controlando el flujo, y un caso similar en el que no? Gracias – Muggen

+2

Esa es una muy buena pregunta @Muggen; Le daré una oportunidad para actualizar mi respuesta, pero creo que eso vale la pena. –

+3

@Muggen si tiene un archivo abierto que debería poder leer, pero si no puede, este es un caso excepcional. Si un usuario intenta iniciar sesión pero ingresa una contraseña no válida, esta es una condición de flujo normal y debe tratarse así, no con try-catch –

-2

Su pregunta es demasiado vaga y sin código de ejemplo. No hay finally en C++.

EDIT En general, no desea utilizar exceptions como medio para controlar el flujo. Exceptions se supone que deben usarse solo para casos excepcionales (situaciones inesperadas).

+1

En realidad, esta respuesta comienza a abordar la "otra" pregunta que planteó OP: ¿Cuáles son las diferencias en el manejo de excepciones entre java y C++ –

+0

? Esa es una buena respuesta, +1. – fastcodejava

8

Diría que, desde el punto de vista de la arquitectura de un programa, el objetivo de las excepciones es el mismo en Java y C++. Deben usarse para manejar casos excepcionales, no el flujo normal directo del programa.

El argumento más común contra el uso de excepciones es que son lentas. Al igual que la mayoría de los argumentos basados ​​en la velocidad del código, casi siempre es irrelevante hoy en día, especialmente cuando las excepciones se usan correctamente.

+0

Hola. "... especialmente cuando las excepciones se usan correctamente". ¿Cómo se puede usar una excepción de manera incorrecta? – Muggen

+2

Siempre que se use para controlar el flujo del programa, en lugar de manejar casos excepcionales. Por ejemplo, si puede verificar la longitud de una matriz, no use una excepción de índice fuera de límites para saber que se le pasa la longitud de la matriz para el índice, sino que simplemente haga que termine la bucle for en el punto apropiado. – aperkins

+3

En este caso, "son lentos" es una especie de argumento proxy para "eso no es para lo que son". Algunas personas no entienden muy bien el razonamiento simbólico de alto nivel como este, por lo que hay que darles ejemplos. Cuando utilizas cosas fuera de su rango de usos previstos, obtienes problemas (siendo lento para que el uso sea un ejemplo de uno). Si alguien soluciona la lentitud, todo sigue igual en el mundo. –

4

Yo esperaría que el C++ y Java mundos a ser muy similar en sus puntos de vista:

  1. de control de flujo con bloques try/catch no es inmediatamente obvio
  2. es caro en cuanto al rendimiento. En la práctica, esto puede no ser un problema, pero en muchos escenarios (por ejemplo, bucles estrechos) definitivamente le afectará.
6

Creo que lo que está diciendo es que está utilizando excepciones para condiciones no excepcionales, como las terminaciones normales de bucle.Eso es considerado como un no-no por los programadores en la mayoría de los idiomas que brindan excepciones, incluido C++.

La razón de esto es que las excepciones tienden a arrastrar un poco de información junto con ellas. En algunas plataformas, traen toda la pila de llamadas en el punto de la excepción, con el propósito de mostrarla en un bonito mensaje de depuración. Eso es muy caro, si todo lo que quieres es un salto de control incondicional.

En su lugar, debe utilizar declaraciones como break, return, o incluso (en una pizca real) goto.

+2

Por otro lado, este es un "sí-sí" en Python donde ** cada ciclo for ** finaliza manejando una excepción StopIteration. ;) – UncleBens

+2

@UncleBens - Muchas gracias por validar mi deseo de perdición. Pensé que tenía que haber al menos uno por ahí. :-) –

2

El bloque try-catch tiene la intención de hacer lo mismo en todos los idiomas; las excepciones son una de las muchas formas de recuperación cuando algo sale mal. En Java, las dos afirmaciones siguientes son idénticos:

if(x != null){ 
    //do the normal thing 
} 
else{ 
    //recover from the error 
} 

y

try{ 
    //do the normal thing 
} 
catch(NullPointerException ex){ 
    //recover 
} 

Sin embargo, el uso de excepciones no es buena idea para una serie de razones:

  • el costo asociado con el lanzamiento la excepción (es decir, generar un Throwable en Java)
  • el flujo de control no es inmediatamente obvio, por ejemplo, si se puede utilizar una NullPointerException lanzada por varias instrucciones en el bloque try, ¿cómo puede saber cuál arrojó en el bloque catch
  • etc, etc
+0

Hola. Gracias por responder. "¿Cómo se puede saber cuál lo tiró en el bloque de captura?" es otra pregunta que tenía. ¿Entonces sugieres que Try-catch solo debería usarse en casos especiales o entendí mal? Cheers – Muggen

+0

Tenga cuidado al decir que las construcciones son idénticas o equivalentes. Si "// hace lo normal" primero hace algo que no utiliza incorrectamente la referencia 'null', entonces el 2do ejemplo hará algo de trabajo (posiblemente con efectos secundarios visibles) que no ocurrirá en el primer ejemplo. –

+0

Espera, ¿"nunca" es una buena idea? Las excepciones son ideales para lo que están diseñadas: excepciones. A diferencia de los códigos de resultado, no pueden ignorarse, y se disparan automáticamente hasta que encuentran el código que está dispuesto a manejarlos. Nunca digas nunca, especialmente sobre cosas con un uso bien definido. –

3

La única propósito de try/catch es el control de flujo. Está destinado a permitirnos salir de cualquier bucle, e incluso ir más allá de la persona que llama y hasta una función de nivel superior.

Sin embargo, está diseñado para condiciones excepcionales, como referencias nulas utilizadas, desbordamiento de división o falla de E/S de archivos. Estos son errores que impiden que el programa continúe y se debe manejar. En general, son difíciles de predecir o son muy raros.

Cuando se produce una condición excepcional, lo mejor que se puede hacer es alterar el flujo de control para que la excepción se arroje lo más lejos posible para encontrar un bloque catch que esté dispuesto a manejarlo. Cualquier método intermedio se aborta y desenrolla, incluso si no tiene un código para verificar los resultados.

Cuando la gente se queja sobre el uso de try/catch para el control de flujo, lo que debe media es que no es para el control de flujo en condiciones no excepcionales. Si todo lo que quiere hacer es salir de un bucle, use break o return; no lanzar una excepción y luego atraparla. Para eso no son excepciones, ni es para lo que son buenas.

+0

Buena explicación @Steven. No estoy seguro de que valga la pena votar mi respuesta, pero bueno, no obstante :) –

+0

@John: Tienes 20 votos favorables. El votante negativo al menos obtendrá personas para detenerse y mirar alternativas. –

1

Lo que puede faltar es varias maneras de no ejecutar un poco de código ... Así que en lugar de (en Java)

if (cond1) { 
    some_code(); 
    if (cond2) { 
    some_more_code(); 
    if (condN) { 
     ad_infinitum 
    } 
    } 
} 

Esto se puede '' aplanado por tirar un poco de basura ...

try { 
    if (!cond1) throw new Throwable(); 
    some_code(); 
    if (!cond2) throw new Throwable(); 
    some_more_code(); 
    if (!condN) throw new Throwable(); 
    ad_infinitum(); 
} catch (Throwable ignore) { } 

El problema es, ¿qué ocurre si se produce una excepción real?Creo que lo que su colega debe escribir si quiere aplanar la sangría es algo como esto:

do { 
    if (!cond1) break; 
    some_code(); 
    if (!cond2) break; 
    some_more_code(); 
    if (!condN) break; 
    ad_infinitum(); 
} while (false); 

Desde do/while siempre ejecuta podemos utilizar la pausa para aproximarse a una Goto (siempre y cuando todo se va a la mismo punto).

Cuestiones relacionadas