|
Indice | Temas Recientes | Quién Está en LÃnea | Lista de Usuarios | Mi Perfil | Búsqueda | Ayuda |
![]() |
mvnForum » Listar todos los foros » Foro: Curso PLJ » Tema: Excepciones. Acerca de throw. |
Total de mensajes en este tema: 5 |
[Eliminar este Tema]
[Mover este Tema] [AÅadir a Mis Favoritos] [AÅadir un aviso a este tema] [Publicar nuevo tema] |
Autor |
|
![]() Extranjero
|
Hola. He estado leyendo la teorÃa de excepciones del módulo 2 y no me ha quedado claro el punto 2.1.3. Lanzamiento de excepciones. Entiendo que con el bloque catch se capturan las excepciones que se producen. ¿Pero que hace throw? ¿Lanza la excepción manualmente en lugar de lanzarse automáticamente? ¿Si es asà la excepción busca un bloque manejador en el bloque en el que se encuentra? ¿Si el bloque que la maneja no existe en esa función busca en la de nivel superior? ¿Tiene que tener la función superior alguna declaración para capturar la excepcion? ¿Y si la excepción no se ha lanzado con throw sino automáticamente puede pasar al nivel superior? AgradecerÃa que alguien me ayudara a entender esto y si es posible que adjunte algún ejemplo donde se vea claro. Un saludo. |
||
|
![]() Miembro
|
Hola. Vamos a ver, intentaré resumirlo todo lo que pueda ![]() Cuando en un método de una clase Java puede producirse un error, y ese error es de lo que en los apuntes llama "tipo checked" (es decir, algo asà como "predecible"), se debe o bien capturar, o bien lanzar la excepción correspondiente, para que quien llame a ese método tenga en cuenta que se puede producir ese error. Si aplicamos esto a los sucesivos niveles de llamadas, resulta que un throw que se produce en un método, puede volverse a producir en el que le llama, y en el que llama a este segundo... y asà sucesivamente. El tema está entonces en ver hasta dónde queremos que llegue el error. Si en uno de esos métodos intermedios hacemos un "catch" de la excepción, capturamos el error, y sacamos el mensaje correspondiente o hacemos lo que toque. En ese momento la propagación del error termina. Si en ningún método capturamos el error, el "main" que hayamos ejecutado será su última parada, antes de salir por el monitor. Un método útil para seguir todo esto es "printStackTrace" de la clase "Exception" (y por ende, de todas sus subclases). Con este método puedes ver una traza de por dónde ha ido propagándose una determinada excepción. Como pone en los apuntes, hay dos tipos de excepciones básicamente: las checked y las no checked. Las primeras, cuando llamamos al método que las produce, tenemos OBLIGACION de capturarlas, o bien de pasarlas con otro "throw" al siguiente método en el árbol de llamadas. Eso durará como mucho hasta llegar al "main" que ejecutemos, donde obligatoriamente tendremos que capturarla para que el programa compile. Las no checked no hace falta capturarlas, porque en teorÃa no se sabe cuándo pueden producirse. Estas no dan errores de compilación si no las capturamos ni las lanzamos, y si no tenemos cuidado pueden provocar excepciones en la ejecución principal. Veamos un ejemplo de tratamiento de excepciones con checked y no checked. ---------------------------------------------------------- EJEMPLO con tipo checked: Supongamos que tenemos un método que puede lanzar una excepcion de tipo MiExcepcion (que es de tipo checked): public void metodo() throws MiExcepcion { if (... condicion ...) throw new MiExcepcion ("Error en el metodo..."); ... resto del codigo del método } Al ser de tipo checked, si queremos lanzarla en un método tenemos que poner la cláusula "throws" en su cabecera, y luego lanzarla con un throw dentro. Supongamos que luego tenemos otro método "m2" que llama a este. El compilador nos dará ERROR si no capturamos la excepción: public void m2() { try { metodo(); // Esta lÃnea sin el try darÃa ERROR } catch (MiExcepcion e) { e.printStackTrace(); } } o bien declaramos que puede lanzarse a otro nivel: public void m2() throws MiExcepcion { if (... condicion...) throw new MiExcepcion ("Propagando el error..."); ... // Aqui no hace falta try //porque declaras que puede lanzarse metodo(); ... } Si optamos por lo primero, ahà se acaba el error. Si elegimos lo segundo, la cadena continuará hasta que la capturemos en otro método después. Como muy tarde, deberemos capturarla en el método "main" que ejecutemos, que será el último método de todos. Ahà ya no podemos hacer más "throw". En resumen, siempre que estemos tratando una excepción de tipo checked tenemos OBLIGACION de capturarla, o de declarar que se puede lanzar. Si no no podremos compilar el programa. ---------------------------------------------------------- EJEMPLO con tipo no checked: Supongamos por otra parte que tenemos un método que recorre un array. Si no tenemos cuidado, puede ser que nos salgamos de los lÃmites del array, y salte una excepción de tipo ArrayIndexOutOfBoundsException. Sin embargo, esta excepción no es checked, asà que no tenemos obligación de capturarla. Es decir, si el método lo dejamos asÃ: public void m3() { int[] elementos = new int[4]; for (int i = 0; i < 10; i++) { System.out.println("Elemento: " + elementos); } } Como tenemos un array de 4 elementos, en cuanto el bucle pase de la 4ª posicion lanzará una excepción de tipo ArrayIndexOutOfBounds. No nos va a dar error de compilación como en las checked. Asà que este tipo de excepciones es voluntario capturarlas. PodrÃamos dejar el método bien hecho con algo como: public void m3() { int[] elementos = new int[4]; for (int i = 0; i < 10; i++) { try { System.out.println("Elemento: " + elementos); } catch (ArrayIndexOutOfBoundsException e) {} } } Pero como digo, no es necesario ---------------------------------------------------------- Bueno, después de todo este "rollazo", espero haber sido de ayuda. Si no, dÃmelo e intentaré explicártelo de otra forma, pero no te quedes con la duda porque las excepciones son básicas para todo lo que va a venir después. Un saludo! Nacho. |
||
|
![]() Extranjero
|
Hola de nuevo. Gracias por la explicación. Entonces, si no lo he entendido mal, lo que hace throw es pasar la excepción al métdo superior. ¿Me equivoco? Pero aún no me he enterado bien y me quedan algunas dudas acerca de cómo debemos usar el throw cuando queremos que una excepción se propague. En el caso de try-catch, se especifica un bloque donde "permanecer alerta" y, si se produce una excepción pasar el control al bloque catch. En estos casos la excepción salta automáticamente cuando se viola una determinada condición. ¿Pero qué pasa con throw? ¿Tenemos que chequear nosotros si se cumple una condición y entonces lanzar la excepción? CreÃa que la excepción ArrayIndexOutOfBoundsException, por ejemplo, se producÃa automáticamente al acceder fuera de los lÃmites de un array... ¿Qué hace el programa cuando llega a un throw? ¿Se detiene y pasa al nivel superior en busca de un catch? ¿Cómo se volverÃa a lanzar la excepción hacia el siguiente nivel desde allÃ? ¿...? Por último, en el método divide del ejercicio 7 de la sesión 6, ¿por qué no se pone divide(int dividendo, int divisor) throws IllegalArgumentException? Saludos. |
||
|
![]() Extranjero
|
NOTA: A la última pregunta ya he encontrado la solución en los ejercicios. |
||
|
![]() Miembro
|
Hola otra vez ![]() El "throw" se puede usar con cualquier excepción (es decir, puedes lanzar cualquier excepción), la diferencia está en que las que no son tipo checked (como ArrayIndexOutOfBounds, o IllegalArgument) no lo necesitan para lanzarse, como tampoco necesitan el "throws". Simplemente cuando suceda un error del tipo de la excepción se lanzará la misma. Eso sÃ, cuando uses "throw" tienes que comprobar tú a mano que se está produciendo un error. Es decir, si quieres lanzar un IllegalArgumentException tú, y no dejar que lo haga el programa, tienes que comprobar tú a mano que el argumento no es válido. De la misma forma, si quieres indicar que se está saliendo de los lÃmites de un array, debes comprobar tú esos lÃmites y lanzar el ArrayIndexOutOfBounds. Si no lo haces tú, lo hará el programa. La diferencia está en que si lo haces tú controlas un poco más cuándo y dónde se produce ese error. Sobre lo de cómo propagar el throw de un nivel al siguiente, es sencillo. Si por ejemplo todo empieza aquÃ: public void m1() throws UnaExcepcion { if (...condicion...) throw new UnaExcepcion(...); } Y luego este método llama al anterior: public void m2() { m1(); } Tenemos dos opciones: - Capturar la excepcion y acabar con la propagación del error. Para eso ponemos un bloque try...catch y listo: public void m2() { try { m1(); } catch (UnaExcepcion e) { ... } } - Propagar la excepción. Basta con definir en la cabecera del método, con un "throws", que este método puede lanzar excepciones de ese tipo. No hace falta que hagamos un "throw" dentro, porque eso ya lo hace el método que la lanzó originalmente: public void m2() throws UnaExcepcion { m1(); } De esta otra forma, un método m3 que llame al anterior podrÃa optar por lo mismo: public void m3() { try { m2(); } catch (UnaExcepcion e) {} } o bien public void m3() throws UnaExcepcion { m2(); } ... y asà sucesivamente. De todas formas, es IMPORTANTE que tengas en cuenta que todo esto se aplica OBLIGATORIAMENTE para excepciones de tipo checked (es decir, las que no sean subtipos de RuntimeException). Para las otras, es voluntario tratar todo esto, puesto que serán excepciones que se considera que no se pueden predecir. |
||
|
[Versión imprimible] [Publicar nuevo tema] |