¿Por qué evitar el uso de excepciones para controlar su flujo en Java?

Java es un lenguaje de programación universal que tiene muchas soluciones alternativas para sus tareas específicas. Sin embargo, hay buenos enfoques que deben seguirse, y también hay algunos enfoques fallidos que todavía utilizamos en su mayor parte.

Uno de los enfoques fallidos más comunes es utilizar excepciones para controlar el flujo de ejecución. Esto debe evitarse por dos razones:

  1. Esto reduce el rendimiento y la velocidad de su código.
  2. Esto hace que su código sea menos legible.

Comencemos mirando un ejemplo. Aquí la excepción se usa para controlar el flujo de ejecución:

public static int findAge(String name) { try { String ageAsString = findUser(name); return ageAsString.length(); } catch (NameNotFoundException e) { return 0; } } private static String findUser(String name) { if(name==null) { throw new NameNotFoundException(); } return name; } 

Si el usuario proporciona un valor no nulo para el nombre, el método findAge devolverá la longitud de este nombre, pero si el nombre de usuario es nulo, el método findUser generará una excepción NameNotFoundException y en este caso el método findAge devolverá 0.

¿Cómo podemos convertir este código sin usar excepciones? En general, hay muchas opciones, considere una de ellas:

 public static int findAgeNoEx(String name) { String ageAsString = findUserNoEx(name); return ageAsString.length(); } private static String findUserNoEx(String name) { if(name==null) { return ""; } return name; } 

Para descubrir el impacto de la excepción en el rendimiento, preparé el siguiente código que llama a ambas variantes de los métodos 10 millones de veces: con y sin excepción.

 public class ControlFlowWithExceptionOrNot { public static class NameNotFoundException extends RuntimeException { private static final long serialVersionUID = 3L; } private static final int TRIAL = 10000000; public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); for (int i = 0; i < TRIAL; i++) { findAgeNoEx(null); } System.out.println("Duration :" + (System.currentTimeMillis() - start)); long start2 = System.currentTimeMillis(); for (int i = 0; i < TRIAL; i++) { findAge(null); } System.out.println("Duration :" + (System.currentTimeMillis() - start2)); }; public static int findAge(String name) { try { String ageAsString = findUser(name); return ageAsString.length(); } catch (NameNotFoundException e) { return 0; } } private static String findUser(String name) { if (name == null) { throw new NameNotFoundException(); } return name; } public static int findAgeNoEx(String name) { String ageAsString = findUserNoEx(name); return ageAsString.length(); } private static String findUserNoEx(String name) { if (name == null) { return ""; } return name; } } 

Conclusión

 Duration :16 Duration :6212 

Como puede ver, usar la excepción nos costó miles de milisegundos en mi Intel Core i7-3630QM.

Si comparamos nuestros dos métodos findAge en términos de legibilidad, el método sin excepción es absolutamente claro: en primer lugar, podemos estar absolutamente seguros de que el método findUser devuelve una cadena; y en segundo lugar, independientemente de qué cadena se devolverá, obtenemos su longitud. Al mismo tiempo, el método con la excepción es algo confuso: no está completamente claro qué devuelve exactamente el método findUser. Puede devolver una cadena, o puede lanzar una excepción y esto no es visible desde la firma del método. Por esta razón, el paradigma de programación funcional no acepta el uso de excepciones.

Al final, sería mejor si usa excepciones donde la excepción realmente surge y es necesaria. Si usa excepciones para controlar el flujo de ejecución, esto provocará una caída en el rendimiento del programa y hará que su código sea menos legible.

Espero que este artículo te haya resultado interesante y posiblemente útil.

Source: https://habr.com/ru/post/476142/


All Articles