Cuándo elegir excepciones marcadas y no marcadas

213

En Java (o en cualquier otro idioma con excepciones marcadas), al crear su propia clase de excepción, ¿cómo decide si se debe marcar o no?

Mi instinto es decir que se solicitaría una excepción marcada en los casos en que la persona que llama podría recuperarse de una manera productiva, donde una excepción no verificada sería más para casos irrecuperables, pero estaría interesado en los pensamientos de otros.

Matt Sheppard
fuente
11
Barry Ruzek ha escrito una excelente guía sobre cómo elegir excepciones marcadas o no marcadas.
sigget

Respuestas:

241

Las excepciones marcadas son geniales, siempre y cuando comprenda cuándo deben usarse. La API principal de Java no sigue estas reglas para SQLException (y a veces para IOException), por lo que son tan terribles.

Las excepciones marcadas deben usarse para errores predecibles , pero no evitables , de los que es razonable recuperarse .

Las excepciones no marcadas deben usarse para todo lo demás.

Desglosaré esto por ti, porque la mayoría de la gente no entiende lo que esto significa.

  1. Previsible pero no prevenible : la persona que llamó hizo todo lo que estuvo a su alcance para validar los parámetros de entrada, pero alguna condición fuera de su control ha causado que la operación falle. Por ejemplo, intenta leer un archivo pero alguien lo elimina entre el momento en que verifica si existe y el momento en que comienza la operación de lectura. Al declarar una excepción marcada, le está diciendo a la persona que llama que anticipe esta falla.
  2. Razonable para recuperarse : no tiene sentido decirle a las personas que llaman que anticipen excepciones de las que no pueden recuperarse. Si un usuario intenta leer un archivo no existente, la persona que llama puede solicitarle un nuevo nombre de archivo. Por otro lado, si el método falla debido a un error de programación (argumentos de método no válidos o implementación de método defectuoso) no hay nada que la aplicación pueda hacer para solucionar el problema a mitad de la ejecución. Lo mejor que puede hacer es registrar el problema y esperar a que el desarrollador lo solucione más adelante.

A menos que la excepción que esté lanzando cumpla con todas las condiciones anteriores, debe usar una excepción no verificada.

Reevaluar en todos los niveles : a veces, el método para detectar la excepción marcada no es el lugar adecuado para manejar el error. En ese caso, considere lo que es razonable para sus propias personas que llaman. Si la excepción es predecible, evitable y razonable para que se recuperen, entonces debe lanzar una excepción marcada usted mismo. De lo contrario, debe ajustar la excepción en una excepción no marcada. Si sigue esta regla, se encontrará convirtiendo excepciones marcadas en excepciones no verificadas y viceversa, dependiendo de la capa en la que se encuentre.

Para las excepciones marcadas y no marcadas, use el nivel de abstracción correcto . Por ejemplo, un repositorio de código con dos implementaciones diferentes (base de datos y sistema de archivos) debe evitar exponer detalles específicos de la implementación lanzando SQLExceptiono IOException. En cambio, debería envolver la excepción en una abstracción que abarque todas las implementaciones (por ejemplo RepositoryException).

Gili
fuente
2
"intenta leer un archivo pero alguien lo elimina entre el momento en que verifica si existe y el momento en que comienza la operación de lectura". => ¿Cómo es esto 'esperado'? Para mí suena más como: Inesperado y evitable. ¿Quién esperaría que un archivo se elimine solo entre 2 declaraciones?
Koray Tugay
99
@KorayTugay Esperado no significa que el escenario sea típico. Simplemente significa que podemos prever que este error ocurra con anticipación (en comparación con los errores de programación que no se pueden predecir con anticipación). Imprevitable se refiere al hecho de que el programador no puede hacer nada para evitar que el usuario u otras aplicaciones eliminen un archivo entre el momento en que verificamos si existe y el momento en que comienza la operación de lectura.
Gili
Entonces, ¿cualquier problema relacionado con la base de datos dentro del método debe arrojar una excepción marcada?
ivanjermakov
59

De un aprendiz de Java :

Cuando ocurre una excepción, debe atrapar y manejar la excepción, o decirle al compilador que no puede manejarla declarando que su método arroja esa excepción, entonces el código que usa su método tendrá que manejar esa excepción (incluso también puede optar por declarar que arroja la excepción si no puede manejarlo).

El compilador verificará que hayamos hecho una de las dos cosas (atrapar o declarar). Por lo tanto, se llaman excepciones marcadas. Pero los errores y las excepciones de tiempo de ejecución no son controlados por el compilador (aunque puede elegir capturar o declarar, no es obligatorio). Entonces, estos dos se llaman excepciones no verificadas.

Los errores se utilizan para representar aquellas condiciones que ocurren fuera de la aplicación, como el bloqueo del sistema. Las excepciones de tiempo de ejecución generalmente se producen por error en la lógica de la aplicación. No puedes hacer nada en estas situaciones. Cuando se produce una excepción en tiempo de ejecución, debe volver a escribir el código del programa. Entonces, estos no son verificados por el compilador. Estas excepciones de tiempo de ejecución se descubrirán en el desarrollo y el período de prueba. Luego tenemos que refactorizar nuestro código para eliminar estos errores.

Espo
fuente
13
Esa es la visión ortodoxa. Pero hay mucha controversia al respecto.
artbristol
49

La regla que uso es: ¡nunca use excepciones no marcadas! (o cuando no ves ninguna forma de evitarlo)

Hay un caso muy fuerte para lo contrario: nunca use excepciones marcadas. Soy reacio a tomar partido en el debate, pero parece haber un amplio consenso de que introducir excepciones controladas fue una decisión equivocada en retrospectiva. Por favor, no dispare al mensajero y consulte esos argumentos .

Konrad Rudolph
fuente
3
En mi humilde opinión, las excepciones verificadas podrían haber sido un activo importante si hubiera habido una manera fácil para que un método declare que no está esperando que los métodos llamados en un bloque de código en particular arrojen ciertas excepciones (o alguna) las excepciones que se lanzan en contra de tal expectativa deben incluirse en algún otro tipo de excepción y volverse a lanzar. Yo diría que el 90% de las veces cuando el código no está preparado para hacer frente a una excepción marcada, tal ajuste y relanzamiento sería la mejor manera de manejarlo, pero debido a que no hay soporte de idiomas, rara vez se hace.
supercat
@supercat Básicamente eso es todo: soy un fanático acérrimo de la verificación estricta de tipos y las excepciones verificadas son una extensión lógica de eso. He abandonado por completo las excepciones comprobadas aunque conceptualmente me gustan mucho.
Konrad Rudolph
1
Una molestia que tengo con el diseño de excepciones, que el mecanismo que describí resolvería, es que si foose documenta como arrojar barExceptional leer más allá del final de un archivo, y foollama a un método que arroja barExceptionaunque foono lo espera, el codifique qué llamadas foopensarán que se alcanzó el final del archivo y no tendrán idea de que sucedió algo inesperado. Consideraría que esa situación es aquella en la que las excepciones verificadas deberían ser más útiles, pero también es el único caso en el que el compilador permitirá excepciones verificadas no controladas.
supercat
@supercat: Ya hay una manera fácil para que el código haga lo que desea en el primer comentario: envuelva el código en un bloque de prueba, capture Exception y envuelva la Exception en una RuntimeException y vuelva a lanzar.
Warren Dew
1
@KonradRudolph supercat se refirió a "un bloque particular de código"; dado que el bloque debe estar definido, la sintaxis declarativa no reduciría significativamente la hinchazón. Si está pensando que sería declarativo para toda la función, eso alentaría una mala programación, ya que las personas simplemente se quedarían en la declaración en lugar de mirar realmente las excepciones comprobadas potencialmente atrapadas y asegurarse de que no haya otra manera mejor para manejarlos.
Warren Dew
46

En cualquier sistema lo suficientemente grande, con muchas capas, la excepción marcada es inútil ya que, de todos modos, necesita una estrategia de nivel arquitectónico para manejar cómo se manejará la excepción (use una barrera de falla)

Con excepciones marcadas, su estrategia de manejo de errores está microgestionada y es insoportable en cualquier sistema grande.

La mayoría de las veces no sabe si un error es "recuperable" porque no sabe en qué capa se encuentra la persona que llama de su API.

Digamos que creo una API StringToInt que convierte la representación de cadena de un entero en un Int. ¿Debo lanzar una excepción marcada si se llama a la API con la cadena "foo"? ¿Es recuperable? No lo sé porque en su capa la persona que llama de mi API StringToInt ya puede haber validado la entrada, y si se lanza esta excepción, es un error o una corrupción de datos y no es recuperable para esta capa.

En este caso, la persona que llama de la API no quiere detectar la excepción. Él solo quiere dejar que la excepción "brote". Si elegí una excepción marcada, esta persona que llama tendrá un montón de bloqueos inútiles solo para volver a lanzar artificialmente la excepción.

Lo que es recuperable depende la mayor parte del tiempo del llamante de la API, no del escritor de la API. Una API no debe usar excepciones marcadas, ya que solo las excepciones no marcadas permiten elegir capturar o ignorar una excepción.

Stephane
fuente
3
Esto está muy cerca de userstories.blogspot.com/2008/12/…
alexsmail
15
@alexsmail Internet nunca deja de sorprenderme, en realidad es mi blog :)
Stephane
30

Estás en lo correcto.

Se utilizan excepciones no verificadas para permitir que el sistema falle rápidamente, lo cual es bueno. Debe indicar claramente qué espera su método para que funcione correctamente. De esta manera, puede validar la entrada solo una vez.

Por ejemplo:

/**
 * @params operation - The operation to execute.
 * @throws IllegalArgumentException if the operation is "exit"
 */
 public final void execute( String operation ) {
     if( "exit".equals(operation)){
          throw new IllegalArgumentException("I told you not to...");
     }
     this.operation = operation; 
     .....  
 }
 private void secretCode(){
      // we perform the operation.
      // at this point the opreation was validated already.
      // so we don't worry that operation is "exit"
      .....  
 }

Solo para poner un ejemplo. El punto es que si el sistema falla rápidamente, entonces sabrás dónde y por qué falló. Obtendrás un stacktrace como:

 IllegalArgumentException: I told you not to use "exit" 
 at some.package.AClass.execute(Aclass.java:5)
 at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
 ar ......

Y sabrás lo que pasó. OtherClass en el método "delegateTheWork" (en la línea 4569) llamó a su clase con el valor "exit", incluso cuando no debería, etc.

De lo contrario, tendría que rociar validaciones en todo el código y eso es propenso a errores. Además, a veces es difícil hacer un seguimiento de lo que salió mal y puede esperar horas de depuración frustrante

Lo mismo sucede con NullPointerExceptions. Si tiene una clase de 700 líneas con unos 15 métodos, que usa 30 atributos y ninguno de ellos puede ser nulo, en lugar de validar en cada uno de esos métodos la nulabilidad, puede hacer que todos esos atributos sean de solo lectura y validarlos en el constructor o método de fábrica

 public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
      if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }

  }


  // the rest of the methods don't validate data1 anymore.
  public void method1(){ // don't worry, nothing is null 
      ....
  }
  public void method2(){ // don't worry, nothing is null 
      ....
  }
  public void method3(){ // don't worry, nothing is null 
      ....
  }

Excepciones comprobadas Son útiles cuando el programador (usted o sus compañeros de trabajo) hicieron todo bien, validaron la entrada, realizaron pruebas y todo el código es perfecto, pero el código se conecta a un servicio web de terceros que puede estar inactivo (o un archivo que estaba usando fue eliminado por otro proceso externo, etc. El servicio web puede incluso validarse antes de intentar la conexión, pero durante la transferencia de datos algo salió mal.

En ese escenario, no hay nada que usted o sus compañeros de trabajo puedan hacer para ayudarlo. Pero aún debe hacer algo y no dejar que la aplicación simplemente muera y desaparezca a los ojos del usuario. Utiliza una excepción marcada para eso y maneja la excepción, ¿qué puede hacer cuando eso sucede ?, la mayoría de las veces, solo para intentar registrar el error, probablemente guarde su trabajo (el trabajo de la aplicación) y presente un mensaje al usuario . (El sitio blabla está inactivo, vuelva a intentarlo más tarde, etc.)

Si la excepción marcada se usa en exceso (agregando la "excepción de lanzamiento" en todas las firmas de métodos), entonces su código se volverá muy frágil, porque todos ignorarán esa excepción (porque es demasiado general) y la calidad del código será seriamente comprometidos.

Si usa en exceso la excepción no marcada, sucederá algo similar. Los usuarios de ese código no saben si algo puede salir mal y aparecerán muchos intentos {...} catch (Throwable t).

OscarRyz
fuente
2
¡Bien dicho! +1. Siempre me sorprende que esta distinción de llamada (sin marcar) / llamada (marcada) no sea más obvia ...
VonC
19

Aquí está mi 'regla de oro final'.
Yo suelo:

  • excepción no verificada dentro del código de mi método por una falla debido a la persona que llama (que involucra una documentación explícita y completa )
  • Se marcó la excepción por una falla debido a la persona que llama que debo hacer explícita a cualquiera que quiera usar mi código

Compare con la respuesta anterior, esta es una razón clara (sobre la cual uno puede estar de acuerdo o en desacuerdo) para el uso de uno u otro (o ambos) tipo de excepciones.


Para ambas excepciones, crearé mi propia Excepción sin marcar y marcada para mi aplicación (una buena práctica, como se menciona aquí ), excepto por una excepción sin marcar muy común (como NullPointerException)

Entonces, por ejemplo, el objetivo de esta función particular a continuación es hacer (u obtener si ya existe) un objeto, lo que
significa:

  • el contenedor del objeto para hacer / obtener DEBE existir (responsabilidad del LLAMADOR
    => excepción no marcada, y borrar el comentario de javadoc para esta función llamada)
  • los otros parámetros no pueden ser nulos
    (elección del codificador para poner eso en el LLAMADOR: el codificador no verificará el parámetro nulo pero el codificador LO DOCUMENTA)
  • el resultado NO PUEDE SER NULO
    (responsabilidad y elección del código de la persona que llama, elección que será de gran interés para la persona que llama
    => la excepción marcada porque cada persona que llama DEBE tomar una decisión si el objeto no se puede crear / encontrar, y eso la decisión debe hacerse cumplir en el momento de la compilación: no pueden usar esta función sin tener que lidiar con esta posibilidad, es decir, con esta excepción marcada ).

Ejemplo:


/**
 * Build a folder. <br />
 * Folder located under a Parent Folder (either RootFolder or an existing Folder)
 * @param aFolderName name of folder
 * @param aPVob project vob containing folder (MUST NOT BE NULL)
 * @param aParent parent folder containing folder 
 *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
 * @param aComment comment for folder (MUST NOT BE NULL)
 * @return a new folder or an existing one
 * @throws CCException if any problems occurs during folder creation
 * @throws AssertionFailedException if aParent is not in the same PVob
 * @throws NullPointerException if aPVob or aParent or aComment is null
 */
static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
    final IPVob aPVob, final Comment aComment) throws CCException {
    Folder aFolderRes = null;
    if (aPVob.equals(aParent.getPVob() == false) { 
       // UNCHECKED EXCEPTION because the caller failed to live up
       // to the documented entry criteria for this function
       Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }

    final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
        " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);

    final Status st = getCleartool().executeCmd(ctcmd);

    if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
        aFolderRes = Folder.getFolder(aFolderName, aPVob);
    }
    else {
        // CHECKED EXCEPTION because the callee failed to respect his contract
        throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
    }
    return aFolderRes;
}
VonC
fuente
19

No se trata solo de la capacidad de recuperarse de la excepción. Lo más importante, en mi opinión, es si la persona que llama está interesada en detectar la excepción o no.

Si escribe una biblioteca para usar en otro lugar, o una capa de nivel inferior en su aplicación, pregúntese si la persona que llama está interesada en detectar (saber) su excepción. Si no lo está, use una excepción no marcada, para no cargarlo innecesariamente.

Esta es la filosofía utilizada por muchos marcos. Spring e hibernate, en particular, vienen a la mente: convierten la excepción comprobada conocida en una excepción no comprobada precisamente porque las excepciones comprobadas se usan en exceso en Java. Un ejemplo en el que puedo pensar es la JSONException de json.org, que es una excepción marcada y es en su mayoría molesta: debe estar desmarcada, pero el desarrollador simplemente no lo ha pensado.

Por cierto, la mayoría de las veces el interés de la persona que llama en la excepción está directamente relacionado con la capacidad de recuperarse de la excepción, pero ese no es siempre el caso.

Yoni
fuente
13

Aquí hay una solución muy simple para su dilema marcado / no marcado.

Regla 1: piense en una excepción no verificada como una condición comprobable antes de que se ejecute el código. por ejemplo…

x.doSomething(); // the code throws a NullPointerException

donde x es nulo ... ... el código posiblemente debería tener lo siguiente ...

if (x==null)
{
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
}
x.doSomething();

Regla 2: piense en una excepción marcada como una condición no comprobable que puede ocurrir mientras se ejecuta el código.

Socket s = new Socket(“google.com”, 80);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

... en el ejemplo anterior, es posible que la URL (google.com) no esté disponible debido a que el servidor DNS está inactivo. Incluso en el instante en que el servidor DNS estaba funcionando y resolvió el nombre 'google.com' a una dirección IP, si la conexión se realiza a google.com, en cualquier momento posterior, la red podría fallar. Simplemente no puede probar la red todo el tiempo antes de leer y escribir en las transmisiones.

Hay momentos en los que el código simplemente debe ejecutarse antes de que podamos saber si hay un problema. Al obligar a los desarrolladores a escribir su código de tal manera que los obligue a manejar estas situaciones a través de la Excepción Comprobada, tengo que inclinarme ante el creador de Java que inventó este concepto.

En general, casi todas las API en Java siguen las 2 reglas anteriores. Si intenta escribir en un archivo, el disco podría llenarse antes de completar la escritura. Es posible que otros procesos hayan causado que el disco se llene. Simplemente no hay forma de probar esta situación. Para aquellos que interactúan con el hardware en cualquier momento, el uso del hardware puede fallar, las Excepciones comprobadas parecen ser una solución elegante para este problema.

Hay un área gris en esto. En el caso de que se necesiten muchas pruebas (una declaración alucinante de if con muchos && y ||), la excepción lanzada será una excepción CheckedException simplemente porque es demasiado difícil hacerlo bien; simplemente no puede decir este problema Es un error de programación. Si hay menos de 10 pruebas (por ejemplo, 'if (x == null)'), el error del programador debe ser una excepción no verificada.

Las cosas se ponen interesantes cuando se trata de intérpretes de idiomas. De acuerdo con las reglas anteriores, ¿se debe considerar un error de sintaxis como una excepción marcada o no marcada? Yo diría que si la sintaxis del lenguaje se puede probar antes de que se ejecute, debería ser una excepción no verificada. Si no se puede probar el idioma, de forma similar a cómo se ejecuta el código de ensamblaje en una computadora personal, entonces el Error de sintaxis debería ser una excepción comprobada.

Las 2 reglas anteriores probablemente eliminarán el 90% de su preocupación sobre la cual elegir. Para resumir las reglas, siga este patrón ... 1) si el código que se ejecutará puede probarse antes de ejecutarse para que se ejecute correctamente y si se produce una excepción, es decir, un error del programador, la excepción debería ser una excepción no verificada (una subclase de RuntimeException ) 2) si el código que se va a ejecutar no se puede probar antes de que se ejecute para que se ejecute correctamente, la excepción debe ser una excepción comprobada (una subclase de excepción).

usuario3598189
fuente
9

Puede llamarlo una excepción marcada o no marcada; sin embargo, el programador puede detectar ambos tipos de excepción, por lo que la mejor respuesta es: escriba todas sus excepciones como desmarcadas y documente. De esa forma, el desarrollador que usa su API puede elegir si quiere atrapar esa excepción y hacer algo. Las excepciones marcadas son una completa pérdida de tiempo para todos y hacen que su código sea una pesadilla impactante. Las pruebas unitarias adecuadas luego mostrarán cualquier excepción que pueda tener que atrapar y hacer algo.

Colin Saxton
fuente
1
+1 Por mencionar que las pruebas unitarias podrían ser una mejor manera de resolver el problema, las excepciones comprobadas están destinadas a resolver.
Keith Pinson el
+1 para pruebas unitarias. El uso de excepciones marcadas / no marcadas tiene poco impacto en la calidad del código. Por lo tanto, el argumento de que si uno usa excepciones marcadas daría como resultado una mejor calidad de código es un argumento falso completo.
user1697575
7

Excepción marcada : si el cliente puede recuperarse de una excepción y desea continuar, use la excepción marcada.

Excepción no verificada: si un cliente no puede hacer nada después de la excepción, entonces genere una excepción no verificada.

Ejemplo: si se espera que realice una operación aritmética en un método A () y se base en la salida de A (), debe realizar otra operación. Si la salida es nula del método A () que no esperaba durante el tiempo de ejecución, se espera que arroje una excepción de puntero nulo, que es la excepción del tiempo de ejecución.

Consulte aquí

Reachgoals
fuente
2

Estoy de acuerdo con la preferencia por las excepciones no marcadas como regla, especialmente al diseñar una API. La persona que llama siempre puede elegir capturar una excepción documentada y sin marcar. Simplemente no estás obligando innecesariamente a la persona que llama.

Encuentro excepciones comprobadas útiles en el nivel inferior, como detalle de implementación. A menudo parece un mejor mecanismo de flujo de control que tener que gestionar un error específico "código de retorno". A veces también puede ayudar a ver el impacto de una idea para un cambio de código de bajo nivel ... declarar una excepción comprobada en sentido descendente y ver quién necesitaría ajustar. Este último punto no se aplica si hay muchos genéricos: atrapar (Excepción e) o lanzar Excepción, que de todos modos no está muy bien pensada.

Scott Kurz
fuente
2

Aquí quiero compartir mi opinión que tengo después de muchos años de experiencia en desarrollo:

  1. Excepción marcada. Esto es parte del caso de uso comercial o flujo de llamadas, es parte de la lógica de la aplicación que esperamos o no esperamos. Por ejemplo, conexión rechazada, condición no satisfecha, etc. Necesitamos manejarlo y mostrar el mensaje correspondiente al usuario con instrucciones de lo que sucedió y qué hacer a continuación (intente nuevamente más tarde, etc.). Por lo general, lo llamo excepción de procesamiento posterior o excepción de "usuario".

  2. Excepción no verificada. Esto es parte de la excepción de programación, algún error en la programación del código de software (error, defecto) y refleja la forma en que los programadores deben usar la API según la documentación. Si un documento lib / framework externo dice que espera obtener datos en algún rango y no nulo, porque se lanzará NPE o IllegalArgumentException, el programador debe esperarlo y usar la API correctamente según la documentación. De lo contrario, se lanzará la excepción. Normalmente lo llamo excepción de preprocesamiento o excepción de "validación".

Por público objetivo. Ahora hablemos sobre el público objetivo o grupo de personas, las excepciones han sido diseñadas (según mi opinión):

  1. Excepción marcada. El público objetivo son los usuarios / clientes.
  2. Excepción no verificada. El público objetivo son los desarrolladores. En otras palabras, la excepción no marcada está diseñada solo para desarrolladores.

Por fase de ciclo de vida de desarrollo de aplicaciones.

  1. La excepción marcada está diseñada para existir durante todo el ciclo de vida de producción como mecanismo normal y esperado, una aplicación maneja casos excepcionales.
  2. La excepción no marcada está diseñada para existir solo durante el ciclo de vida de desarrollo / prueba de la aplicación, todos ellos deben repararse durante ese tiempo y no deben arrojarse cuando una aplicación ya se está ejecutando en producción.

La razón por la cual los frameworks usualmente usan excepciones no verificadas (Spring, por ejemplo) es que el framework no puede determinar la lógica de negocios de su aplicación, esto depende de los desarrolladores y luego diseñar su propia lógica.

Denys
fuente
2

Tenemos que distinguir estos dos tipos de excepción en función de si es un error del programador o no.

  • Si un error es un error del programador, debe ser una excepción no verificada . Por ejemplo: SQLException / IOException / NullPointerException. Estas excepciones son errores de programación. Deben ser manejados por el programador. Mientras que en JDBC API, SQLException es una excepción marcada, en Spring JDBCTemplate es una excepción no verificada. El programador no se preocupa por SqlException, cuando usa Spring.
  • Si un error no es un error del programador y el motivo proviene de una fuente externa, debe ser una excepción comprobada. Por ejemplo: si el archivo se elimina o alguien más cambia el permiso del archivo, debe recuperarse.

FileNotFoundException es un buen ejemplo para comprender diferencias sutiles. FileNotFoundException se lanza en caso de que no se encuentre el archivo. Hay dos razones para esta excepción. Si el desarrollador define la ruta del archivo o la toma del usuario final a través de la GUI, debería ser una excepción no verificada. Si alguien más elimina el archivo, debería ser una excepción marcada.

La excepción marcada se puede manejar de dos maneras. Estos están usando try-catch o propagan la excepción. En caso de propagación de excepción, todos los métodos en la pila de llamadas estarán estrechamente acoplados debido al manejo de excepciones. Por eso, tenemos que usar la Excepción Comprobada con cuidado.

En caso de que desarrolle un sistema empresarial en capas, debe elegir una excepción mayormente no marcada para lanzar, pero no olvide usar la excepción marcada para el caso de que no pueda hacer nada.

ailhanli
fuente
1

Las excepciones marcadas son útiles para casos recuperables en los que desea proporcionar información a la persona que llama (es decir, permisos insuficientes, archivo no encontrado, etc.).

Las excepciones no verificadas se usan raramente, si es que lo hacen, para informar al usuario o programador de errores graves o condiciones inesperadas durante el tiempo de ejecución. No los arroje si está escribiendo código o bibliotecas que serán utilizados por otros, ya que es posible que no esperen que su software arroje excepciones no verificadas, ya que el compilador no obliga a que sean capturados o declarados.

David Crow
fuente
No estoy de acuerdo con su afirmación "Las excepciones no verificadas se usan raramente, si es que lo hacen", de hecho, ¡debería ser lo opuesto! Utilice excepciones no verificadas de forma predeterminada cuando diseñe la jerarquía de excepciones de la aplicación. Permita que los desarrolladores decidan cuándo quieren manejar la excepción (por ejemplo, no están obligados a poner bloques catch o poner cláusula throws si no saben cómo manejarlo).
user1697575
1

Siempre que sea menos probable que se espere una excepción, y podemos proceder incluso después de atrapar eso, y no podemos hacer nada para evitar esa excepción, entonces podemos usar la excepción marcada.

Siempre que queramos hacer algo significativo cuando ocurra una excepción en particular y cuando esa excepción sea esperada pero no segura, entonces podemos usar la excepción marcada.

Siempre que la excepción navegue en diferentes capas, no necesitamos atraparla en cada capa, en ese caso, podemos usar la excepción de tiempo de ejecución o la excepción de ajuste como excepción no verificada.

La excepción de tiempo de ejecución se usa cuando es más probable que ocurra una excepción, no hay forma de ir más allá y nada puede ser recuperable. Entonces, en este caso, podemos tomar precauciones con respecto a esa excepción. EJ: NUllPointerException, ArrayOutofBoundsException. Es más probable que sucedan. En este escenario, podemos tomar precauciones mientras codificamos para evitar dicha excepción. De lo contrario, tendremos que escribir try catch blocks en todas partes.

Se pueden hacer excepciones más generales Sin marcar, se verifican las menos generales.

apelmazamiento
fuente
1

Creo que podemos pensar en excepciones a partir de varias preguntas:

¿Por qué sucede la excepción? ¿Qué podemos hacer cuando sucede?

por error, un error. como se llama un método de objeto nulo.

String name = null;
... // some logics
System.out.print(name.length()); // name is still null here

Este tipo de excepción se debe solucionar durante la prueba. De lo contrario, se interrumpe la producción y se obtiene un error muy alto que debe corregirse de inmediato. No es necesario verificar este tipo de excepciones.

por entrada externa, no puede controlar ni confiar en la salida del servicio externo.

String name = ExternalService.getName(); // return null
System.out.print(name.length());    // name is null here

Aquí, es posible que deba verificar si el nombre es nulo si desea continuar cuando sea nulo, de lo contrario, puede dejarlo solo y se detendrá aquí y le dará a la persona que llama la excepción de tiempo de ejecución. No es necesario verificar este tipo de excepciones.

por excepción de tiempo de ejecución externo, no puede controlar o confiar en el servicio externo.

Aquí, es posible que deba detectar todas las excepciones de ExternalService si desea continuar cuando suceda; de lo contrario, puede dejarlo solo y se detendrá aquí y le dará al llamante la excepción de tiempo de ejecución.

mediante la excepción marcada de externo, no puede controlar o confiar en el servicio externo.

Aquí, es posible que deba detectar todas las excepciones de ExternalService si desea continuar cuando suceda; de lo contrario, puede dejarlo solo y se detendrá aquí y le dará al llamante la excepción de tiempo de ejecución.

En este caso, ¿necesitamos saber qué tipo de excepción ocurrió en ExternalService? Depende:

  1. Si puede manejar algunos tipos de excepciones, debe atraparlas y procesarlas. Para otros, burbujearlos.

  2. Si necesita iniciar sesión o responder al usuario la ejecución específica, puede atraparlos. Para otros, burbujearlos.

Jacky
fuente
0

Creo que al declarar la excepción de la aplicación debería ser la excepción no verificada, es decir, la subclase de RuntimeException. La razón es que no saturará el código de la aplicación con la declaración try-catch y throws en el método. Si su aplicación está utilizando Java Api que arroja excepciones comprobadas que de todos modos deben ser manejadas. Para otros casos, la aplicación puede lanzar una excepción no verificada. Si el llamador de la aplicación aún necesita manejar una excepción no verificada, puede hacerlo.

Akash Aggarwal
fuente
-12

La regla que uso es: ¡nunca use excepciones no marcadas! (o cuando no ves ninguna forma de evitarlo)

Desde el punto de vista del desarrollador que usa su biblioteca o el usuario final que usa su biblioteca / aplicación, realmente apesta ser confrontado con una aplicación que se bloquea debido a una excepción no obtenida. Y contar con una captura general tampoco es bueno.

De esta manera, el usuario final aún puede recibir un mensaje de error, en lugar de que la aplicación desaparezca por completo.


fuente
1
No explicas lo que crees que está mal con un resumen para la mayoría de las excepciones no controladas.
Matthew Flaschen
Totalmente en desacuerdo con su respuesta no discutida: "nunca use excepciones no verificadas"
user1697575