Java: explicación de excepción comprobada frente a desmarcada

He leído varias publicaciones en StackOverFlow acerca de las excepciones marcadas frente a las no verificadas. Sinceramente, todavía no estoy muy seguro de cómo usarlos correctamente.

Joshua Bloch en ” Effective Java ” dijo que

Use excepciones marcadas para condiciones recuperables y excepciones de tiempo de ejecución para errores de progtwigción (Artículo 58 en la 2da edición)

Veamos si entiendo esto correctamente.

Aquí está mi entendimiento de una excepción marcada:

try{ String userInput = //read in user input Long id = Long.parseLong(userInput); }catch(NumberFormatException e){ id = 0; //recover the situation by setting the id to 0 } 

1. ¿Es lo anterior considerado una excepción marcada?

2. ¿RuntimeException es una excepción sin marcar?

Aquí está mi entendimiento de una excepción no verificada:

 try{ File file = new File("my/file/path"); FileInputStream fis = new FileInputStream(file); }catch(FileNotFoundException e){ //3. What should I do here? //Should I "throw new FileNotFoundException("File not found");"? //Should I log? //Or should I System.exit(0);? } 

4. Ahora, ¿no podría el código anterior también ser una excepción marcada? Puedo tratar de recuperar la situación de esta manera? ¿Puedo? (Nota: mi tercera pregunta está dentro de la catch anterior)

 try{ String filePath = //read in from user input file path File file = new File(filePath); FileInputStream fis = new FileInputStream(file); }catch(FileNotFoundException e){ //Kindly prompt the user an error message //Somehow ask the user to re-enter the file path. } 

5. ¿Por qué la gente hace esto?

 public void someMethod throws Exception{ } 

¿Por qué dejan que suba la excepción? ¿No está manejando el error más rápido? ¿Por qué burbujear?

EDIT: ¿Debería crear la excepción exacta o enmascararla usando Exception?

A continuación están mis lecturas

En Java, ¿cuándo debería crear una excepción marcada y cuándo debería ser una excepción de tiempo de ejecución?

Cuándo elegir las excepciones marcadas y no marcadas

Mucha gente dice que las excepciones comprobadas (es decir, estas que debería atrapar o volver a lanzar explícitamente) no deberían utilizarse en absoluto. Fueron eliminados en C # por ejemplo, y la mayoría de los idiomas no los tienen. Por lo tanto, siempre puede lanzar una subclase de RuntimeException (excepción no verificada)

Sin embargo, creo que las excepciones controladas son útiles: se usan cuando se quiere forzar al usuario de su API a pensar cómo manejar la situación excepcional (si es recuperable). Es solo que las excepciones comprobadas se usan en exceso en la plataforma Java, lo que hace que la gente las odie.

Aquí está mi vista extendida sobre el tema .

En cuanto a las preguntas particulares:

  1. ¿Es la NumberFormatException considerada una excepción marcada?
    No. NumberFormatException está desmarcada (= es la subclase de RuntimeException ). ¿Por qué? No lo sé. (pero debería haber un método es isValidInteger(..) )

  2. ¿ RuntimeException es una excepción no verificada?
    Sí exactamente.

  3. ¿Qué debería hacer aquí?
    Depende de dónde está este código y lo que quiere que suceda. Si está en la capa UI, tómalo y muestra una advertencia; si está en la capa de servicio, no lo capte del todo, déjelo burbujear. Simplemente no tragues la excepción. Si se produce una excepción en la mayoría de los casos, debe elegir uno de estos:

    • iniciar sesión y regresar
    • volver a lanzarlo (declarar que fue arrojado por el método)
    • construir una nueva excepción pasando el actual en constructor
  4. Ahora, ¿no podría el código anterior también ser una excepción marcada? Puedo tratar de recuperar la situación de esta manera? ¿Puedo?
    Pudo haber sido. Pero nada le impide atrapar la excepción no verificada también

  5. ¿Por qué la gente agrega la clase Exception en la cláusula throws?
    En la mayoría de los casos, las personas son perezosas para considerar qué capturar y qué relanzar. Throwing Exception es una mala práctica y debe evitarse.

Desafortunadamente, no existe una regla única que le permita determinar cuándo atrapar, cuándo volver a lanzar, cuándo usar marcado y cuándo usar las excepciones no verificadas. Estoy de acuerdo, esto causa mucha confusión y muchos códigos malos. El principio general lo establece Bloch (usted citó una parte). Y el principio general es volver a lanzar una excepción a la capa donde puede manejarlo.

Si algo es una “excepción marcada” no tiene nada que ver con si lo capturas o con lo que haces en el bloque catch. Es una propiedad de clases de excepción. Cualquier cosa que sea una subclase de Exception excepto por RuntimeException y sus subclases es una excepción marcada.

El comstackdor de Java lo obliga a capturar excepciones comprobadas o declararlas en la firma del método. Se suponía que debía mejorar la seguridad del progtwig, pero la opinión mayoritaria parece ser que no vale la pena los problemas de diseño que crea.

¿Por qué dejan que suba la excepción? ¿No maneja el error cuanto antes mejor? ¿Por qué burbujear?

Porque ese es todo el punto de las excepciones. Sin esta posibilidad, no necesitarías excepciones. Le permiten manejar los errores en el nivel que elija, en lugar de obligarlo a tratarlos en métodos de bajo nivel donde ocurrieron originalmente.

  1. ¿Es lo anterior considerado una excepción marcada? No El hecho de que esté manejando una excepción no lo convierte en una Excepción Controlada si se trata de una RuntimeException.

  2. ¿RuntimeException es una excepción no verificada? Sí

Las excepciones marcadas son subclases de java.lang.Exception Las excepciones no verificadas son subclases de java.lang.RuntimeException

Las llamadas que lanzan excepciones controladas deben estar encerradas en un bloque try {} o manejadas en un nivel superior en la persona que llama del método. En ese caso, el método actual debe declarar que arroja dichas excepciones para que las personas que llaman puedan hacer arreglos apropiados para manejar la excepción.

Espero que esto ayude.

P: ¿Debería crear la excepción exacta o enmascararla usando Exception?

R: Sí, esta es una muy buena pregunta y una importante consideración de diseño. La clase Exception es una clase de excepción muy general y se puede usar para ajustar excepciones internas de bajo nivel. Debería crear una excepción personalizada y envolverla. Pero, y uno grande: nunca oscurecer en la causa original subyacente. Por ejemplo, Dont ever hagas lo siguiente:

 try { attemptLogin(userCredentials); } catch (SQLException sqle) { throw new LoginFailureException("Cannot login!!"); //< -- Eat away original root cause, thus obscuring underlying problem. } 

En lugar de hacer lo siguiente:

 try { attemptLogin(userCredentials); } catch (SQLException sqle) { throw new LoginFailureException(sqle); //< -- Wrap original exception to pass on root cause upstairs!. } 

Al consumir los entuertos de origen raíz originales, la causa real más allá de la recuperación es una pesadilla para los equipos de soporte de producción, donde todos a los que se les da acceso son registros de aplicaciones y mensajes de error. Aunque este último es un mejor diseño, muchas personas no lo utilizan a menudo porque los desarrolladores simplemente no transmiten el mensaje subyacente a la persona que llama. Por lo tanto, tome una nota firme: Always pass on the actual exception ya sea que esté o no incluida en alguna excepción específica de la aplicación.

En try-catching RuntimeExceptions

RuntimeExceptions como regla general no debe ser try-catched. Por lo general, señalan un error de progtwigción y deben dejarse en paz. En cambio, el progtwigdor debe verificar la condición de error antes de invocar algún código que pueda dar como resultado una RuntimeException. Por ejemplo:

 try { setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!); } catch (NullPointerException npe) { sendError("Sorry, your userObject was null. Please contact customer care."); } 

Esta es una mala práctica de progtwigción. En cambio, se debería haber hecho un cheque nulo como ...

 if (userObject != null) { setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!); } else { sendError("Sorry, your userObject was null. Please contact customer care."); } 

Pero hay momentos en que tal comprobación de errores es costosa, como el formato de número, considere esto:

 try { String userAge = (String)request.getParameter("age"); userObject.setAge(Integer.parseInt(strUserAge)); } catch (NumberFormatException npe) { sendError("Sorry, Age is supposed to be an Integer. Please try again."); } 

En este caso, la comprobación de errores previos a la invocación no vale la pena, ya que básicamente significa duplicar todo el código de conversión de cadena a entero dentro del método parseInt () y es propenso a errores si lo implementa un desarrollador. Por lo tanto, es mejor simplemente acabar con try-catch.

Por lo tanto, NullPointerException y NumberFormatException son ambas RuntimeExceptions, la captura de una NullPointerException debe reemplazarse por una elegante null-check, mientras que yo recomiendo atrapar una NumberFormatException explícitamente para evitar la posible introducción de código propenso a errores.

1. Si no está seguro acerca de una excepción, verifique la API:

  java.lang.Object extended by java.lang.Throwable extended by java.lang.Exception extended by java.lang.RuntimeException //< -NumberFormatException is a RuntimeException extended by java.lang.IllegalArgumentException extended by java.lang.NumberFormatException 

2. Sí, y cada excepción que lo extiende.

3. No hay necesidad de atrapar y lanzar la misma excepción. Puede mostrar un nuevo cuadro de diálogo de archivo en este caso.

4. FileNotFoundException ya es una excepción comprobada.

5. Si se espera que el método que llama a someMethod método para atrapar la excepción, este último se puede lanzar. Simplemente "pasa la pelota". Un ejemplo de su uso sería si desea implementarlo en sus propios métodos privados y, en su lugar, manejar la excepción en su método público.

Una buena lectura es el documento de Oracle en sí: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

¿Por qué los diseñadores decidieron forzar un método para especificar todas las excepciones comprobadas no detectadas que se pueden arrojar dentro de su scope? Cualquier excepción que pueda arrojarse mediante un método es parte de la interfaz de progtwigción pública del método. Aquellos que llaman a un método deben conocer las excepciones que un método puede arrojar para que puedan decidir qué hacer con ellos. Estas excepciones son tanto una parte de la interfaz de progtwigción de ese método como sus parámetros y valor de retorno.

La siguiente pregunta podría ser: "Si es tan bueno documentar la API de un método, incluidas las excepciones que puede arrojar, ¿por qué no especificar excepciones de tiempo de ejecución también?" Las excepciones de tiempo de ejecución representan problemas que son el resultado de un problema de progtwigción y, como tal, no se puede esperar razonablemente que el código del cliente API se recupere de ellos o que los maneje de ninguna manera. Dichos problemas incluyen excepciones aritméticas, como dividir por cero; excepciones de puntero, como intentar acceder a un objeto a través de una referencia nula; e indexar excepciones, como intentar acceder a un elemento de matriz a través de un índice que es demasiado grande o demasiado pequeño.

También hay un poco de información importante en la Especificación del lenguaje Java :

Las clases de excepción comprobadas nombradas en la cláusula throws son parte del contrato entre el implementador y el usuario del método o constructor .

La última palabra en mi humilde opinión es que puedes atrapar cualquier RuntimeException , pero no estás obligado a hacerlo y, de hecho, la implementación no es necesaria para mantener lanzadas las mismas excepciones no verificadas, ya que esas no son parte del contrato.

1) No, una excepción NumberFormatException es una excepción no seleccionada. A pesar de que lo atrapó (no es obligatorio), no está marcado. Esto se debe a que es una subclase de IllegalArgumentException que es una subclase de RuntimeException.

2) RuntimeException es la raíz de todas las Excepciones no verificadas. Cada subclase de RuntimeException está desmarcada. Todas las demás Excepciones y Throwables están marcadas, excepto los Errores (que vienen bajo Throwable).

3/4) Podría alertar al usuario de que eligieron un archivo inexistente y pedir uno nuevo. O simplemente deje de informar al usuario que ingresó algo inválido.

5) Lanzar y atrapar ‘Excepción’ es una mala práctica. Pero, en términos más generales, puede lanzar otras excepciones para que la persona que llama pueda decidir cómo manejarlo. Por ejemplo, si escribió una biblioteca para manejar la lectura de algunos archivos y su método pasó un archivo inexistente, no tiene idea de cómo manejarlo. ¿La persona que llama desea volver a preguntar o dejar de fumar? Entonces le arrojas la Excepción a la cadena de regreso a la persona que llama.

En muchos casos, se produce una excepción no verificada porque el progtwigdor no verificó las entradas (en el caso de NumberFormatException en su primera pregunta). Es por eso que es opcional atraparlos, porque hay formas más elegantes de evitar generar esas excepciones.

Controlado: propenso a suceder. Checked in Tiempo de comstackción.

Por ejemplo … FileOperations

No comprobado: debido a datos incorrectos. Controlado en tiempo de ejecución.

P.ej..

 String s = "abc"; Object o = s; Integer i = (Integer) o; Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at Sample.main(Sample.java:9) 

Aquí la excepción se debe a datos incorrectos y de ninguna manera se puede determinar durante el tiempo de comstackción.

La JVM verifica las excepciones comprobadas en tiempo de comstackción y su relación con los recursos (files / db / stream / socket, etc.). El motivo de la excepción comprobada es que en el momento de la comstackción, si los recursos no están disponibles, la aplicación debe definir un comportamiento alternativo para manejar esto en el bloque catch / finally.

Las excepciones no verificadas son errores puramente programáticos, cálculos incorrectos, datos nulos o incluso fallas en la lógica empresarial que pueden dar lugar a excepciones en el tiempo de ejecución. Es absolutamente correcto manipular / capturar excepciones sin marcar en el código.

Explicación tomada de http://coder2design.com/java-interview-questions/

Solo quiero agregar un razonamiento para no usar excepciones marcadas. Esta no es una respuesta completa, pero creo que responde una parte de su pregunta y complementa muchas otras respuestas.

Siempre que estén involucradas excepciones controladas, hay una throws CheckedException en algún lugar de una firma de método ( CheckedException podría ser cualquier excepción marcada). Una firma NO arroja una Excepción, arrojando Excepciones es un aspecto de la implementación. Interfaces, firmas de métodos, clases principales, todas estas cosas NO deberían depender de sus implementaciones. El uso de Excepciones marcadas aquí (en realidad, el hecho de que debe declarar los throws en la firma del método) vincula sus interfaces de nivel superior con sus implementaciones de estas interfaces.

Dejame mostrarte un ejemplo.

Tengamos una interfaz agradable y limpia como esta

 public interface IFoo { public void foo(); } 

Ahora podemos escribir muchas implementaciones del método foo() , como estas

 public class Foo implements IFoo { @Override public void foo() { System.out.println("I don't throw and exception"); } } 

Class Foo está perfectamente bien. Ahora hagamos un primer bash en Class Bar

 public class Bar implements IFoo { @Override public void foo() { //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same. throw new InterruptedException(); } } 

Esta clase Bar no comstackrá. Como InterruptedException es una excepción comprobada, debes capturarla (con un try-catch dentro del método foo ()) o declarar que la estás lanzando (añadiendo throws InterruptedException a la firma del método). Como no quiero capturar esta excepción aquí (quiero que se propague hacia arriba para que pueda tratarla en otro lugar), modifiquemos la firma.

 public class Bar implements IFoo { @Override public void foo() throws InterruptedException { throw new InterruptedException(); } } 

¡Esta clase Bar no comstackrá tampoco! El método de barra foo () NO anula el método de IFoo foo () ya que sus firmas son diferentes. Podría eliminar la anotación @Override, pero quiero progtwigr contra la interfaz IFoo como IFoo foo; y luego decidir qué implementación quiero usar, como foo = new Bar(); . Si el método de Bar foo () no anula el método de IFoo foo, cuando hago foo.foo(); no llamará a la implementación de Bar de foo ().

Para hacer que el public void foo() throws InterruptedException de Bar public void foo() throws InterruptedException sobreescriba IFO’s public void foo() DEBO agregar throws InterruptedException a la firma del método IFoo. Esto, sin embargo, causará problemas con mi clase Foo, ya que la firma del método foo () difiere de la firma del método IFoo. Además, si agregué throws InterruptedException al método foo () de Foo, obtendría otro error que indica que el método Foo () declara que arroja una InterruptedException pero nunca arroja una InterruptedException.

Como puede ver (si hice un trabajo decente al explicar esto), el hecho de que estoy lanzando una excepción comprobada como InterruptedException me obliga a vincular mi interfaz IFoo a una de sus implementaciones, lo que a su vez causa esgulps en IFoo’s otras implementaciones!

Esta es una gran razón por la cual las excepciones comprobadas son MALAS. En mayúsculas.

Una solución es capturar la excepción comprobada, envolverla en una excepción sin marcar y lanzar la excepción sin marcar.

Para responder a la pregunta final (las otras parecen haber sido respondidas minuciosamente arriba), “¿Debo crear la excepción exacta o enmascararla usando Excepción?”

Supongo que quieres decir algo como esto:

 public void myMethod() throws Exception { // ... something that throws FileNotFoundException ... } 

No, siempre declare la excepción más precisa posible, o una lista de tales. Las excepciones que declara que su método es capaz de lanzar son parte del contrato entre su método y la persona que llama. Lanzar “FileNotFoundException” significa que es posible que el nombre del archivo no sea válido y no se encuentre el archivo; la persona que llama deberá manejar eso inteligentemente. Lanzar “Excepción” significa “Oye, sucede sh * t. Deal”. Que es una API muy pobre.

En los comentarios sobre el primer artículo, hay algunos ejemplos donde “throws Exception” es una statement válida y razonable, pero ese no es el caso para la mayoría de los códigos “normales” que jamás escribirás.

  • Java distingue dos categorías de excepciones (marcadas y sin marcar)
  • Java impone un requisito de captura o declarado para excepciones marcadas
  • El tipo de una excepción determina si una excepción está marcada o no.
  • Todos los tipos de excepciones que son subclases directas o indirectas de la clase RuntimeException son excepciones sin marcar.
  • Todas las clases que heredan de la clase Exception pero no RuntimeException se consideran excepciones marcadas.
  • Las clases que heredan de la clase Error se consideran desmarcadas.
  • El comstackdor comprueba cada llamada y desaceleración de método para determinar si el método arroja la excepción marcada.
    • Si es así, el comstackdor asegura que la excepción se detecta o se declara en una cláusula throws.
  • Para cumplir con la parte de declarar del requisito de capturar o declarar, el método que genera la excepción debe proporcionar una cláusula throws que contenga la excepción verificada.
  • Las clases de excepción se definen para verificarse cuando se consideran lo suficientemente importantes como para detectarlas o declararlas.

¿Por qué dejan que suba la excepción? ¿No está manejando el error más rápido? ¿Por qué burbujear?

Por ejemplo, supongamos que tiene alguna aplicación cliente-servidor y el cliente ha realizado una solicitud de algún recurso que no se ha podido averiguar o, para otra cosa, puede haber ocurrido algún error en el servidor mientras se procesa la solicitud del usuario, entonces es el deber del servidor para decirle al cliente por qué no pudo obtener lo que solicitó, por lo que para lograrlo en el servidor, el código se escribe para lanzar la excepción utilizando throw palabra clave en lugar de tragarlo o manejarlo. si el servidor lo maneja / traga esto, entonces no habrá posibilidad de intimidar al cliente de que se ha producido el error.

Nota: Para dar una descripción clara de qué tipo de error ha ocurrido, podemos crear nuestro propio objeto Exception y lanzarlo al cliente.

Excepciones de tiempo de ejecución Las excepciones de tiempo de ejecución se conocen como excepciones no verificadas. Todas las demás excepciones son excepciones comprobadas, y no derivan de java.lang.RuntimeException.

Excepciones marcadas Se debe capturar una excepción marcada en algún lugar de su código. Si invoca un método que arroja una excepción marcada pero no capta la excepción marcada en algún lugar, su código no se comstackrá. Es por eso que se llaman excepciones comprobadas: el comstackdor verifica que se manejen o declaren.

Varios métodos de la API de Java arrojan excepciones comprobadas, por lo que a menudo escribirá manejadores de excepciones para hacer frente a las excepciones generadas por métodos que no escribió.

Aquí hay una regla simple que puede ayudarte a decidir. Está relacionado con cómo se usan las interfaces en Java.

Tome su clase e imagínese diseñando una interfaz para que la interfaz describa la funcionalidad de la clase pero no la implementación subyacente (como una interfaz). Finge tal vez que podrías implementar la clase de otra manera.

Mire los métodos de la interfaz y considere las excepciones que podrían arrojar:

Si un método puede lanzar una excepción, independientemente de la implementación subyacente (en otras palabras, describe la funcionalidad solamente), entonces probablemente debería ser una excepción marcada en la interfaz.

Si una excepción es causada por la implementación subyacente, no debería estar en la interfaz. Therefore, it must either be an unchecked exception in your class (since unchecked exceptions need not appear in the interface signature), or you must wrap it and rethrow as a checked exception that is part of the interface method.

To decide if you should wrap and rethrow, you should again consider whether it makes sense for a user of the interface to have to handle the exception condition immediately, or the exception is so general that there is nothing you can do about it and it should propagate up the stack. Does the wrapped exception make sense when expressed as functionality of the new interface you are defining or is it just a carrier for a bag of possible error conditions that could also happen to other methods? If the former, it might still be a checked exception, otherwise it should be unchecked.

You should not usually plan to “bubble-up” exceptions (catch and rethrow). Either an exception should be handled by the caller (in which case it is checked) or it should go all the way up to a high level handler (in which case it is easiest if it is unchecked).

My absolute favorite description of the difference between unchecked and checked exceptions is provided by the Java Tutorial trail article, ” Unchecked Exceptions – the Controversy ” (sorry to get all elementary on this post – but, hey, the basics are sometimes the best):

Here’s the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception

The heart of “what type of exception to throw” is semantic (to some degree) and the above quote provides and excellent guideline (hence, I am still blown away by the notion that C# got rid of checked exceptions – particularly as Liskov argues for their usefulness).

The rest then becomes logical: to which exceptions does the compiler expect me to respond, explicitly? The ones from which you expect client to recover.

I think that checked exceptions are a good reminder for the developer that uses an external library that things can go wrong with the code from that library in exceptional situations.

Read more about checked vs unchecked exceptions here http://learnjava.today/2015/11/checked-vs-unchecked-exceptions/

Just to point out that if you throw a checked exception in a code and the catch is few levels above, you need to declare the exception in the signature of each method between you and the catch. So, encapsulation is broken because all functions in the path of throw must know about details of that exception.

In short, exceptions which your module or modules above are supposed to handle during runtime are called check-exceptions, others are unchecked-exceptions which are either RuntimeException or Error . In this video, it explains checked and unchecked exceptions in java. https://www.youtube.com/watch?v=ue2pOqLaArw

All of those are checked exceptions. Unchecked exceptions are subclasses of RuntimeException. The decision is not how to handle them, it’s should your code throw them. If you don’t want the compiler telling you that you haven’t handled an exception then you use an unchecked (subclass of RuntimeException) exception. Those should be saved for situations that you can’t recover from, like out of memory errors and the like.

If anybody cares for yet another proof to dislike checked exceptions, see the first few paragraphs of the popular JSON library:

“Although this is a checked exception, it is rarely recoverable. Most callers should simply wrap this exception in an unchecked exception and rethrow: ”

So why in the world would anyone make developers keep checking the exception, if we should “simply wrap it” instead? lol

http://developer.android.com/reference/org/json/JSONException.html

Checked Exceptions :

  • The exceptions which are checked by the compiler for smooth execution of the program at runtime are called Checked Exception.

  • These occur at compile time.

  • If these are not handled properly, they will give compile time error (Not Exception).
  • All subclasses of Exception class except RuntimeException are Checked Exception.

    Hypothetical Example – Suppose you are leaving your house for the exam, but if you check whether you took your Hall Ticket at home(compile time) then there won’t be any problem at Exam Hall(runtime).

Unchecked Exception :

  • The exceptions which are not checked by the compiler are called Unchecked Exceptions.

  • These occur at runtime.

  • If these exceptions are not handled properly, they don’t give compile time error. But the program will be terminated prematurely at runtime.

  • All subclasses of RunTimeException and Error are unchecked exceptions.

    Hypothetical Example – Suppose you are in your exam hall but somehow your school had a fire accident (means at runtime) where you can’t do anything at that time but precautions can be made before (compile time).

All exceptions must be checked exceptions.

  1. Unchecked exceptions are unrestricted gotos. And unrestricted gotos are considered a bad thing.

  2. Unchecked exceptions break encapsulation. To process them correctly, all the functions in the call tree between the thrower and the catcher must be known to avoid bugs.

  3. Exceptions are errors in the function that throws them but not errors in the function that processes them. The purpose of exceptions is to give the program a second chance by deferring the decision of whether it’s an error or not to another context. It’s only in the other context can the correct decision be made.