try - throws exception java
Diferencia entre los lanzamientos en la firma del método y las declaraciones de lanzamiento en Java (4)
Estoy tratando de dejar en claro la diferencia entre los lanzamientos en la firma del método y las declaraciones de lanzamiento en Java. Los tiros en la firma del método son los siguientes:
public void aMethod() throws IOException{
FileReader f = new FileReader("notExist.txt");
}
Declaraciones de tiro es como sigue:
public void bMethod() {
throw new IOException();
}
A mi entender, una throws
en la firma del método es una notificación de que el método puede lanzar tal excepción. throw
declaración es lo que realmente lanza un objeto creado en las circunstancias correspondientes. En ese sentido, los lanzamientos en la firma del método siempre deberían aparecer si existe una declaración de lanzamiento en el método.
Sin embargo, el siguiente código no parece hacerlo. El código es de la biblioteca. Mi pregunta es ¿por qué está sucediendo? ¿Estoy entendiendo los conceptos equivocados?
Este fragmento de código es una copia de java.util.linkedList. @autor Josh Bloch
/**
* Returns the first element in this list.
*
* @return the first element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
Actualización sobre la respuesta:
actualización 1: ¿el código anterior es el mismo que el siguiente?
// as far as I know, it is the same as without throws
public E getFirst() throws NoSuchElementException {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
Actualización 2: Para excepción comprobada. ¿Necesito tener "tiros" en la firma? Sí.
// has to throw checked exception otherwise compile error
public String abc() throws IOException{
throw new IOException();
}
Tienes bastante razón. Excepto por una cosa que mencionaré en un momento.
los lanzamientos son tan parte del método API como el nombre y los parámetros. Los clientes saben que si llaman a ese método, deben manejar esa excepción, simplemente tirándola o atrapándola y manejándola (lo que de hecho puede implicar lanzar otra excepción que envuelve el original). Los tiros se dirigen en tiempo de compilación.
lanzar es el acto real de dejar que el tiempo de ejecución sepa que sucedió algo malo, que de hecho se ha producido la condición excepcional que nos preocupaba. Por lo tanto, debe ser tratado en tiempo de ejecución.
Pero no estaba del todo bien cuando dijo: "Los lanzamientos en la firma del método siempre deberían aparecer si existe una declaración de lanzamiento en el método". Eso es a menudo cierto pero no siempre. También podría llamar a otro método que lance una excepción dentro de mi método, y si no lo encuentro, mi método debe lanzarlo. En ese caso, no hay un lanzamiento explícito de la misma excepción por mi parte.
El punto final es que solo necesita declarar una excepción en los lanzamientos cuando la excepción es una excepción marcada , lo que significa que es del otro lado de la jerarquía de la clase Exception de RuntimeException. Las excepciones comprobadas comunes son IOException y SQLException. Las excepciones marcadas deben aparecer en la parte de lanzamientos de la firma del método si no las maneja usted mismo. Cualquier subclase de RuntimeException, como NoSuchElementException en su ejemplo y también la odiada NullPointerException, es una excepción sin marcar y no tiene que ser capturada o lanzada ni nada.
Por lo general, usa las excepciones comprobadas para los problemas recuperables (donde el cliente sabe lo que puede suceder y puede manejar el problema y seguir adelante) y las excepciones no comprobadas para los problemas catastróficos (como no se puede conectar a la base de datos).
Si puede superar todas las cosas de AOP, this es una gran discusión de cómo usar efectivamente las excepciones marcadas y no comprobadas.
Vidya dio una gran respuesta a sus preguntas.
Las palabras más importantes son "El último punto es que solo necesita declarar una excepción en los tiros cuando la excepción es una excepción marcada"
Solo para mostrarte un código de ejemplo, ¿qué significa esto? Imagina que nos gustaría usar FileOutputStream para pasar algunos datos. La función se vería así:
public void saveSomeData() throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("input.txt");
out = new FileOutputStream("output.txt");
int c;
while ((c = out.read() != -1) {
in.write(c);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Close in
if (in != null) {
in.close(); // <-- If something bad happens here it will cause runtime error!
}
// Close out
...
}
}
Ahora imagine que, si no proporciona la excepción IOException y ocurre algo malo dentro de la declaración finalmente {}, se generará un error.
RuntimeException
s no tienen que ser manejadas en el bloque try-catch por lo que no tienen que ser declaradas como lanzadas y NoSuchElementException es RuntimeException
porque lo extiende.
throw
atributo de throw
en la firma del método, como ha adivinado correctamente, es una sugerencia para el compilador de que el método genera una excepción que debe ser detectada por el llamador. Este tipo de excepción, es decir, la excepción comprobada es algo que el llamante DEBE siempre capturar o enviar a su llamante nuevamente. Esto es algo a nivel de compilador, la firma especifica qué excepción puede lanzar el método: esto impone un try-catch
o reenvío en la persona que llama y una declaración de lanzamiento en algún lugar dentro del método, es una restricción que el desarrollador coloca para especificar algo sobre el comportamiento del método.
Por otro lado, otras excepciones, a saber, excepciones no comprobadas o en tiempo de ejecución , ( NoSucheElementException
es un ejemplo) son excepciones que no está obligado a especificar porque surgen de diferentes situaciones.
La diferencia conceptual es que la excepción marcada se usa generalmente para advertir sobre situaciones excepcionales que deberían ser manejadas de alguna manera (piense en la IOException
) por parte del desarrollador, mientras que las que no están marcadas son errores reales (como NullPointerException
o similar en su ejemplo NoSuchElementException
)