El documento explica las excepciones en Java. Indica que una excepción indica un problema durante la ejecución de un programa y que el manejo de excepciones permite crear aplicaciones que puedan resolver dichos problemas. Describe algunos tipos comunes de excepciones como ArithmeticException, NullPointerException e IOException. También explica cómo usar bloques try-catch para manejar excepciones y evitar que el programa crashee.
1. EXCEPCIONES EN JAVA
Una excepción es la indicación de un problema que ocurre durante la ejecución de un programa. El
manejo de excepciones le permite crear aplicaciones que puedan resolver (o manejar) las excepciones. En
muchos casos, el manejo de una excepción permite que el programa continúe su ejecución como si no se
hubiera encontrado el problema.
Las excepciones se pueden presentan en todo tipo de sentencias, desde la más sencilla hasta la más
complicada. Un ejemplo del caso sencillo en la división por cero.
public class Aplicacion {
public static void main(String[] args) {
Scanner scanner= new Scanner(System.in);
System.out.println("Agregue el numerador");
int numerador = scanner.nextInt();
System.out.println("Agregue el denominador");
int denominador = scanner.nextInt();
int resultado = dividir(numerador, denominador);
System.out.println(String.format("El númerador es: %d", resultado));
}
/**
* permite realizar la divición entre dos numeros entereos
* @param numerador número que sera dividido
* @param denominador numero que será el divisor
* @return resultado de la división
*/
private static int dividir(int numerador, int denominador) {
return numerador/denominador; // posible divición entre cero
}
}
Cuando se ejecuta el código anterior y se agrega un denominador cero, se tiene la siguiente excepción:
Lenguaje de
programación
Técnica profesional en desarrollo de software
Profesor: Andrés Herrera R. Mail: jherrera@eam.edu.co
Laboratorio
Excepciones básicas
Nombre:_________________________________________________________________________
2. 2
Las excepciones se lanzan (es decir, la excepción ocurre) cuando en la aplicación se detecta un problema que
no se puede manejar. Cuando se introduce el valor 0 (cero) como denominador se muestran varias líneas de
información en respuesta a esta entrada invalida. Esta información se conoce como el rastreo de la pila, la
cual lleva el nombre de la excepción (java.lang.ArithmeticException) en un mensaje descriptivo, que indica el
problema que ocurrió́ y la pila de llamadas a métodos (es decir, la cadena de llamadas) al momento en que
ocurrió́ la excepción. La primera línea específica que ha ocurrido una excepción ArithmeticException. El texto
después del nombre de la excepción (“/ by zero”) indica que esta excepción ocurrió́ como resultado de un
intento de dividir entre cero. Otro tipo de excepción se da cuando se agrega tipos de datos que no
corresponde a los esperado (como decimales o cadenas), dicha excepción es InputMismatchException.
Cuando ocurren excepciones y se muestran los rastreos de la pila, el programa puede terminar. Esto no
siempre ocurre en Java; algunas veces un programa puede continuar, aun cuando haya ocurrido una
excepción y se imprima un rastreo de pila. En tales casos, la aplicación puede producir resultados
inesperados. Por ejemplo, una aplicación de interfaz gráfica de usuario (GUI) por lo general se seguirá́
ejecutando.
Ahora que pasaría si se da manejo a las excepciones, tal y como se hace en el ejemplo siguiente:
public class Aplicacion {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean continuar = true;
do {
try {
System.out.println("Agregue el numerador");
int numerador = scanner.nextInt();
System.out.println("Agregue el denominador");
int denominador = scanner.nextInt();
int resultado = dividir(numerador, denominador);
System.out.println(String.format("El numerador es: %d", resultado));
continuar = false;
} catch (ArithmeticException e) {
System.out.println(String.format("Error: %s", e.getMessage()));
System.out.println("Un denominador no puede ser cero");
} catch (InputMismatchException e) {
System.out.println(String.format("Error: %s", e.getMessage()));
System.out.println("Se deben usar números enteros");
scanner.nextLine();
}
3. 3
} while (continuar);
}
/**
* permite realizar la división entre dos números enteros
* @param numerador
* número que será dividido
* @param denominador
* número que será el divisor
* @return resultado de la división
*/
private static int dividir(int numerador, int denominador) {
return numerador / denominador; // posible división entre cero
}
}
En el código anterior se resalta el uso de la sentencia try, que encierra el código que podría lanzar (throw) una
excepción y el código que no debería ejecutarse en caso de que ocurra una excepción (es decir, si ocurre una
excepción, se omitirá́ el resto del código en el bloque try).
Un bloque catch (también conocido como clausula catch o manejador de excepciones) atrapa (es decir,
recibe) y maneja una excepción. Un bloque catch empieza con la palabra clave catch y va seguido por un
parámetro entre paréntesis (conocido como el parámetro de excepción) y un bloque de código encerrado
entre llaves. Después del bloque try mínimo debe haber un bloque catch. Cada bloque catch especifica entre
paréntesis un parámetro de excepción, que identifica el tipo de excepción que puede procesar el manejador.
Cuando ocurre una excepción en un bloque try, el bloque catch que se ejecuta es el primero cuyo tipo
coincide con el tipo de la excepción que ocurrió́ . Cuando no hay un bloque catch que coincida con la
excepción, esta no se puede atrapar (se considera una excepción no atrapada).
Si ocurre una excepción en un bloque try este termina de inmediato, y el control del programa se transfiere al
primero de los siguientes bloques catch en los que el tipo del parámetro de excepción coincide con el tipo de
la excepción que se lanzó́ .
Una vez que se maneja la excepción, el control del programa no regresa al punto de lanzamiento, ya que el
bloque try ha expirado, Esto se conoce como el modelo de terminación del manejo de excepciones. Es
importante no confundir los términos “bloque try” e “instrucción try; este último incluye el bloque try, así́ como
los siguientes bloques catch y/o un bloque finally.
Excepciones más comunes
Nombre Descripción
Throwable
La clase Throwable es la clase base que representa a todas las
excepciones que pueden ocurrir en un programa Java. En esta
clase existen varios métodos útiles, que son heredados por las
distintas subclases de Throwable. Uno de los métodos más útiles
definido en la clase Throwable y heredado por todas sus subclases
es el método getMessage. Este método permite obtener
información de una excepción. Sólo existen dos subclases directas
4. 4
de “Throwable” en la API de Java (Exception y Error).
Error
Se utiliza para representar algunos errores poco comunes que
pueden tener lugar cuando ejecutamos una aplicación en Java
(por ejemplo, que la JVM se quede sin recursos).
Exception
Representa excepciones comprobadas y no comprobadas. Efectúa
una continuación del código, manejándolo por una modificación de
código en vez de terminar el programa. Es causado por efectos del
entorno y puede gestionarse debido a que en la mayoría de las
veces son errores ocasionados por el usuario del programa.
RuntimeException
Es usada en excepciones no comprobadas que pueden ser
resultantes de código defectuoso. Este tipo de excepciones indican
un problema de diseño o implementación, por lo regular un
programa que funcione bien no genera este tipo de excepciones,
por lo que no es recomendable gestionarlas.
IOException
Ésta es otra de las excepciones más comúnmente usadas en la
librería de Java. Los métodos de Java la lanzan siempre que
encuentren un problema en cualquier operación de lectura o
escritura a un medio externo (lectura o escritura a un fichero).
ClassCastException Tiene lugar cuando se intenta hacer un casting de un objeto a una
clase de la que no es subclase.
NullPointerException
Quizá́ ésta sea la excepción que más comúnmente aparece
cuando se trabaja con Java. Surge siempre que se intenta acceder
a cualquier atributo o método de un objeto que tiene asignado un
valor “null”.
NumberFormatException
Esta excepción tiene lugar cuando se intenta convertir un dato de
tipo “String” a algún tipo de dato numérico, pero el dato de tipo
“String” no tiene el formato adecuado.
IndexOutOfBoundsException
Excepción que tiene lugar cuando se intenta acceder a un índice
de un “array”, “String” o “vector” mayor que el número de
elementos de dicha estructura.
FileNotFoundException
En general, la lanzan diversos métodos de la API de Java cuando
se intenta abrir algún fichero que no existe o no ha sido
encontrado.
StackOverflowError Típicamente lanzado cuando un método es muy recursivo y cada
llamada se va añadiendo al stack.
PRACTICA
1. Nombre en qué casos ha aparecido la excepción ClassCastException en sus aplicaciones. Realice un ejemplo que lance
dicha excepción con y sin la instrucción try.
2. Nombre en qué casos ha aparecido la excepción NullPointerException en sus aplicaciones. Realice un ejemplo que lance
dicha excepción con y sin la instrucción try.
3. Nombre en qué casos ha aparecido la excepción NumberFormatException en sus aplicaciones. Realice un ejemplo que
lance dicha excepción con y sin la instrucción try.
4. Nombre en qué casos ha aparecido la excepción IndexOutOfBoundsException en sus aplicaciones. Realice un ejemplo que
lance dicha excepción con y sin la instrucción try.
5. 5
PARTE 2
JERARQUÍA DE EXCEPCIONES EN JAVA
Todas las clases de excepciones heredan, ya sea en forma directa o indirecta, de la clase Exception,
formando una jerarquía de herencias. Los programadores pueden extender esta jerarquía para crear sus
propias excepciones.
Throwable es la superclase de las excepciones, las dos subclases directas son Exception y Error. La
clase Exception y sus subclases representan situaciones excepcionales que pueden ocurrir en un programa
en Java, y que pueden ser atrapadas por la aplicación. La clase Error y sus subclases representan las
situaciones anormales que ocurren en la JVM. La mayoría de los excepciones tipo Error ocurren con poca
frecuencia y no deben ser atrapadas por las aplicaciones; por lo general no es posible que las aplicaciones se
recuperen de los errores tipo Error. En la Figura 1 se muestra con claridad la jerarquía de herencia básica, ya
que la jerarquía de excepciones de Java contiene cientos de clases.
Figura 1. Jerarquía de herencias de las excepciones en Java.
Excepciones verificadas y no verificadas (marcadas o no marcadas)
Java clasifica a las excepciones en dos categorías: excepciones verificadas y excepciones no verificadas.
Esta distinción es importante, ya que el compilador de Java implementa un requerimiento de atrapar o
declarar para las excepciones verificadas. El tipo de una excepción determina si es verificada o no verificada.
Todos los tipos de excepciones que son subclases directas o indirectas de la clase RuntimeException son
excepciones no verificadas. Por lo general, se deben a los defectos en el código de nuestros programas.
Algunos ejemplos de excepciones no verificadas son las excepciones ArraylndexOutOfBoundsException y
ArithmeticException. Todas las clases que heredan de la clase Exception pero no de la clase
RuntimeException se consideran como excepciones verificadas. Por lo general, dichas excepciones son
provocadas por condiciones que no están bajo el control del programa; por ejemplo, en el procesamiento de
6. 6
archivos, el programa no puede abrir un archivo debido a que no existe. Las clases que heredan de la clase
Error se consideran como no verificadas.
El compilador verifica cada una de las llamadas a un método, junto con su declaración, para determinar si el
método lanza excepciones verificadas. De ser así́, el compilador asegura que la excepción verificada sea
atrapada o declarada en una cláusula throws.
Si un método llama a otros métodos que lanzan explícitamente excepciones verificadas, éstas deben
atraparse o declararse en el método. Si una expresión puede manejarse de manera significativa en un
método, éste debe atrapar la excepción en vez de declararla.
Si un método intenta lanzar de manera explícita una excepción verificada (o si llama a otro método que lance
una excepción verificada),y ésta no se enumera en la cláusula throws de ese método, se produce un error de
compilación.
A diferencia de las excepciones verificadas, el compilador de Java no verifica el código para determinar si una
excepción no verificada es atrapada o declarada. Por lo general, las excepciones no verificadas se pueden
evitar mediante una codificación apropiada.
Por ejemplo, la excepción ArithmeticException puede evitarse si el método se asegura de que el denominador
no sea cero antes de tratar de realizar la división. No es obligatorio que se enumeren las excepciones no
verificadas en la cláusula throws de un método; aun si se hace, no es obligatorio que una aplicación atrape
dichas excepciones.
Nota:
Aunque el compilador no implementa el requerimiento de atrapar o declarar para las excepciones no
verificadas, se debe deberá́ proporcionar un código apropiado para el manejo de excepciones cuando sepa
que podrían ocurrir.
Atrapar los tipos de las subclases en forma individual puede ocasionar errores si no se evalúa uno o más de
los tipos de subclase en forma explícita. Al colocar un bloque catch para el tipo de la superclase después de
los demás bloques catch para todas las subclases de esa superclase asegura que todas las excepciones de
las subclases se atrapen en un momento dado.
Throws
Esta cláusula especifica las excepciones que lanza el método. Contiene una lista separada por comas de las
excepciones que lanzará el método, en caso de que ocurran varios problemas. Dichas excepciones pueden
lanzarse mediante instrucciones en el cuerpo del método, o a través de métodos que se llamen desde el
cuerpo.
Bloque finally
Java realiza la recolección automática de basura en la memoria que ya no es utilizada por los programas,
evitando así́ la mayoría de las fugas de memoria. Sin embargo, pueden ocurrir otros tipos de fugas de
recursos en Java. Por ejemplo, los archivos, las conexiones de bases de datos y conexiones de red que no se
cierran apropiadamente cuando ya no se necesitan, podrían no estar disponibles para su uso en otros
programas.
7. 7
Nota:
Java no elimina completamente las fugas de memoria. Java no hace recolección de basura en un objeto sino
hasta que no existen más referencias a ese objeto. Por lo tanto, si los programadores mantienen por error
referencias a objetos no deseados, pueden ocurrir fugas de memoria. Para ayudar a evitar este problema,
asigne null a las variables de tipo por referencia cuando ya no las necesite.
El bloque finally es opcional. Si está presente, se coloca después del último bloque catch. Si no hay bloques
catch, el bloque final sigue justo después del bloque try. El bloque finally se ejecutará, se lance o no una
excepción en el bloque try correspondiente. El bloque finally también se ejecutará si un bloque try se sale
mediante el uso de una instrucción return, break o continúé, o simplemente al llegar a la llave derecha de
cierre del bloque try. El bloque finally no se ejecutará si la aplicación sale antes de tiempo de un bloque try,
llamando al método System.exit.
Como un bloque finally casi siempre se ejecuta, por lo general contiene código para liberar recursos. Suponga
que se asigna un recurso en un bloque try. Si no ocurre una excepción, se ignoran los bloques catch y el
control pasa al bloque finally, que libera el recurso. Después, el control pasa a la primera instrucción después
del bloque finally.
Si ocurre una excepción en el bloque try, esté termina. Si el programa atrapa la excepción en uno de los
bloques catch correspondientes, procesa la excepción, después el bloque finally libera el recurso y el control
pasa a la primera instrucción después del bloque finally. A continuación se muestra la estructura de la
instrucción try usando finally.
try{
//Instrucciones que se intentan ejecutar, si se produce una
//situación inesperada se lanza una excepción
}
catch(tipoExcepcion e){
//Instrucciones para tratar esta excepción
}
catch(otroTipoExcepcion e){
//Instrucciones para tratar esta excepción
}
//Se pueden escribir tantos bloques catch como sean necesarios
finally{
// instrucciones que se ejecutarán siempre
}
Lanzar Excepciones
La instrucción throw se ejecuta para indicar que ha ocurrido una excepción. Los programadores pueden lanzar
excepciones mediante el uso de la instrucción throw. En la siguiente figura se muestra un ejemplo de cómo
debe ser la estructura de un método que lanza una excepción.
8. 8
Figura 2. Estructura de un método usando excepciones verificadas y no verificadas.
PRACTICA
1- Cree un proyecto de nombre <<Excepciones verificadas y no verificadas>>.
2- Cree un paquete de nombre <<com.EAM.lenguaje.excepciones>>
3- Cree una clase de nombre <<PracticaExcepciones>> con su respectivo método main.
4- Agregue el siguiente código dentro de la clase PracticaExcepciones:
public static void noLanzaExcepcion() {
try {
System.out.println("Método noLanzaExcepcion");
} catch (Exception excepción) {
System.err.println(excepción);
} finally {
System.err.println("Se ejecuto Finally en noLanzaExcepcion");
}
System.out.println("Fin del métodonoLanzaExcepcion");
}
5- Use el método anterior en el main. Ejecute la aplicación y verifique el funcionamiento.
6- Agregue el siguiente código dentro de la clase PracticaExcepciones:
public static void lanzaExcepcion() throws Exception {
try {
System.out.println("Método lanzaExcepcion");
throw new Exception();
} catch (Exception excepción) {
System.err.println(excepción);
throw excepción;
} finally {
System.err.println("Se ejecuto Finally en lanzaExcepcion");
}
}
7- Use el método anterior en el main. Ejecute la aplicación y verifique el funcionamiento.
9. 9
8- Modifique el código agregado en la clase anterior (ejemplo de división por cero) y agregue throws, throw y finally donde
considere necesario.
9- Revise el siguiente código, y analice como se debería de mostrar el rastreo de pila.
public class UsoDeExcepcionesEncadenadas {
public static void main(String[] args) {
try {
metodo1();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void metodo1() throws Exception{
metodo2();
}
public static void metodo2() throws Exception{
metodo3();
}
public static void metodo3() throws Exception{
throw new Exception("La excepción se lanzó en metodo3" );
}
}
Ahora lance las excepciones en el método uno y dos desde el bloque catch, use el siguiente método
constructor de Exception:
throw new Exception("mensaje", causa);
Analice el cambio que se presenta el rastreo de pila.
ENTREGABLE
Mostrar la Practica realizada en su totalidad.
BIBLIOGRAFÍA
Deitel, P. J. & Deitel, H. M. (2012). Como Programar en java. Novena edición. México: Prentice Hall.