Вы находитесь на странице: 1из 29

Manejo de Excepciones

H. Tejeda

Abril 2016

Indice

1. Introducci
on 1

2. Intentar c
odigo y capturar excepciones 5

3. Lanzar y atrapar excepciones m


ultiples 11

4. Bloque finally 14

5. Ventajas del manejo de excepci


on 16

6. Especificar excepciones que un m


etodo puede lanzar 18

7. Traza de excepciones en la pila de llamadas 21

8. Creaci
on de clases Exception propias 23

9. Uso de afirmaciones 26

1. Introducci
on

Una excepci on es una condici


on inesperada o error. Los programas que se escriben pueden generar
varios tipos de excepciones potenciales:

Podra emitir un comando para leer un archivo de un disco, pero el archivo no existe.

Podra intentar escribir datos a un disco, pero el disco esta lleno o no formateado.

Podra pedir entrada al usuario, pero el usuario ingresa un tipo de dato no valido.

1
Podra intentar acceder un arreglo con un subndice que no es valido.

Estos errores son llamados excepciones porque no son ocurrencias usuales. El manejo de excep-
ciones es el nombre para las tecnicas orientadas al objeto que manejan tales errores. Excepciones
no planeadas que ocurren durante la ejecucion del programa son tambien llamadas excepciones
en tiempo de ejecuci on, en contraste con errores de sintaxis que son descubiertos durante la
compilacion del programa.

Java incluye dos clases b


asicas de errores: Error y Exception. Ambas clases descienden de la clase
Throwable, como se muestra enseguida. Como todas las otras clases en Java, Error y Exception
originalmente descienden de Object.

java.lang.Object
|
+--java.lang.Throwable
|
+--java.lang.Exception
| |
| +--java.io.IOException
| |
| +--java.lang.RuntimeException
| | |
| | +--java.lang.ArithmeticException
| | |
| | +--java.lang.IndexOutOfBoundsException
| | | |
| | | +--java.lang.ArrayIndexOutOfBoundsException
| | |
| | +--java.util.NoSuchElementException
| | | |
| | | +--java.util.InputMismatchException
| | |
| | +--Otras...
| |
| +--Otras...
|
+--java.lang.Error
|
+--java.lang.VirtualMachineError
| |
| +--java.lang.OutOfMemoryError
| |
| +--java.lang.InternalError
| |
| +--Otras...
|
+--Otras...

2
La clase Error representa los errores mas serios de los cuales el programa usualmente no se pueden
recuperar. Podra haber memoria insuficiente para ejecutar un programa. Usualmente, no se usan o
implementan objetos Error en el programa. Un programa no se puede recuperar de las condiciones
Error por su propia cuenta.

La clase Exception comprende errores menos serios que representan condiciones no usuales que
surgen mientras un programa se ejecuta y del cual el programa se puede recuperar. Estos errores se
dan al usar un subndice de arreglo no valido o realizando ciertas operaciones aritmeticas ilegales.

Java muestra un mensaje Exception cuando el codigo del programa podra haber prevenido un
error. La aplicacion Division, c odigo 1, contiene en el metodo main() tres declaraciones de enteros,
peticiones al usuario de valores para dos variables, y el calculo del valor del tercer entero haciendo
la division de los valores dados.
1 import j a v a . u t i l . Scanner ;
2 public c l a s s D i v i s i o n {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int numerador , denominador , r e s u l t a d o ;
6 System . out . p r i n t ( I n g r e s a r e l numerador >> ) ;
7 numerador = e n t r a d a . n e x t I n t ( ) ;
8 System . out . p r i n t ( I n g r e s a r e l denominador >> ) ;
9 denominador = e n t r a d a . n e x t I n t ( ) ;
10 r e s u l t a d o = numerador / denominador ;
11 System . out . p r i n t l n ( numerador + / + denominador +
12 = + resultado );
13 }
14 }

C
odigo 1: La clase Division.

Como se muestra en la siguiente salida, al ejecutar la aplicacion Division y habiendo el usuario


ingresado un cero para el denominador, se genera un mensaje de excepcion. Java no permite division
entera por cero, pero la divisi on flotante por cero es permitida, dando el resultado Infinity.
Los programadores dicen que el programa experimento un choque, para indicar que el programa
termino prematuramente con un error. El termino choque quizas evoluciono del error de hardware
que ocurre cuando una cabeza de lectura/escritura abruptamente hace contacto con un disco duro,
para incluir los errores de software que causan la falla del programa.

$ java Division
Ingresar el numerador >> 3
Ingresar el denominador >> 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Division.main(Division.java:10)

De la salida de la aplicaci
on, mostrada previamente, la Exception es una java.lang.Arithmetic-
Exception la cual es una de muchas subclases de Exception. Java conoce mas de 75 categoras de
Exception con nombres raros como ActivationException, AlreadyBoundException, AWTExcep-
tion, CloneNotSupportedException, PropertyVetoException, y UnsupportedFlavorException.

3
Ademas del tipo de Exception que se muestra en la ejecucion se muestra alguna informacion del
error (/ by zero), el metodo que genero el error(Division.main), y el archivo y n
umero de lnea
para el error(Division.java, lnea 10).

En la siguiente salida se muestran dos ejecuciones mas de la aplicacion Division. En cada ejecuci on,
el usuario ha metido datos no enteros para el denominador, primero una cadena de carateres, y
luego un valor de punto flotante. De los mensajes de error se ve que en ambos casos la Exception
es una InputMismatchException. La u ltima lnea del mensaje indica que el problema ocurrio en la
lnea 9 de la aplicaci
on, y el mensaje de error que le antecede muestra que el problema ocurrio dentro
de la llamada a nextInt(). Como el usuario no ingreso un entero, el metodo nextInt() fallo. Por
supuesto que no se quiere modificar el metodo nextInt() que reside en la clase Scanner, se prefiere
volver a ejecutar el programa y meter un entero, o modificar el programa para que estos errores no
puedan ocurrir.

$ java Division
Ingresar el numerador >> 12
Ingresar el denominador >> tres
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:909)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at Division.main(Division.java:9)

$ java Division
Ingresar el numerador >> 12
Ingresar el denominador >> 3.0
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:909)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at Division.main(Division.java:9)

La lista de mensajes de error que se muestran en los intentos de ejecucion mostrados previamente
es llamada una lista del historial de seguimiento de la pila, o un seguimiento de la pila.
La lista muestra cada metodo que fue llamado conforme el programa se ejecutaba.

Solo porque una excepci on ocurra, no es obligatorio manejarla. Se puede dejar el codigo sin mo-
dificacion pero, la terminacion del programa es abrupta. Posiblemente alg un usuario podra estar
molesto si el programa termina abruptamente. Sin embargo, si el programa es usado para tareas
de mision crtica tales como el control del trafico aereo, o para monitorear los signos vitales de un
paciente en una ciruga, una conclusi on abrupta podra ser desastrosa. Las tecnicas de manejo de
error orientadas al objeto dan soluciones elegantes y seguras para errores.

Se pueden escribir programas sin usar tecnicas de manejo de excepciones. Posiblemente la soluci
on
de manejo de errores mas comun ha sido el uso de una decision para evitar un error. Por ejemplo,
se puede cambiar el metodo main() de la clase Division para evitar dividir por cero agregando la

4
decision como se muestra en la aplicacion DivisionIf, codigo 2.

1 import j a v a . u t i l . Scanner ;
2 public c l a s s D i v i s i o n I f {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int numerador , denominador , r e s u l t a d o ;
6 System . out . p r i n t ( I n g r e s a r e l numerador >> ) ;
7 numerador = e n t r a d a . n e x t I n t ( ) ;
8 System . out . p r i n t ( I n g r e s a r e l denominador >> ) ;
9 denominador = e n t r a d a . n e x t I n t ( ) ;
10 i f ( denominador == 0 )
11 System . out . p r i n t l n ( No s e puede d i v i d i r por 0 ) ;
12 else {
13 r e s u l t a d o = numerador / denominador ;
14 System . out . p r i n t l n ( numerador + / + denominador +
15 = + resultado );
16 }
17 }
18 }

C
odigo 2: Aplicacion DivisionIf.

La aplicacion DivisionIf muestra un mensaje al usuario cuando cero es ingresado para el valor
del denominador, pero no se puede recuperar cuando un dato no entero, como una cadena o un
valor punto flotante, es ingresado.

Los programas que pueden manejar excepciones apropiadamente se dice que son mas tolerantes a las
fallas y robustos. Las aplicaciones tolerantes a las fallas son dise
nadas para que puedan continuar
operando, posiblemente a un nivel reducido, cuando alguna parte del sistema falla. La robustez
representa el grado en el cual un sistema es resistente al uso, manteniendo el funcionamiento
correcto.

Es importante entender las tecnicas de manejo de excepciones porque los metodod incorporados en
Java lanzaran excepciones a los programas.

2. Intentar c
odigo y capturar excepciones

En la terminologa orientada al objeto, se intenta (try) un procedimiento que podra causar un


error. Un metodo que detecta una condicion de error lanza (throws) una excepcion, y el c
odigo
de bloque que procesa el error atrapa (catch) la excepcion.

Cuando se crea un segmento de c odigo en el cual algo podra ir mal, se coloca el codigo en un
bloque try, el cual es un bloque de codigo que se intenta ejecutar mientras se reconoce que una
excepcion podra ocurrir. Un bloque try consiste de los siguientes elementos:

La palabra reservada try.


Una llave de apertura.
Sentencia ejecutables, incluyendo algunas que podran causar excepciones.

5
Una llave de cierre.

Para manejar una excepci on lanzada, se pueden codificar uno o mas bloques catch siguiendo
inmediatamente al bloque try. Un bloque catch es un segmento de codigo que puede manejar
una excepcion que podra ser lanzada por el bloque try que le precede. La excepcion podra ser
una que es lanzada autom aticamente, o se podra explcitamente escribir una sentencia throw. Una
sentencia throw es una que manda un objeto Exception fuera de un bloque o un metodo para
que pueda ser manejada donde sea. Una Exception lanzada puede ser capturada por un bloque
catch. Cada bloque catch puede atrapar un tipo de excepcion, es decir, un objeto que es del
tipo Exception o de sus clases hijas. Se crea un bloque catch poniendo los siguientes elementos:

La palabra reservada catch.

Un parentesis de apertura.

Un tipo o subtipo Exception.

Un identificador para una instancia del tipo Exception.

Un parentesis de cierre.

Una llave de apertura.

Las sentencias que toman la acci


on que se quiere usar para manejar la condicion de error.

Una llave de cierre.

Se muestra enseguida el formato general de un metodo que incluye un par try...catch. Un bloque
catch se parece a un metodo llamado catch() que toma un argumento que es alg un tipo de
Exception. Sin embargo, no es un metodo; no tiene tipo que se devuelve, y no se puede llamar
directamente. Algunos programadores se refieren a un bloque catch como una clausula catch.

tipoDevuelto nombreM ametros opcionales) {


etodo(par
// sentencias opcionales previas al codigo que se intentar
a
try {
// sentencias que podran generar una excepci
on
}
on) {
catch (Exception algunaExcepci
// acciones que se haran si la excepci
on ocurre
}
// sentencias opcionales que ocurren despues del try,
// ya sea que el bloque catch se ejecute o no
}

Cuadro 1: Formato try...catch en un metodo.

En el formato, algunaExcepci on representa un objeto de la clase Exception o alguna de sus


subclases. Si una excepci
on ocurre durante la ejecucion del bloque try, las sentencias en el bloque

6
catch se ejecutan. Si no ocurre una excepcion dentro del bloque try, el bloque catch no se ejecuta.
De cualquier forma, las sentencias que siguen el bloque catch se ejecutan normalmente.

La aplicacion DivisionPorCeroAtrapada, codigo 3, mejora la clase Division. El metodo main()


contiene un bloque try con c
odigo que intenta dividir. Cuando una division entera ilegal es inten-
tada, una ArithmeticException es automaticamente creada y el bloque catch es ejecutado.

1 import j a v a . u t i l . Scanner ;
2 public c l a s s D i v i s i o n P o r C e r o A t r a p a d a {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int numerador , denominador , r e s u l t a d o ;
6 System . out . p r i n t ( I n g r e s a r e l numerador >> ) ;
7 numerador = e n t r a d a . n e x t I n t ( ) ;
8 System . out . p r i n t ( I n g r e s a r e l denominador >> ) ;
9 denominador = e n t r a d a . n e x t I n t ( ) ;
10 try {
11 r e s u l t a d o = numerador / denominador ;
12 System . out . p r i n t l n ( numerador + / + denominador +
13 = + resultado );
14 }
15 catch ( A r i t h m e t i c E x c e p t i o n e r r o r ) {
16 System . out . p r i n t l n ( I n t e n t o de d i v i d i r por 0 ) ;
17 }
18 }
19 }

C
odigo 3: Aplicacion DivisionPorCeroAtrapada.

Enseguida se muestra la salida de dos ejecuciones de la aplicacion, una con una excepcion generada
y una sin excepci
on.

$ java DivisionPorCeroAtrapada
Ingresar el numerador >> 20
Ingresar el denominador >> 5
20 / 5 = 4
$ java DivisionPorCeroAtrapada
Ingresar el numerador >> 20
Ingresar el denominador >> 0
Intento de dividir por 0

Nota. En la aplicaci
on DivisionPorCeroCapturada, las operaciones lanzar y atrapar estan en el
mismo metodo. Despues se revisara que los lanzamientos y su correspondiente bloque de captura
frecuentemente estan en metodos separados.

Nota. Si se quiere mandar mensajes de error a una localidad diferente a la salida normal, se puede
usar System.err en vez de System.out. Por ejemplo, si una aplicacion escribe un reporte a un
archivo de disco especfico, se podra querer que los errores se escriben en una localidad diferente,
como en otro disco o a la pantalla.

7
Cualquier ArithmeticException generada dentro del bloque try podra ser atrapada por el bloque
catch en el metodo, para la aplicaci
on DivisionPorCeroAtrapada. Se puede usar el metodo de
instancia getMessage() calificado con la excepcion atrapada, que ArithmeticException hereda
de la clase Throwable, en vez de poner su propio mensaje.

En la aplicaci
on DivisionPorCeroAtrapada2, codigo 4, usa el metodo getMessage(), lnea 16,
para generar el mensaje que viene con el argumento atrapado ArithmeticException para el
bloque catch. Al ejecutar esta aplicacion con un denominador que sea cero, se muestra el mensaje
/ by zero.

1 import j a v a . u t i l . Scanner ;
2 public c l a s s D i v i s i o n P o r C e r o A t r a p a d a {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int numerador , denominador , r e s u l t a d o ;
6 System . out . p r i n t ( I n g r e s a r e l numerador >> ) ;
7 numerador = e n t r a d a . n e x t I n t ( ) ;
8 System . out . p r i n t ( I n g r e s a r e l denominador >> ) ;
9 denominador = e n t r a d a . n e x t I n t ( ) ;
10 try {
11 r e s u l t a d o = numerador / denominador ;
12 System . out . p r i n t l n ( numerador + / + denominador +
13 = + resultado );
14 }
15 catch ( A r i t h m e t i c E x c e p t i o n e r r o r ) {
16 System . out . p r i n t l n ( I n t e n t o de d i v i d i r por 0 ) ;
17 }
18 }
19 }

C
odigo 4: Aplicacion DivisionPorCeroAtrapada2.

El mensaje / by zero ya haba sido visto previamente, y fue cuando el programa, Division, no
tena manejo de excepciones.

Por supuesto que se quiere hacer m as que mostrar un mensaje de error en el bloque catch; despues
de todo, Java lo haca sin requerir escribir codigo para atrapar cualquier excepcion. Se podra querer
agregar codigo para corregir el error; tal codigo podra forzar la aritmetica al dividir por uno en
vez de cero. Enseguida se muestra un codigo try...catch que realiza lo comentado. Despues del
bloque catch, la aplicaci on podra continuar con la garanta que resultado tiene un valor v alido,
a
un si la divisi
on funcion o en el bloque try y el bloque catch no se ejecuto, o el bloque catch
arregla el error.

try {
resultado = numerador / denominador;
}
catch (ArithmeticException error) {
resultado = numerador / 1;
}
// el programa continua aqu
; resultado est
a garantizado
// para tener un valor valido

8
Uso de un bloque try para hacer programa infalibles

Uno de los usos m as comunes del bloque try es para esquivar errores de entrada de datos del
usuario. Como cuando el usuario en la aplicacion Division ingresa un caracter o un numero de
punto flotante en respuesta a la llamada del metodo nextInt() y hace que la aplicacion choque.
Usando un bloque try se puede permitir manejar excepciones potenciales de conversion de datos
causadas por usuarios distraidos. Las llamadas a nextInt() o nextDouble() se ponen en el bloque
try y luego se maneja cualquier error generado.

Despues de cualquier llamada al metodo next(), nextInt(), o nextDouble() se agrega una lla-
mada a nextLine() para leer la tecla Intro remanente en el b ufer de entrada, antes de llamadas
subsecuentes nextLine(). Cuando se intenta convertir a dato numerico en un bloque try y es
seguido por otro intento de conversi
on, se debe tener en cuenta los caracteres remanentes dejados
en el b
ufer de entrada. En la aplicaci
on IngresoEnteros, codigo 5, se aceptan y se muestran un
arreglo de seis enteros.

1 import j a v a . u t i l . Scanner ;
2 public c l a s s I n g r e s o E n t e r o s {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 int [ ] l i s t a N u m e r o s = { 0 , 0 , 0 , 0 , 0 , 0 } ;
5 Scanner e n t r a d a = new Scanner ( System . i n ) ;
6 f o r ( int x = 0 ; x < l i s t a N u m e r o s . l e n g t h ; ++x ) {
7 try {
8 System . out . p r i n t ( I n g r e s a un e n t e r o >> ) ;
9 listaNumeros [ x ] = entrada . nextInt ( ) ;
10 }
11 catch ( E x c e p t i o n e ) {
12 System . out . p r i n t l n ( O c u r r i o una e x c e p c i on ) ;
13 }
14 // e n t r a d a . n e x t L i n e ( ) ;
15 }
16 System . out . p r i n t ( Los n u meros son : ) ;
17 f o r ( int num : l i s t a N u m e r o s )
18 System . out . p r i n t (num + ) ;
19 System . out . p r i n t l n ( ) ;
20 }
21 }

C
odigo 5: Aplicacion IngresoEnteros.

Al ejecutar la aplicaci
on IngresoEnteros y poner un dato valido para el primer n umero, se obtiene
la siguiente salida, la cual s muestra Ocurrio una excepcion, pero al usuario no se le permite
ingresar datos para cualquiera de los n umeros restantes. El problema se puede corregir descomen-
tando la llamada a nextLine(), lnea 14, del codigo anterior. De esta forma el mensaje de excepci
on
es puesto, y se permite al usuario continuar ingresando datos.

$ java IngresoEnteros
Ingresa un entero >> a
Ocurri
o una excepci
on
Ingresa un entero >> Ocurri
o una excepci
on
Ingresa un entero >> Ocurri
o una excepci
on

9
Ingresa un entero >> Ocurri
o una excepci
on
Ingresa un entero >> Ocurri
o una excepci
on
Ingresa un entero >> Ocurri
o una excepci
on
Los n
umeros son: 0 0 0 0 0 0

Actividad 1. Descomentar la lnea 14 de la aplicacion IngresoEnteros, compilar y ejecutar la


apliacion meter un dato no v
alido para observar que indica el error

Declaraci
on e inicializaci
on de variables en bloques try...catch

Se puede incluir cualquier sentencia legal dentro de un bloque try o catch, incluyendo la declaraci
on
de variables. Una variable declarada dentro de un bloque es local a ese bloque, por lo que esta
variable sirve s
olo para un proposito temporal.

Si se quiere usar una variable tanto en un bloque try, como en un catch y despues, entonces se
debe declarar la variable antes de que el bloque try inicie. Si el valor inicial a esta variable se
asignara dentro del bloque try...catch, se debe tener cuidado que la variable reciba un valor
u
til; de otra forma, cuando se use la variable despues del bloque try...catch, el programa no
compilara.

En el programa PruebaVariableNoInicializada, codigo 6, x esta declarada y su valor es asignado


por la entrada del usuario en el bloque try...catch. Como el usuario podra no ingresar un entero,
la conversion podra fallar, y una excepcion podra ser lanzada. En este codigo el bloque catch s
olo
muestra un mensaje y no asigna un valor a x. Cuando el programa intenta mostrar x despues del
bloque catch, un mensaje de error es generado.

Actividad 2. Compilar el c
odigo PruebaVariableNoInicializada para ver el mensaje de error.

1 import j a v a . u t i l . Scanner ;
2 public c l a s s P r u e b a V a r i a b l e N o I n i c i a l i z a d a {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 int x ;
5 Scanner e n t r a d a = new Scanner ( System . i n ) ;
6 try {
7 System . out . p r i n t ( I n g r e s a un e n t e r o )))) ) ;
8 x = entrada . nextInt ( ) ;
9 }
10 catch ( E x c e p t i o n e ) {
11 System . out . p r i n t l n ( O c u r r i o e x c e p c i on ) ;
12 }
13 System . out . p r i n t l n ( x e s + x ) ;
14 }
15 }

C
odigo 6: Aplicacion PruebaVariableNoInicializada.

Se tienen tres opciones para arreglar este error:

Se puede asignar un valor a x antes de que el bloque try inicie. De esta forma, aun si una
excepci
on es lanzada, x tendr
a un valor usable para mostrar en la u
ltima sentencia.

10
Se puede asignar un valor usable a x dentro del bloque catch. De esta forma, si una excepci
on
es lanzada, x tendr
a otra vez un valor usable.

Se puede mover la sentencia de salida al bloque try para que en el caso de que el usuario
ingrese un entero muestre ese valor, y si la conversion falla entonces se deja el bloque try,
para ser ejecutado el bloque catch mostrando el mensaje de error y sin usar x.

Actividad 3. Modificar la aplicacion DivisionPorCeroAtrapada que los enteros sean solicitados


con cuadros de dialogo de entrada y el metodo Integer.ParseInt() para convertir las cadenas
devueltas por los cuadros de dialogo de entrada en enteros. De igual forma modificar el bloque
catch para mostrar el error con un cuadro de dialogo.

3. Lanzar y atrapar excepciones m


ultiples

Se pueden poner tantas sentencias como se requiera dentro de un bloque try, y se pueden atrapar
tantas excepciones como se quiera. Si se intenta mas de una sentencia, solo la primera sentencia
generadora de error lanza una excepci on. Tan pronto la excepcion ocurre, la logica se transfiere al
bloque catch, lo cual deja el resto de las sentencias en el bloque try sin ejecutar.

Cuando un programa contiene varios bloques catch, estos son examinados en secuencia hasta que
un apareamiento es encontrado para el tipo de excepcion que ha ocurrido. Entonces, el bloque
catch apareado se ejecuta, y cada bloque catch restante es omitido.

Considerar la aplicaci
on DivisionPorCeroAtrapada3, codigo 7, donde el metodo main() lanza
dos tipos de objetos Exception: una ArithmeticException y una InputMismatchException. El
bloque try en la aplicaci
on rodea todas las sentencias en la cual las excepciones podran ocurrir.

11
1 import j a v a . u t i l . ;
2 public c l a s s D i v i s i o n P o r C e r o A t r a p a d a 3 {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int numerador , denominador , r e s u l t a d o ;
6 try {
7 System . out . p r i n t ( I n g r e s a r e l numerador >> ) ;
8 numerador = e n t r a d a . n e x t I n t ( ) ;
9 System . out . p r i n t ( I n g r e s a r e l denominador >> ) ;
10 denominador = e n t r a d a . n e x t I n t ( ) ;
11 r e s u l t a d o = numerador / denominador ;
12 System . out . p r i n t l n ( numerador + / + denominador +
13 = + resultado );
14 }
15 catch ( E x c e p t i o n e ) {
16 System . out . p r i n t l n ( e . getMessage ( ) ) ;
17 }
18 catch ( A r i t h m e t i c E x c e p t i o n e r r o r ) {
19 System . out . p r i n t l n ( e r r o r . getMessage ( ) ) ;
20 }
21 catch ( InputMismatchException e r r o r ) {
22 System . out . p r i n t l n ( Tipo de dato i n c o r r e c t o ) ;
23 }
24 }
25 }

C
odigo 7: Aplicacion DivisionPorCeroAtrapada3.

Nota. La aplicaci
on DivisionPorCeroAtrapada3 debe importar la clase java.util.InputMis-
matchException para poder usar un objeto InputMismatchException. El paquete java.util es
tambien ocupado por la clase Scanner, as que es mas facil importar el paquete completo.

Nota. Si se usa el metodo getMessage() con el objeto InputMismatchException, se vera que


el mensaje es null, porque null es el valor del mensaje por defecto para un objeto InputMis-
matchException.

Para la aplicaci
on DivisionPorCeroAtrapada3 el bloque try se ejecuta y varias salidas son posibles:

Si el usuario ingresa dos enteros usables, resultado es calculado, la salida normal es mostrada,
y ningun bloque catch se ejecuta.
Si el usuario ingresa un valor no valido ya sea en la lnea 7, o en la lnea 9, un objeto
InputMismatchException es creado y lanzado. Cuando el programa encuentra el primer
bloque catch el bloque es pasado porque la excepcion generada InputMismatchException
no empata con ArithmeticException. Al encontrar el programa el segundo bloque catch, el
tipo empata, y el mensaje Tipo de dato incorrecto es mostrado.
Si el usuario ingresa cero para el denominador, la sentencia de division lanza una Arithmetic-
Exception, y el bloque try es abandonado. Cuando el programa encuentra el primer bloque
catch, el tipo de excepci on empata, el valor del metodo getMessage() es mostrado, y luego
el segundo bloque catch es pasado.

12
Cuando se ponen varios bloques catch siguiendo un bloque try, se debe tener cuidado de que algu-
nos bloques catch no se hagan inalcanzables. Por ejemplo, si un primer bloque catch atrapan una
ArithmeticException y enseguida otra atrapa una Exception, los errores ArithmeticException
causan que el primer bloque catch se ejecute y otros tipos que deriven de Exception caigan
al bloque catch Exception m as general. Por otra parte, si se invierte la secuencia de los bloques
catch para que atrape primero el bloque catch Exception, a un las ArithmeticException ser an
atrapadas por el primer catch, y de esta forma el bloque catch ArithmeticException sera inal-
canzable ya que la ArithmeticException sera atrapada por el catch Exception, y por lo tanto
la clase no compilar a. Se deben de poner los bloques catch de forma que los mas especializados
esten primero y al final los m
as generales. Es decir, cada excepcion debera caer a traves de tantos
bloques catch como sea necesario hasta llegar con el que lo procesara.

Nota. Otras sentencias que son inalcanzables son aquellas que siguen despues de una sentencia
return en un metodo. Crear bloques catch inalcanzables provoca un error del compilador que
genera un mensaje indicando que la excepcion has already been caught (ya ha sido atrapada).

En ocasiones se quiere ejecutar el mismo codigo no importando cual tipo de excepcion ocurre. En
la aplicacion DivisionPorCeroAtrapada3, codigo 7, cada uno de los dos bloques catch muestran
un mensaje u nico, pero se podra querer que ambos bloques catch muestren el mismo mensaje.
Como ArithmeticException e InputMismatchException son subclases de Exception, se puede
reescribir el c
odigo 7, como se muestra en el codigo 8, usando un bloque catch generico, lneas
1517, que puede atrapar cualquier tipo de objeto Exception.

1 import j a v a . u t i l . ;
2 public c l a s s D i v i s i o n P o r C e r o A t r a p a d a 4 {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int numerador , denominador , r e s u l t a d o ;
6 try {
7 System . out . p r i n t ( I n g r e s a r e l numerador >> ) ;
8 numerador = e n t r a d a . n e x t I n t ( ) ;
9 System . out . p r i n t ( I n g r e s a r e l denominador >> ) ;
10 denominador = e n t r a d a . n e x t I n t ( ) ;
11 r e s u l t a d o = numerador / denominador ;
12 System . out . p r i n t l n ( numerador + / + denominador +
13 = + resultado );
14 }
15 catch ( E x c e p t i o n e r r o r ) {
16 System . out . p r i n t l n ( O p e r a c i on no e x i t o s a ) ;
17 }
18 }
19 }

C
odigo 8: Aplicacion DivisionPorCeroAtrapada4.

El bloque catch generico de la clase DivisionPorCeroAtrapada4 acepta un tipo de argumento


Exception generico lanzado por cualquier sentencia potencialmente causante del error, as el bloque
generico act
ua como un bloque atrapa todo. Cuando un error aritmetico o de entrada ocurre, la
excepcion lanzada es promovida a un error Exception en el bloque catch.

Actividad 4. Ejecutar la aplicaci


on DivisionPorCeroAtrapada4 para ver que no importando el

13
tipo de error que ocurra durante la ejecucion del programa, el mensaje general Operacion no
exitosa es mostrado

Como una caracterstica nueva en Java 7, un bloque catch ya puede ser escrito para atrapar
multiples tipos de excepciones especficas. Por ejemplo, el siguiente bloque catch atrapa dos tipos
de excepciones. Cuando cualquiera es atrapada, su identificador local es e.

catch (ArithmeticException, InputMismatchException e) {


...
}

Un metodo puede lanzar cualquier cantidad de tipos de excepciones, sin embargo varios progra-
madores consideran que es un estilo pobre para un metodo lanzar y atrapar mas de tres o cuatros
tipos. Si lo hace, una de las siguientes condiciones podra ser cierta:

Quizas el metodo est


a intentando realizar muchas tareas diversas y entonces debera ser
dividido en metodos mas peque
nos.

Quizas los tipos de excepci


on lanzados son muy especficos y deberan ser generalizados, como
se hizo en la aplicaci
on DivisionPorCeroAtrapada4, codigo 8.

Actividad 5. Usar la actividad 2 para agregar un bloque catch que atrape un objeto NumberFor-
matException. Si este bloque se ejecuta, mostrar un mensaje de error, asignar a numerador y
denominador el valor por defecto 999, y forzar resultado a uno. Ejecutar la aplicacion para confirmar
que el programa trabaja apropiadamente si se dan dos enteros usables, un cero no usable para el
segundo entero, o datos no enteros como cadenas conteniendo caracteres alfabeticos o de puntuaci on.

4. Bloque finally

Cuando se tienen acciones que se deben hacer al final de una secuencia try...catch, se puede
usar un bloque finally. El c odigo dentro de un bloque finally se ejecuta no importando si
el bloque try precedente identifica una excepcion. Generalmente, el bloque finally se usa para
realizar tareas de limpieza que deben suceder no importando si alguna excepcion ocurrio o no, y
si cualquier excepcion que ocurri
o fue capturada o no. El siguiente formato muestra una secuencia
try....catch que usa un bloque finally.

try {
// sentencias a intentar
}
catch (Exception e) {
// acciones que ocurren si Exception fue lanzada
}
finally {
// acciones que ocurren si el bloque catch fue ejecutado o no
}

14
En una secuencia try...catch que no incluya un bloque finally, ver el formato del cuadro 1, las
sentencias opcionales que ocurren despues del try, al final del metodo, podran nunca ser ejecutadas
por al menos dos razones.

Cualquier bloque try podra lanzar un objeto Exception para el cual no se proporcione un
bloque catch. En el caso de una excepcion no manejada, la ejecucion del programa termina
inmediatamente, la excepcion es mandada al sistema operativo para que la maneje, y el
metodo actual es abandonado.

El bloque try o catch podran contener la sentencia System.exit();, la cual detiene la


ejecuci
on inmediatamente.

Cuando se incluye un bloque finally, se asegura que las sentencias finally se ejecutaran antes
que el metodo sea abandonado, a un si el metodo concluye prematuramente. Los programadores
usan un bloque finally cuando el programa usa archivos de datos que deban cerrarse. El formato
del cuadro representa parte de la l
ogica para un programa que maneja archivos.

try {
// Abrir el archivo
// Leer el archivo
// Colocar los datos del archivo en un arreglo
// Calcular el promedio de los datos
// Mostrar el promedio
}
catch (IOException e) {
// mostrar un mensaje de error
// salir de la aplicacion
}
finally {
// Si el archivo esta abierto entonces cerrarlo.
}

Cuadro 2: Pseudoc
odigo que intenta leer un archivo y manejar una excepcion IOException

El pseudocodigo del cuadro 2 representa una aplicacion que abre un archivo; en Java, si un archivo
no existe cuando se abre, una excepcion entrada/salida, o IOException, es lanzada y el bloque
catch puede manejar el error. Como el pseudocodigo usa un arreglo, una IndexOutOfBoundsEx-
ception no atrapada podra ocurrir a un si se pudo abrir el archivo, esta excepcion ocurre cuando
un subndice no est a en rango de subndices validos. Tambien podra dividirse por cero y una
ArithmeticException no atrapada podra ocurrir. En cualquiera de estos eventos, se podr`a querer
cerrar el archivo antes de proceder. Usando el bloque finally, se asegura que el archivo sera cerrado
porque el codigo en este bloque se ejecuta antes que el control regrese al sistema operativo. El c
odigo
en el bloque finally se ejecuta no importando cual de las siguientes salidas del bloque try ocurra:

El bloque try termina normalmente.

El bloque catch se ejecuta.

15
Una excepcion no capturada causa que el metodo sea abandonado prematuramente. Una
excepci
on no capturada no permite que el bloque try concluya, ni causa que un bloque
catch sea ejecutado.

Si una aplicaci
on pudiera lanzar varios tipos de excepciones, se puede intentar alg un codigo, atrapar
la posible excepci
on, intentar alg
un c
odigo mas y atrapar la excepcion, y as sucesivamente. La mejor
alternativa es intentar todas las sentencias que podran lanzar excepciones, y luego incluir todos
los bloques catch necesarios y un bloque finally opcional. Esta es la alternativa mostrada en el
cuadro 2, y resulta en un logica que es mas facil de entender.

Se puede evitar usar un bloque finally, pero se podra necesitar repetir codigo. Para el pseu-
docodigo del cuadro 2 para evitar usar el bloque finally se podra insertar la sentencia Si el
archivo esta abierto entonces cerrrarlo como la u
ltima sentencia en el bloque try y despues de
mostrar el mensaje de error en el bloque catch. Sin embargo, escribiendo codigo solo una vez en el
bloque finally es m as simple y menos susceptible a error.

Nota. Si un bloque try llama al metodo System.exit() y el bloque finally llama al mismo
metodo, el metodo exit() en el bloque finally se ejecuta. La llamada del metodo exit() del
bloque try es abandonado.

5. Ventajas del manejo de excepci


on

Antes de la llegada de los lenguajes orientados al objeto, los errores potenciales del programa fueron
manejados usando algo enredado, metodos propensos a error. Un programa procedural tradicional
no orientado al objeto podra realizar tres metodos que dependen de otros usando codigo que
proporcione revision similar al pseudocodigo del cuadro 3.
llamar al metodoA()
if metodoA() trabajo {
llamar al metodoB()
if metodoB() trabaj o {
llamar al metodoC()
if metodoC() trabaj o
todo esta bien, as que mostrar resultadoFinal
else
poner c
odigoError a C
}
else
poner c
odigoError a B
}
else
poner c
odigoError a A

Cuadro 3: Pseudoc
odigo representando revision tradicional de error

16
El pseudocodigo del cuadro 2 representa una aplicacion en la cual la logica debera pasar tres
pruebas antes de que resultadoFinal pueda ser mostrado. El programa ejecuta el metodoA();
luego llama al metodoB() s olo si metodoA() es exitoso. De igual forma, el metodoC() se ejecuta
solo cuando ambos metodos metodoA() y metodoB() son ambos exitosos. Cuando falla alguno
de los metodos, el programa pone un codigo A, B, o C apropiado en c odigoError, quiz as
odigoError sea usado m
c as tarde en la aplicacion. La logica es difcil de seguir, y el prop
osito
de la aplicaci
on y la salida usual intentada, mostrar resultadoFinal, se pierde en laberinto de
sentencias if. Tambien, se pueden f
acilmente cometer errores de codificacion dentro del programa
por el anidamiento complicado, sangrado, y apertura y cierre de llaves.

Comparar la misma l ogica del programa usando la tecnica orientada al objeto, manejo de errores
de Java mostrada en el cuadro 4. Usando la tecnica try...catch se logran los mismos resultados
que el metodo tradicional, pero las sentencias del programa que hacen el trabajo verdadero, la
llamada a los metodos A, B, y C y mostrar resultadoFinal, estan puestos juntos, donde su l ogica
es mas facil de seguir. Los pasos try deberan usualmente trabajar sin generar errores; despues de
todo, los errores son excepciones. Es conveniente ver los pasos usuales en un solo lugar, y los
eventos excepcionales est an agrupados y puestos fuera de la accion primaria.

try {
llamar al metodoA()
llamar al metodoB()
llamar al metodoC()
}
catch (error del metodoA()){
poner codigoError a A
}
catch (error del metodoB()){
poner codigoError a B
}
catch (error del metodoC()){
poner codigoError a C
}

Cuadro 4: Pseudoc
odigo representando el manejo de excepciones orientada al objeto

Una ventaja del manejo de excepciones orientada al objeto, ademas de la claridad, es la flexibilidad
que permite en el manejo de situaciones de error. Cuando un metodo escrito lanza una excepci on, el
mismo metodo puede atrapar la excepcion, lo cual no es necesario y en la mayora de los programas
no se hace. Generalmente no se quiere que un metodo maneje su propia excepcion. En muchos
casos, se quiere que el metodo revise los errores, pero no se quiere hacer que un metodo maneje un
error si este lo encuentra. Otra ventaja con el manejo de excepciones es que se tiene la habilidad
para manejar apropiadamente las excepciones conforme se decide como hacerlo. Cuando se escribe
un metodo, este puede llamar otro, atrapar una excepcion lanzada, y se puede decidir que se quiere
hacer. Los programas pueden reaccionar a excepciones especficas para sus propositos actuales.

Los metodos son flexibles en parte porque son reusables. Cada aplicacion llamada podra necesitar
manejar un error lanzado diferentemente, dependiendo de su proposito. Considerar una aplicaci on
que usa un metodo que divide valores podra necesitar terminar si la division por cero ocurre. Un

17
programa diferente podra querer que el usuario reingrese el dato a ser usado, y un tercer programa
podra querer forzar la divisi
on por uno. El metodo que contiene la sentencia de division podra
lanzar el error, pero cada programa que llama puede asumir la responsabilidad para manejar el
error detectado por el metodo en una forma apropiada.

6. Especificar excepciones que un m


etodo puede lanzar

Si un metodo lanza una excepcion que no atrapara pero que sera atrapada por un metodo diferente,
se debe usar la palabra reservada throws seguida por un tipo Exception en la cabecera del metodo.
Esta practica es conocida como especificaci on de excepci on.

En la clase ListaPrecios, c odigo 9, usada por una empresa para tener una lista de precios de
los artculos que venden, hay solamente cuatro precios y un solo metodo que muestra el precio de
un artculo individual. El metodo mostrarPrecio() acepta un parametro que sera usado como el
subndice del arreglo, pero como el subndice podra estar fuera de rango, el metodo contiene una
clausula throws en la lnea 3, reconociendo que podra lanzar una excepcion.

1 public c l a s s L i s t a P r e c i o s {
2 private s t a t i c f i n a l double [ ] p r e c i o = { 3 5 . 5 0 , 6 7 . 8 0 , 1 2 . 5 0 , 3 2 . 2 0 } ;
3 public s t a t i c void m o s t r a r P r e c i o ( int a r t i c u l o ) throws IndexOutOfBoundsException {
4 System . out . p r i n t l n ( El p r e c i o e s $ + p r e c i o [ a r t i c u l o ] ) ;
5 }
6 }

C
odigo 9: La clase ListaPrecios.

La aplicacion AplicacionListaPrecios1, codigo 10, se ha escogido manejar la excepcion en el


bloque catch, lneas 1113, para mostrar un precio de cero.

1 import j a v a . u t i l . Scanner ;
2 public c l a s s A p l i c a c i o n L i s t a P r e c i o s 1 {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int a r t i c u l o ;
6 System . out . p r i n t ( I n g r e s a r e l n u mero d e l a r tc u l o >> ) ;
7 a r t i c u l o = entrada . nextInt ( ) ;
8 try {
9 ListaPrecios . mostrarPrecio ( a r t i c u l o ) ;
10 }
11 catch ( IndexOutOfBoundsException e r r o r ) {
12 System . out . p r i n t l n ( El p r e c i o e s $0 ) ;
13 }
14 }
15 }

C
odigo 10: Clase AplicacionListaPrecios1.

En la aplicacion AplicacionListaPrecios2, codigo 11, el programador ha escogido manejar la


excepci`on en el bloque catch, lneas 1214, mostrando el precio del u
ltimo artculo del arreglo.

18
1 import j a v a . u t i l . ;
2 public c l a s s A p l i c a c i o n L i s t a P r e c i o s 2 {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int a r t i c u l o ;
6 f i n a l int ARTMAX = 3 ;
7 System . out . p r i n t ( I n g r e s a r e l n u mero d e l a r tc u l o >> ) ;
8 a r t i c u l o = entrada . nextInt ( ) ;
9 try {
10 ListaPrecios . mostrarPrecio ( a r t i c u l o ) ;
11 }
12 catch ( IndexOutOfBoundsException e r r o r ) {
13 L i s t a P r e c i o s . m o s t r a r P r e c i o (ARTMAX) ;
14 }
15 }
16 }

C
odigo 11: Clase AplicacionListaPrecios2.

Otros programadores escribiendo otras aplicaciones que usen la clase ListaPrecios podran escoger
todava acciones diferentes, pero pueden usar el metodo flexible mostrarPrecio() porque este no
limita la llamada de los metodos de recurso escogidos.

Para la mayora de los metodos Java que se escriben no se usa la clausula throws. La mayora
del tiempo se le permite a Java manejar cualquier excepcion abortando el programa, ya que de
otra forma se requerira dar instrucciones para manejar cada error posible. Muchas excepciones
nunca tendran que ser explcitamente lanzadas o atrapadas, ni se tendran que incluir una clausula
throws en la cabecera de los metodos que automaticamente lanzan estas excepciones. Las u nicas
excepciones que deberan ser atrapadas o nombradas en una clausula throws son del tipo conocido
como excepciones comprobadas.

Las excepciones de Java pueden ser categorizadas en dos tipos:

Excepciones no comprobadas. Estas heredan de la clase Error o RuntimeException. Se


pueden manejar estas excepciones en los programas, pero no se esta obligado a hacerlo. Por
ejemplo, dividir por cero es un tipo de RuntimeException, y no se esta obligado a manejar
esta excepci
on, se puede dejar que el programa termine.
Excepciones comprobadas. Estas excepciones son del tipo donde los programadores podran
anticipar y de las cuales los programas deberan poderse recuperar. Todas las excepciones que
explcitamente se lanzen y que desciendan de la clase Exception son excepciones comproba-
das.

Los programadores dicen que las excepciones comprobadas estan sujetas al catch o especificamiento
de requerimientos, lo cual significa que si se lanza una excepcion comprobada desde un metodo, se
debe hacer uno de los siguientes:

Atrapar y manejar la excepci


on posible.
Declarar la excepci
on en su cl
ausula throws. El metodo llamado puede entonces relanzar la
excepci
on a otro metodo que podra atraparla o lanzarla otra vez.

19
Es decir, cuando una excepcion es una comprobada, los programas clientes son forzados a negociar
con la posibilidad que una excepcion sera lanzada.

Si se escribe un metodo que explcitamente lanza una excepcion comprobada que no es capturada
dentro del metodo, Java requiere que se use la clausula throws en la cabecera del metodo. Usando
la clausula throws no significa que el metodo lanzara una excepcion, todo podra ir bien. En vez
de esto significa que el metodo podra lanzar una excepcion. Se incluye la clausula throws en la
cabecera del metodo para que las aplicaciones que usen los metodos esten notificados del potencial
de una excepci on.

Nota. La firma del metodo es la combinacion del nombre del metodo y la cantidad, tipo y orden de
los argumentos. La clausula throws no es parte de la firma porque no se puede crear una clase que
contenga metodos m ultiples que s
olo difieran en sus clausulas throws; el compilador considera que
los metodos tienen firma identica. Se podra decir que la clausula throws es parte de la interfaz del
metodo.

Nota. Un metodo que anule otro no puede lanzar una excepcion a menos que esta lance el mismo tipo
como su padre o una subclase del tipo lanzado de su padre. Estas reglas no aplican a metodos so-
brecargados. Cualquier excepci
on podra o no ser lanzada de una version de un metodo sobrecargado
sin considerar que excepciones son lanzadas por otras versiones de un metodo sobrecargado.

Para poder usar un metodo a su potencial completo, se debe conocer el nombre del metodo y tres
piezas adicionales de informaci
on:

El tipo regresado por el metodo.


El tipo y n
umero de argumentos que el metodo requiere.
El tipo y cantidad de excepciones que el metodo lanza.

Para usar un metodo, se debe saber que tipos de argumentos son requeridos. Se puede llamar
un metodo sin saber su tipo devuelto, pero no se puede beneficiar de alg un valor que el metodo
devuelva, adem as no se entendera el proposito del metodo. De igual forma no se pueden hacer
decisiones coherentes acerca de que hacer en caso de un error si no se sabe que tipos de excepciones
un metodo podra lanzar.

Cuando un metodo podra lanzar m as de una tipo de excepcion, se puede indicar una lista de las
excepciones potenciales en la cabecera del metodo separandolas con comas. Como una alternativa,
si todas las excepciones descienden del mismo padre, se puede especificar la clase padre mas general.
Si el metodo podra lanzar una ArithmeticException o una ArrayIndexOutOfBoundsException,
se puede solo especificar que el metodo lanza una RuntimeException. Una ventaja de esta tecnica
es cuando el metodo es modificado para incluir RuntimeException mas especfico en el futuro, la
cabecera del metodo no cambiar a. Esto ahorra tiempo para los usuarios de los metodos, quienes no
tendran que modificar sus propios metodos para considerar nuevos tipos RuntimeException.

Una alternativa extrema es especificar que el metodo lance un objeto Exception general, as todas
las excepciones estan incluidas en una clausula. Con esto se simplifica la especificacion de la ex-
cepcion, pero se disfraza la informaci
on acerca de los tipos especficos de excepciones que podran
ocurrir, y esta informacion tiene valor para los usuarios de los metodos.

20
Nota. Se declaran solo excepciones comprobadas. Las excepciones tiempos de ejecucion pueden
ocurrir en cualquier parte del programa, y pueden ser numerosas. Los programas podran ser menos
limpios y mas inc
omodos si se tiene que tener en cuenta las excepciones tiempos de ejecucion en
cada declaracion del metodo. Por lo tanto, el compilador de Java no requiere que se atrape o se
especifiquen excepciones tiempos de ejecucion.

7. Traza de excepciones en la pila de llamadas

Cuando un metodo llama a otro, el sistema operativo de la computadora debera seguir la pista de
donde provino la llamada del metodo, y el control del programa debe regresar al metodo llamador
cuando el metodo llamado este completo. Si el m
etodoA() llama al m
etodoB(), el sistema operativo
tiene que recordar regresar al metodoA() cuando el m etodoB() termine. De igual forma si el
etodoB() llama al m
m etodoC(). La localidad de memoria conocida como la pila de llamadas es
donde la computadora guarda la lista de la ubicacion del metodo al cual el sistema deba regresar.

Cuando un metodo lanza una excepci on y el metodo no la atrapa, la excepcion es lanzada al siguiente
metodo de la pila de llamadas, o al metodo que llamo al metodo ofendido. Si el m etodoA() llama
al m
etodoB(), y el metodoB() llama al metodo m etodoC(), y el m etodoC() lanza una excepci on,
Java primero busca por un bloque catch en el m etodoC(). Si ninguno existe, Java busca por la
misma cosa en el metodoB(). Si el m
etodoB() no tiene un bloque catch, Java busca en m etodoA().
Si el m
etodoA() no puede atrapar la excepcion, esta es lanzada a la Maquina Virtual Java, la cual
muestra un mensaje en la pantalla.

La aplicacion DemoTrazaPila, codigo 12, en el metodo main() llama al m


etodoA(), el cual muestra
un mensaje y llama al m
etodoB(). Dentro del m etodoB(), otro mensaje es mostrado y el m
etodoC()
es llamado. En el metodoC(), otro mensaje es mostrado. Luego un arreglo de tres enteros es de-
clarado, y el programa intenta mostrar el cuarto elemento del arreglo. El programa compila co-
rrectamente, pero un error es detectado cuando el m etodoC() intenta acceder el elemento fuera del
rango.

21
1 public c l a s s DemoTrazaPila {
2 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
3 metodoA ( ) ;
4 }
5 public s t a t i c void metodoA ( ) {
6 System . out . p r i n t l n ( En e l metodoA ( ) ) ;
7 metodoB ( ) ;
8 }
9 public s t a t i c void metodoB ( ) {
10 System . out . p r i n t l n ( En e l me todoB ( ) ) ;
11 metodoC ( ) ;
12 }
13 public s t a t i c void metodoC ( ) {
14 System . out . p r i n t l n ( En e l metodoC ( ) ) ;
15 int [ ] a r r e g l o = { 0 , 1 , 2 } ;
16 System . out . p r i n t l n ( a r r e g l o [ 3 ] ) ;
17 }
18 }

C
odigo 12: Clase DemoTrazaPila.

Enseguida se muestra la salida cuando se ejecuta DemoTrazaPila que tiene tres mensajes, indi-
cando el orden en el que fueron llamados los metodos m etodoA(), m etodoB() y m etodoC(). Sin
embargo, cuando el m etodoC() intenta acceder el elemento fuera de rango en el arreglo, una excep-
cion ArrayIndexOutOfBoundsException es automaticamente lanzada. El mensaje de error genera
muestra que la excepci on ocurrio en la lnea 16 del archivo en el m
etodoC(), el cual fue llamado en
la lnea 11 del archivo por el m
etodoB(), el cual fue llamado en la lnea 7 por el metodoA(), el cual
fue llamado por el metodo main() en la lnea 3 del archivo. Usando la lista de mensajes de error,
se podra rastrear el lugar donde el error fue generado. Por supuesto, en una aplicacion mas granda
que contenga miles de lneas de c odigo, la lista del historial de seguimiento de la pila podra ser
mas u til.

En el m
etodoA()
En el m
etodoB()
En el m
etodoC()
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at DemoTrazaPila.m
etodoC(DemoTrazaPila.java:16)
at DemoTrazaPila.m
etodoB(DemoTrazaPila.java:11)
at DemoTrazaPila.m
etodoA(DemoTrazaPila.java:7)
at DemoTrazaPila.main(DemoTrazaPila.java:3)

Cuando un programa usa varias clases, la desventaja es que el programador encuentra difcil en-
contrar la fuente original de una excepcion.

El metodo getMessage() de Throwable se usa para obtener informacion de un objeto Exception.


Otro metodo util de Exception es el metodo printStackTrace(). Cuando se atrapa un objeto
Exception, se puede llamar printStackTrace() para mostrar una lista de metodos en la pila de
llamadas y determinar el lugar de la sentencia que causo la excepcion.

La aplicacion DemoTrazaPila2, c
odigo 13, en la cual el metodo printStackTrace() produce un
seguimiento del camino tomado por el lanzamiento de una excepcion. La llamada al metodoB()

22
ha sido puesta en un bloque try para que la excepcion pueda ser capturada. En vez de lanzar la
excepcion al sistema operativo, la aplicacion atrapa la excepcion, muestra la lista del historial de
seguimiento de la pila, y contin
ua la ejecucion.

1 public c l a s s DemoTrazaPila2 {
2 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
3 metodoA ( ) ;
4 }
5 public s t a t i c void metodoA ( ) {
6 System . out . p r i n t l n ( En e l metodoA ( ) ) ;
7 try {
8 metodoB ( ) ;
9 }
10 catch ( ArrayIndexOutOfBoundsException e r r o r ) {
11 System . out . p r i n t l n ( En metodoA ( ) S e g u i m i e n t o de l a p i l a : ) ;
12 error . printStackTrace ( ) ;
13 }
14 System . out . p r i n t l n ( metodoA ( ) t e r m i n a normalmente . ) ;
15 System . out . p r i n t l n ( La a p l i c a c i on podra c o n t i n u a r d e s d e e s t e punto . ) ;
16 }
17 public s t a t i c void metodoB ( ) {
18 System . out . p r i n t l n ( En e l me todoB ( ) ) ;
19 metodoC ( ) ;
20 }
21 public s t a t i c void metodoC ( ) {
22 System . out . p r i n t l n ( En e l metodoC ( ) ) ;
23 int [ ] a r r e g l o = { 0 , 1 , 2 } ;
24 System . out . p r i n t l n ( a r r e g l o [ 3 ] ) ;
25 metodoB ( ) ;
26 }
27 }

C
odigo 13: Clase DemoTrazaPila2.

Actividad 6. Ejecutar la aplicaci


on DemoTrazaPila2 para revisar que la aplicacion no termina
abruptamente.

Generalmente no se quiere poner una llamada al metodo printStackTrace() en un programa


terminado. El usuario tpico de la aplicacion no tiene interes en los mensajes crtpico que son
mostrados. Sin embargo, mientras se esta desarrollando una aplicacion, printStackTrace() puede
ser una herramienta u
til para diagnosticar los problemas de la clase.

8. Creaci
on de clases Exception propias

Java proporciona m as de 40 categoras de Exception que se pueden usar en los programas. Pero
hay situaciones que no fueron consideradas en Java, por ejemplo, se podra querer declarar una
Exception cuando el saldo bancario es negativo o cuando un participante externo intenta acce-
der su cuenta de correo electr
onico. Diversas organizaciones tienen reglas especficas para datos
excepcionales; por ejemplo, un numero de empleado no debera exceder tres dgitos, o un salario
por hora no debera ser menor que el salario mnimo legal. Por supuesto, se pueden manejar estas

23
situaciones potenciales de error con sentencias if, pero Java tambien permite crear sus propias
clases Exception.

Para crear su propia clase Exception lanzable, se debe extender una subclase de Throwable.
Throwable tiene dos subclases, Exception y Error, las cuales son usadas para distinguir entre
errores recuperables e irrecuperables. Como siempre se quiera que las excepciones propias se pue-
dan recuperar entonces las clases se deberan extender de la clase Exception. Se puede extender
cualquier subclase Exception existente, como ArithmeticException o NullPointerException,
pero generalmente se quiere heredar directamente de Exception. Cuando se crea una subclase
Exception, es una convenci on terminar el nombre con Exception.

La clase Exception contiene cuatro constructores que son:

Exception(). Construye un nuevo objeto Exception con null como su mensaje detallado.

Exception(String mensaje). Construye un nuevo objeto Exception con el mensaje deta-


llado especificado.

Exception(String mensaje, Throwable causa). Construye un nuevo objeto Exception


con el mensaje detallado especificado y causa.

Exception(Throwable causa). Construye un nuevo objeto Exception con la causa especi-


ficada y un mensaje detallado de causa.toString(), la cual tpicamente contiene la clase y
mensaje detallado de causa, o null si el argumento de la causa es null.

La clase SaldoAltoException, c odigo 14, tiene un constructor que contiene una sola sentencia
que pasa una descripcion de un error al constructor padre Exception. Este String podra ser
recuperada si se llama al metodo getMessage() con un objeto SaldoAltoException.

1 public c l a s s S a l d o A l t o E x c e p t i o n extends E x c e p t i o n {
2 public S a l d o A l t o E x c e p t i o n ( ) {
3 super ( El s a l d o d e l c l i e n t e e s t a a l t o ) ;
4 }
5 }

C
odigo 14: Clase SaldoAltoException.

En la clase CuentaCliente, codigo 15, se usa SaldoAltoException. La cabecera del constructor


CuentaCliente indica que podra lanzar una instancia SaldoAltoException sin nombre, en el caso
de que el saldo usado como argumento para el constructor exceda un lmite.

24
1 public c l a s s C u e n t a C l i e n t e {
2 private int numCuenta ;
3 private double s a l d o ;
4 public s t a t i c double LIM CRED SUP = 2 0 0 0 0 . 0 0 ;
5 public C u e n t a C l i e n t e ( int num , double s a l ) throws S a l d o A l t o E x c e p t i o n {
6 numCuenta = num ;
7 saldo = sal ;
8 i f ( s a l d o > LIM CRED SUP )
9 throw new S a l d o A l t o E x c e p t i o n ( ) ;
10 }
11 }

C
odigo 15: Clase CuentaCliente.

Nota. En la clase CuentaCliente se podra escoger instanciar un SaldoAltoException con nombre


y lanzarlo cuando el balance exceda el lmite de credito. Se mejora el rendimiento del programa
esperando e instanciando un objeto anonimo solo cuando sea necesario.

En la aplicaci
on UsaCuentaCliente, 16, se le pide al usuario un n umero de cuenta y un saldo.
Despues de que los valores son dados, se intenta construir un objeto CuentaCliente en un bloque
try, como se ve en la lnea 12. Si el intento es exitoso, es decir, el constructor CuentaCliente no
lanza una Exception, entonces la informacion del objeto es mostrada en cuadro de dialogo. Pero si el
constructor lanza una SaldoAltoException, el bloque catch, lneas 1620, lo recibe y muestra un
mensaje. Una aplicacion diferente podra mostrar el valor regresado por el metodo getMessage(),
construir un objeto CuentaCliente con un saldo menor, o construir un tipo diferente de objeto el
permita una saldo mayor.

1 import j a v a x . swing . ;
2 public c l a s s UsaCuentaCliente {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 int num ;
5 double s a l d o ;
6 String entrada ;
7 e n t r a d a = JOptionPane . sh ow In put Di al og ( null , I n g r e s a r n u mero de c u e n t a ) ;
8 num = I n t e g e r . p a r s e I n t ( e n t r a d a ) ;
9 e n t r a d a = JOptionPane . sh ow In put Di al og ( null , I n g r e s a r e l s a l d o que s e debe ) ;
10 s a l d o = Double . p a r s e D o u b l e ( e n t r a d a ) ;
11 try {
12 C u e n t a C l i e n t e c c = new C u e n t a C l i e n t e (num , s a l d o ) ;
13 JOptionPane . showMessageDialog ( null , C l i e n t e # +
14 num + t i e n e un s a l d o de $ + s a l d o ) ;
15 }
16 catch ( S a l d o A l t o E x c e p t i o n e s a ) {
17 JOptionPane . showMessageDialog ( null , C l i e n t e # +
18 num + t i e n e un s a l d o de $ + s a l d o +
19 e l c u a l e s mayor que e l lmite d e l c re d i t o ) ;
20 }
21 }
22 }

C
odigo 16: Aplicacion UsaCuentaCliente.

25
En vez de codificar los mensajes de error en las clases de excepcion, como se muestra en el c
odigo
16, se podra considerar crear un cat
alogo de mensajes posibles para usar. Esta forma da varias
ventajas:

Todos los mensajes son guardados en una localidad en vez de estar dispersos por todo el
programa, haciendo mas f
acil verlos y modificarlos.

La lista de errores posibles sirve como una fuente de documentacion, listando problemas
potenciales cuando se ejecute la aplicacion.

Otras aplicaciones podran querer usar el mismo catalogo de mensajes.

Si la aplicaci
on ser
a usada mundialmente, se puede proporcionar mensajes en m ultiples len-
guajes, y otros programadores pueden usar la version que es apropiada para su pas.

Nota. Se puede lanzar cualquier tipo de excepcion en cualquier momento, no solo las excepciones
de su propia creaci
on. Por ejemplo, dentro de cualquier programa se puede codificar throw(new
RuntimeException());. Se podra querer hacerlo solo con una buena razon porque Java maneja
RuntimeException por usted parando el programa. Como no se puede anticipar cada error posible,
la respuesta automatica de Java es frecuentemente el mejor curso de la accion.

No se debera crear una cantidad excesiva de tipos de excepcion especiales para sus clases, porque
el ambiente de desarrollo de Java ya contiene un clase Exception que atrapara el error. Los tipos
Exception adicionales agregan complejidad para otros programadores que usaran sus clases. Sin
embargo, cuando clases Exception apropiadas y especializadas proporcionan una forma elegante
para manejar las situcaciones de error, permiten separar el codigo de manejo de error de la secuencia
de eventos no excepcionales y usuales. Permiten a los clientes de sus clases manejar situaciones
excepcionales de la forma mas adecuada para su aplicacion.

9. Uso de afirmaciones

Algunos errores de logica no causan que un programa termine pero producen resultados incorrectos.
Por ejemplo, si un programa de pago debe determinar el pago multiplicando horas trabajados por
el pago por hora, pero si inadvertidamente se dividieron los n umeros, no ocurre un error en tiempo
de ejecucion y no se lanza excepci
on, pero la salida es incorrecta. Una afirmaci
on es una capacidad
del lenguaje Java que puede ayudar a detectar tales errores de logica para depurar el programa.
Se usa la sentencia assert para crear una afirmacion; cuando se usa una sentencia assert, se
establece una condici on que debera ser true, y Java lanza una assertionError cuando no.

La sintaxis de la sentencia assert es:

assert expresi
onBooleana : mensajeErrorOpcional

La expresion booleana en la sentencia assert debera ser siempre true si el programa esta traba-
jando correctamente. El mensajeErrorOpcional es mostrado si la expresi onBooleana es false.

26
La aplicacion ParImpar, c odigo 17, pide a un usuario un n umero y lo pasa a un metodo que
determina si un valor es par. Dentro del metodo esPar(), el residuo es tomado cuando el parametro
pasado es dividido por 2. Si el residuo despues de dividir por 2 es 1, resultado es puesto a false.
Por ejemplo, 1, 3, y 5 todos son impares, ya que todos los resultados dan un valor de 1 cuando %
2 es aplicado a estos. Si el residuo despues de dividir por 2 no es 1, resultado es puesto a true.
Por ejemplo, 2, 4, y 6 todos son pares, todos tienen un 0 de residuo cuando % 2 es aplicado a ellos.

1 import j a v a . u t i l . Scanner ;
2 public c l a s s ParImpar {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 Scanner e n t r a d a = new Scanner ( System . i n ) ;
5 int numero ;
6 System . out . p r i n t ( I n g r e s a r un n
u mero >> ) ;
7 numero = e n t r a d a . n e x t I n t ( ) ;
8 i f ( esPar ( numero ) )
9 System . out . p r i n t l n ( numero + e s par ) ;
10 else
11 System . out . p r i n t l n ( numero + e s impar ) ;
12 }
13 public s t a t i c boolean esPar ( int numero ) {
14 boolean r e s u l t a d o ;
15 i f ( numero % 2 == 1 )
16 resultado = false ;
17 else
18 r e s u l t a d o = true ;
19 return r e s u l t a d o ;
20 }
21 }

Codigo 17: ParImpar.

La siguiente salida se muestra correcta excepto en las dos u


ltimas ejecuciones. Los valores -5 y -7
son clasificados como pares sin embargo son impares. Una afirmacion podra ayudar a depurar la
aplicacion.

$ java ParImpar
Ingresar un n
umero >> 4
4 es par
$ java ParImpar
Ingresar un n
umero >> 5
5 es impar
$ java ParImpar
Ingresar un n
umero >> -4
-4 es par
$ java ParImpar
Ingresar un n
umero >> -5
-5 es par
$ java ParImpar
Ingresar un n
umero >> -7
-7 es par

27
En el codigo 18 se tiene una nueva version del metodo es esPar() al cual se le ha agregado la
sentencia assert en la lnea 7 (adem
as las llaves). La sentencia afirma que cuando el residuo de
un numero dividido por 2 no es 1, debera ser 0. Si la expresion no es true, un mensaje es creado
usando los valores de numero y su residuo despues de dividir por 2.

1 public s t a t i c boolean esPar ( int numero ) {


2 boolean r e s u l t a d o ;
3 i f ( numero % 2 == 1 )
4 resultado = false ;
5 else {
6 r e s u l t a d o = true ;
7 a s s e r t numero % 2 == 0 : numero + % 2 e s + numero % 2 ;
8 }
9 return r e s u l t a d o ;
10 }

C
odigo 18: El metodo defectuoso esPar con una afirmacion.

Si se agrega la afirmaci
on entonces al momento de ejecutar el programa se debe usar la opcion -ea
enable assertion para que sea lanzada la excepcion cuando la afirmacion no sea verdadera.

Al ejecutar el programa ParImpar y con el valor -5, el programa muestra el mensaje de que una
AssertionError fue lanzada y que el valor de -5 % 2 es -1, no 1 como se haba asumido. El operador
residuo da un valor negativo cuando el primer operando es negativo.

Los ajustes que podran realizarse al codigo para que muestre la informacion correctamente son
alguno de los siguientes:

1. Calcular el valor absoluto del par


ametro numero del metodo esPar() antes de usar el operador
residuo:

numero = Math.abs(numero);

2. Cambiar la sentencia de selecci


on para probar por valores pares primero revisando si numero %
0 es cero.

if (numero % 2 == 1)
resultado = true;
else
resultado = false;

3. Otras opciones son: mostrar un mensaje de error cuando valores negativos sean encontrados,
invertir los valores del resultado cuando el parametro sea negativo, o lanzar una excepci
on.

Un programador experimentado podra encontrar el error sin usar una afirmacion. Quizas por que
saba que al aplicarlo con un valor negativo el resultado es negativo. O metiendo sentencias para
mostrar valores en puntos estrategicos en el programa, pero despues de que el error es encontrado,
las sentencias extras puestas deben ser quitadas. En cambio, cualquier sentencia assert puede ser
dejada, y si no se usa la opci
on -ea al ejecutar el programa, el usuario no vera evidencia del uso

28
de sentencias assert. Colocando sentencias assert en lugares clave del programa puede reducir el
tiempo de desarrollo y depuraci
on.

No se quieren usar afirmaciones para revisar cada tipo de error que podra ocurrir en un programa.
Si se quiere asegurar que un usuario ingrese datos numericos, se debera usar las tecnicas de manejo
de excepciones que dan los medios para que el programa se recupere de ese error. Si se quiere
asegurar que los datos caen dentro de un cierto rango, se debera usar una decision o un ciclo. Las
afirmaciones son de ayuda en la etapa de desarrollo de un programa, no cuando esta en producci on
y en las manos de los usuarios.

29

Вам также может понравиться