Estaba revisando el libro SCJP 6 de Kathe sierra y encontré estas explicaciones de lanzar excepciones en el método anulado. No lo entendí. Puede alguien explicármelo ?
El método de invalidación NO debe generar excepciones comprobadas que sean nuevas o más amplias que las declaradas por el método invalidado. Por ejemplo, un método que declara una FileNotFoundException no puede ser anulado por un método que declara una SQLException, Exception o cualquier otra excepción que no sea de tiempo de ejecución, a menos que sea una subclase de FileNotFoundException.
Respuestas:
Significa que si un método declara lanzar una excepción dada, el método de reemplazo en una subclase solo puede declarar lanzar esa excepción o su subclase. Por ejemplo:
SocketException extends IOException
, peroSQLException
no lo hace.Esto se debe al polimorfismo:
Si
B
hubiera decidido lanzarSQLException
, el compilador no podría obligarlo a capturarlo, porque se está refiriendo a la instancia deB
por su superclase -A
. Por otro lado, cualquier subclase deIOException
será manejada por cláusulas (catch o throws) que manejanIOException
La regla que necesita para poder referirse a objetos por su superclase es el principio de sustitución de Liskov.
Dado que las excepciones no marcadas se pueden lanzar en cualquier lugar, no están sujetas a esta regla. Puede agregar una excepción sin marcar a la cláusula throws como una forma de documentación si lo desea, pero el compilador no aplica nada al respecto.
fuente
@Override public void foo() {...}
es legal.El método anulado PUEDE lanzar cualquier excepción sin marcar (tiempo de ejecución), independientemente de si el método anulado declara la excepción
Ejemplo:
fuente
En mi opinión, es un error en el diseño de sintaxis de Java. El polimorfismo no debería limitar el uso del manejo de excepciones. De hecho, otros lenguajes de computadora no lo hacen (C #).
Además, un método se anula en una subclase más especializada para que sea más complejo y, por esta razón, más probable que arroje nuevas excepciones.
fuente
Proporciono esta respuesta aquí a la pregunta anterior, ya que ninguna respuesta dice el hecho de que el método principal no puede arrojar nada, esto es nuevamente lo que puede arrojar el método principal:
1) lanza la misma excepción
2) lanzar una subclase de la excepción lanzada del método anulado
3) no arrojes nada.
4) No es necesario tener RuntimeExceptions en los lanzamientos.
Puede haber RuntimeExceptions en lanzamientos o no, el compilador no se quejará de ello. RuntimeExceptions no son excepciones marcadas. Solo las excepciones marcadas deben aparecer en los lanzamientos si no se detectan.
fuente
Para ilustrar esto, considere:
Suponga que luego escribe:
Esto le dará un error de compilación, porque r.close () arroja una IOException, que es más amplia que FileNotFoundException.
Para solucionar esto, si escribe:
Obtendrá un error de compilación diferente, porque está implementando la operación perform (...), pero arrojando una excepción no incluida en la definición del método de la interfaz.
¿Porque es esto importante? Bueno, un consumidor de la interfaz puede tener:
Si se permitió que se lanzara la IOException, el código del cliente ya no es correcto.
Tenga en cuenta que puede evitar este tipo de problemas si utiliza excepciones sin marcar. (No estoy sugiriendo que lo hagas o no, eso es una cuestión filosófica)
fuente
Tomemos una pregunta de entrevista. Hay un método que arroja NullPointerException en la superclase. ¿Podemos anularlo con un método que arroje RuntimeException?
Para responder a esta pregunta, háganos saber qué es una excepción sin marcar y marcada.
Las excepciones marcadas deben capturarse o propagarse explícitamente como se describe en Manejo básico de excepciones try-catch-billion. Las excepciones no marcadas no tienen este requisito. No tienen que ser capturados ni declarados arrojados.
Las excepciones marcadas en Java amplían la clase java.lang.Exception. Las excepciones no comprobadas extienden la excepción java.lang.RuntimeException.
La clase pública NullPointerException extiende RuntimeException
Las excepciones no comprobadas extienden la excepción java.lang.RuntimeException. Por eso, NullPointerException es una excepción no comprobada.
Tomemos un ejemplo: Ejemplo 1:
El programa se compilará correctamente. Ejemplo 2:
El programa también se compilará con éxito. Por lo tanto, es evidente que no ocurre nada en caso de excepciones no comprobadas. Ahora, echemos un vistazo a lo que sucede en el caso de las excepciones marcadas. Ejemplo 3: cuando la clase base y la clase secundaria arrojan una excepción marcada
El programa se compilará correctamente. Ejemplo 4: cuando el método de la clase secundaria arroja una excepción de borde comprobado en comparación con el mismo método de la clase base.
El programa no se podrá compilar. Por lo tanto, debemos tener cuidado cuando utilizamos excepciones marcadas.
fuente
digamos que tiene una superclase A con el método M1 lanzando E1 y la clase B derivada de A con el método M2 anulando M1. M2 no puede lanzar nada DIFERENTE o MENOS ESPECIALIZADO que E1.
Debido al polimorfismo, el cliente que usa la clase A debería poder tratar B como si fuera A. Inharitance ===> Is-a (B is-a A). ¿Qué pasa si este código que trata con la clase A maneja la excepción E1, ya que M1 declara que lanza esta excepción marcada, pero luego se lanza un tipo diferente de excepción? Si M1 estaba lanzando IOException, M2 bien podría lanzar FileNotFoundException, ya que es una IOException. Los clientes de A podrían manejar esto sin problemas. Si la excepción lanzada fuera más amplia, los clientes de A no tendrían la oportunidad de saberlo y, por lo tanto, no tendrían la oportunidad de detectarlo.
fuente
Bueno, java.lang.Exception se extiende a java.lang.Throwable. java.io.FileNotFoundException extiende java.lang.Exception. Entonces, si un método arroja java.io.FileNotFoundException, entonces en el método de anulación no puede arrojar nada más alto en la jerarquía que FileNotFoundException, por ejemplo, no puede lanzar java.lang.Exception. Sin embargo, podría lanzar una subclase de FileNotFoundException. Sin embargo, se verá obligado a manejar la excepción FileNotFoundException en el método anulado. ¡Crea un código y pruébalo!
Las reglas están ahí para que no pierda la declaración de throws original al ampliar la especificidad, ya que el polimorfismo significa que puede invocar el método anulado en la superclase.
fuente
El método de invalidación NO debe generar excepciones comprobadas que sean nuevas o más amplias que las declaradas por el método invalidado.
Ejemplo:
fuente
El método de invalidación NO debe generar excepciones comprobadas que sean nuevas o más amplias que las declaradas por el método invalidado.
Esto simplemente significa que cuando anula un método existente, la excepción que arroja este método sobrecargado debe ser la misma excepción que arroja el método original o cualquiera de sus subclases .
Tenga en cuenta que la verificación de si se manejan todas las excepciones marcadas se realiza en tiempo de compilación y no en tiempo de ejecución. Entonces, en el momento de la compilación, el compilador de Java verifica el tipo de excepción que arroja el método anulado. Dado que el método anulado se ejecutará solo se puede decidir en tiempo de ejecución, no podemos saber qué tipo de excepción tenemos que detectar.
Ejemplo
Digamos que tenemos class
A
y su subclaseB
.A
tiene métodom1
y la claseB
ha anulado este método (llamémoslom2
para evitar confusiones ..). Ahora digamosm1
lanzamientosE1
ym2
lanzamientosE2
, que esE1
la superclase de. Ahora escribimos el siguiente código:Tenga en cuenta que
m1
no es más que una llamada am2
(de nuevo, las firmas de métodos son las mismas en los métodos sobrecargados, así que no se confunda conm1
ym2
... son solo para diferenciar en este ejemplo ... ambos tienen la misma firma). Pero en el momento de la compilación, todo lo que hace el compilador de Java es ir al tipo de referencia (ClassA
en este caso) verifica el método si está presente y espera que el programador lo maneje. Entonces, obviamente, tirarás o atraparásE1
. Ahora, en tiempo de ejecución, si el método sobrecargado arrojaE2
, que esE1
la superclase, entonces ... bueno, está muy mal (por la misma razón no podemos decirloB myBObj = new A()
). Por tanto, Java no lo permite. Las excepciones no comprobadas generadas por el método sobrecargado deben ser iguales, subclases o inexistentes.fuente
Para entender esto, consideremos un ejemplo en el que tenemos una clase
Mammal
que define unreadAndGet
método que lee algún archivo, realiza alguna operación en él y devuelve una instancia de claseMammal
.La clase
Human
extiende la claseMammal
y anula elreadAndGet
método para devolver la instancia de enHuman
lugar de la instancia deMammal
.Para llamar
readAndGet
, necesitaremos manejarIOException
porque es una excepción marcada y el mamífero lareadAndMethod
está lanzando.Y sabemos que el compilador
mammal.readAndGet()
está recibiendo una llamada desde el objeto de la clase,Mammal
pero en tiempo de ejecución, la JVM resolverá lamammal.readAndGet()
llamada al método a una llamada desde la claseHuman
porquemammal
está en esperanew Human()
.Método
readAndMethod
deMammal
está lanzandoIOException
y porque es un compilador excepción comprobada nos obligará a cogerlo siempre que llamamosreadAndGet
elmammal
Ahora suponga que
readAndGet
inHuman
está lanzando cualquier otra excepción marcada, por ejemplo, Exception y sabemosreadAndGet
que se llamará desde la instancia deHuman
becausemammal
is holdingnew Human()
.Debido a que para el compilador se está llamando al método
Mammal
, el compilador nos obligará a manejar solo,IOException
pero en tiempo de ejecución sabemos que el método lanzará unaException
excepción que no se está manejando y nuestro código se romperá si el método arroja la excepción.Es por eso que se evita en el nivel del compilador y no se nos permite lanzar ninguna excepción marcada nueva o más amplia porque no será manejada por JVM al final.
También hay otras reglas que debemos seguir al anular los métodos y puede leer más sobre Por qué debemos seguir las reglas de anulación de métodos para conocer las razones.
fuente
¿Qué explicación atribuimos a lo siguiente?
Class DerivedClass.java lanza una excepción en tiempo de compilación cuando el método de impresión arroja una Excepción, el método print () de baseclass no arroja ninguna excepción
Puedo atribuir esto al hecho de que Exception es más estrecha que RuntimeException, puede ser No Exception (Runtime error), RuntimeException y sus excepciones secundarias
fuente
El método de reemplazo de la subclase solo puede generar múltiples excepciones marcadas que son subclases de la excepción marcada del método de la superclase, pero no puede generar múltiples excepciones marcadas que no están relacionadas con la excepción marcada del método de la superclase
fuente
Java le ofrece la opción de restringir las excepciones en la clase principal, porque supone que el cliente restringirá lo que se detecta . En mi humilde opinión, esencialmente nunca debería utilizar esta "función", porque sus clientes pueden necesitar flexibilidad en el futuro.
Java es un lenguaje antiguo que está mal diseñado. Los idiomas modernos no tienen tales restricciones. La forma más fácil de evitar este defecto es hacer que su clase base sea
throw Exception
siempre. Los clientes pueden lanzar excepciones más específicas pero hacer que sus clases base sean realmente amplias.fuente
Regla de manejo de excepciones de verificación y no verificadas en métodos anulados
- Cuando el método de clase principal no declara ninguna excepción, el método de invalidación de la clase secundaria puede declarar ,
-Cuando el método de clase principal declara una excepción no verificada, entonces el método de invalidación de clase secundaria puede declarar ,
- Cuando el método de clase principal declara una excepción marcada, entonces el método de invalidación de la clase secundaria puede declarar ,
Toda la conclusión anterior es cierta, incluso si la combinación de excepción marcada y no marcada se declara en el método de la clase principal
Árbitro
fuente