apuntes:excepciones
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | Next revisionBoth sides next revision | ||
apuntes:excepciones [2019/02/16 11:31] – Santiago Faci | apuntes:excepciones [2021/03/10 13:14] – Santiago Faci | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Gestión de las excepciones ====== | ====== Gestión de las excepciones ====== | ||
- | ===== Las excepciones ===== | + | \part*{Excepciones y aserciones} |
- | Las excepciones son errores que se producen en tiempo de ejecución y que no pueden ser controladas ni anticipadas en tiempo de compilación. Fallos como que el disco duro esté lleno, que no se pueda acceder a una carpeta determinada, | + | \section{Excepciones} |
- | controladas para que el fallo que puedan ocasionar se contenga y no permita que el programa falle. | + | |
- | Para controlar las excepciones | + | Las excepciones en Java son errores |
- | le podemos sugerir diferentes causas del error (quizás se haya quedado sin conexión o tenga que comprobar | + | serie de errores que deben ser corregidos para que el programa pueda compilarse |
+ | puedne producirse una serie de errores, los cuales son imposibles de detectar durante | ||
+ | que, en Java, acaban lanzando una excepción | ||
- | ===== Recuperación | + | \begin{itemize} |
+ | \item Estamos escribiendo en disco y éste se llena (\verb IOException ) | ||
+ | \item Estamos descargando un fichero y cae la conexión a Internet (\verb ConnectionException ) | ||
+ | \item Estamos recorriendo un array en un bucle y accedemos a una posición que no existe (\verb IndexOutOfBoundException ) | ||
+ | \item Accedemos atributos o métodos | ||
+ | \item Realizamos una operación matemática no válida (división por cero) (\verb ArithmeticException ) | ||
+ | \item . . . | ||
+ | \end{itemize} | ||
- | < | + | En Java se propone el control de excepciones para evitar que se produzcan estos errores en lugar de tener que escribir continuamente |
+ | estructuras \verb if que controlen que no ocurre nada anómalo que impida la ejecución de un cierto código. Así, lo que haremos será colocar | ||
+ | dentro un bloque controlado todo el código (y el que dependa de éste) que sea susceptible de producir una excepción, sin interrumpir el | ||
+ | flujo de nuestro programa (al contrario de lo que ocurre añadiendo sentencias \verb if ). | ||
+ | |||
+ | Se recomienda excepciones como \verb NullPointerException | ||
+ | general, corresponderán a errores de codificación, | ||
+ | esperando capturarlas cuando se produzcan. Son dos excepciones que derivan de \verb RuntimeException . Son lo que se conoce como | ||
+ | \emph{unchecked exceptions}. Echa un vistazo a | ||
+ | | ||
+ | |||
+ | \subsection{Bloque try-catch} | ||
+ | |||
+ | El bloque \verb try-catch | ||
+ | para corregir o notificar el problema (parte \verb catch ). | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
. . . | . . . | ||
try { | try { | ||
- | | + | |
- | } catch (< | + | } catch (Exception e1) { |
- | instrucciones_en_caso_de_que_se_produzca_la_excepcion; | + | } catch (Exception e2) { |
- | } [ finally | + | } . . . |
- | instrucciones_en_cualquier_caso; | + | |
- | } ] | + | |
. . . | . . . | ||
- | </ | + | \end{lstlisting} |
- | < | + | En este caso, el código que hay asociado al bloque \verb try se ejecutará de forma que, si dentro de él se produjera una excepción, el |
+ | flujo de ejecución pasaría al bloque \verb catch de la excepción que corresponda. A continuación, | ||
+ | el grupo \verb try-catch . | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
. . . | . . . | ||
+ | File fichero = null; | ||
+ | FileReader lectorFichero = null; | ||
+ | BufferedReader buffer = null; | ||
try { | try { | ||
- | | + | |
- | | + | |
- | | + | |
- | } catch (NumberFormatException nfe) { | + | System.out.println(linea); |
- | | + | } |
- | | + | buffer.close(); |
- | System.out.println(" | + | } catch (FileNotFoundException fnfe) { |
+ | | ||
+ | | ||
+ | } catch (IOException ioe) { | ||
+ | System.out.println(" | ||
+ | ioe.printStackTrace(); | ||
} | } | ||
. . . | . . . | ||
- | </ | + | \end{lstlisting} |
- | ===== Creación y activación de Excepciones ===== | + | \subsection{Instrucción throws} |
- | También podemos | + | También podemos, |
+ | estoy desarrollando una clase que debe controlar una determinada excepción, quizás me pueda resultar interesante hacerla " | ||
+ | para que sea controlada, por ejemplo, | ||
+ | podamos ajustar mejor el comportamiento en caso de error. | ||
- | Para eso, primero tendremos | + | \begin{lstlisting}[language=java] |
+ | public class Util { | ||
+ | public static Date parseFecha(String fecha) throws ParseException { | ||
+ | SimpleDateFormat sdf = new SimpleDateFormat(" | ||
+ | return sdf.parse(fecha); | ||
+ | } | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | El ejemplo de arriba es un caso en el que tenemos un método estático que utilizamos para parsear fechas en nuestra aplicación. Cuando el | ||
+ | texto que se le pase no se corresponda con un formato válido de fecha, lanzará una excepción. Pero justamente en el método no tenemos muy | ||
+ | claro que hacer puesto que dicho método lo utilizarán desde diferentes localizaciones del código en la aplicación. Por eso es mejor que | ||
+ | lancemos fuera la excepción para que sea quién utilice este método quién deba decidir qué hacer en caso de fallo. Por ejemplo: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Ventana { | ||
+ | . . . | ||
+ | private JTextField tfFecha; | ||
+ | . . . | ||
+ | private void comprobarInput() { | ||
+ | . . . | ||
+ | |||
+ | try { | ||
+ | . . . | ||
+ | Date fecha = Util.parseFecha(tfFecha.getText()); | ||
+ | . . . | ||
+ | } catch (ParseException pe) { | ||
+ | JOptionPane.showMessageDialog(. . .); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \subsection{Bloque try-catch-finally} | ||
+ | |||
+ | Se puede añadir también un tercer bloque de código asociado a la parte \verb try que permite añadir código que se ejecutará siempre, de | ||
+ | forma que incluso lo hará cuando se produzca una excepción no controlada. Normalmente se utiliza para la zona donde liberar recursos que | ||
+ | hayan sido ocupados durante el bloque \verb try . De esta forma nos aseguramos que siempre se liberen correctamente, | ||
+ | de ejecución del código se vea interrumpido por una excepción. | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | . . . | ||
+ | BufferedReader buffer = null; | ||
+ | try { | ||
+ | buffer = new BufferedReader(new FileReader(new File(" | ||
+ | String linea = null; | ||
+ | while ((linea = buffer.readLine()) != null) { | ||
+ | System.out.println(linea); | ||
+ | } | ||
+ | } catch (FileNotFoundException fnfe) { | ||
+ | System.out.println(" | ||
+ | fnfe.printStackTrace(); | ||
+ | } catch (IOException ioe) { | ||
+ | System.out.println(" | ||
+ | ioe.printStackTrace(); | ||
+ | } finally { | ||
+ | if (buffer != null) { | ||
+ | try { | ||
+ | buffer.close(); | ||
+ | } catch (IOException ioe) { | ||
+ | ioe.printStackTrace(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \subsection{Cómo | ||
+ | |||
+ | Como ya hemos visto, Java tiene una serie de \emph{unchecked} y \emph{checked exceptions} | ||
+ | Vamos a ver ahora cómo también podemos crear nuestras propias excepciones y lanzarlas cuando se produzcan situaciones de "más alto nivel" en | ||
+ | nuestra lógica | ||
+ | |||
+ | Por ejemplo, en una aplicación | ||
- | < | + | \begin{lstlisting}[language=java] |
- | public class NoRevisadoException | + | public class FueraDeStockException |
- | public | + | public |
super(); | super(); | ||
} | } | ||
- | public | + | public |
- | super(mensaje); | + | super(mensaje); |
} | } | ||
} | } | ||
- | </ | + | \end{lstlisting} |
- | A continuación, podremos utilizar la excepción | + | Así, cuando |
- | En el ejemplo siguiente, cuando se entrega un coche al cliente hay que comprobar que éste esté revisado previamente. En caso de que no lo esté se producirá un error de tipo '' | + | \begin{lstlisting}[language=java] |
+ | . . . | ||
+ | private void anadirProductoAlCarrito(Producto producto) { | ||
+ | if (producto.getStock() <= 0) { | ||
+ | throw new FueraDeStockException(); | ||
+ | } | ||
+ | } | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
- | < | + | Y de esta manera, por ejemplo, en el controlador o interaz de la aplicación, |
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Ventana { | ||
+ | . . . | ||
+ | try { | ||
+ | . . . | ||
+ | anadirProductoAlCarrito(producto); | ||
+ | . . . | ||
+ | } catch (FueraDeStockException fdse) { | ||
+ | JOptionPane.showMessageDialog(. . .); | ||
+ | fdse.printStackTrace(); | ||
+ | } | ||
+ | . . . | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \subsection{Bloques multi-catch} | ||
+ | |||
+ | También es posible capturar más de un tipo de excepción bajo un mismo bloque \verb catch , aunque no es una práctica recomendada ya que no | ||
+ | permite afinar el caso de error en algunos casos, pero bien utilizado permite que agrupemos en el caso de que varias excepciones tengan | ||
+ | asociado el mismo bloque de código. | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Ventana { | ||
+ | . . . | ||
+ | try { | ||
+ | . . . | ||
+ | anadirProductoAlCarrito(producto); | ||
+ | . . . | ||
+ | } catch (FueraDeStockException | ProductoDescatalogadoException e) { | ||
+ | JOptionPane.showMessageDialog(. . .); | ||
+ | fdse.printStackTrace(); | ||
+ | } | ||
+ | . . . | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \subsection{Uso de recursos en bloques try-catch} | ||
+ | |||
+ | Como hemos visto en el primer ejemplo, accedíamos a un fichero en la excepción, para luego acabar liberando los recursos al finalizar el | ||
+ | bloque \verb try-catch . A veces es habitual que dichos recursos se inicialicen al comenzar la excepción (incluso dentro de ésta) y se | ||
+ | liberen al terminar. Así, ese ejemplo podría escribirse de la siguiente forma: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
. . . | . . . | ||
- | public void entregarVehiculo() throws NoRevisadoException | + | try (BufferedReader buffer = |
- | + | new BufferedReader(new FileReader(new File(" | |
- | | + | |
- | | + | |
+ | | ||
} | } | ||
+ | } catch (FileNotFoundException fnfe) { | ||
+ | System.out.println(" | ||
+ | fnfe.printStackTrace(); | ||
+ | } catch (IOException ioe) { | ||
+ | System.out.println(" | ||
+ | ioe.printStackTrace(); | ||
+ | } | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Para este caso, hay que tener en cuenta que, para que Java pueda liberar automáticamente los recursos de una clase Java, debemos implementar | ||
+ | uno de los interfaces \verb java.lang.AutoClosable | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class MiRecurso implements AutoCloseable { | ||
. . . | . . . | ||
. . . | . . . | ||
+ | public void close() throws Exception { | ||
+ | // Aqui hay que liberar los recursos | ||
+ | // Se ejecutará automáticamente | ||
+ | . . . | ||
+ | . . . | ||
+ | } | ||
} | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \section{Aserciones} | ||
+ | |||
+ | Las aserciones son sentencias utilizadas para comprobar si una condición es cierta (o no) y controlar asi los errores en el código. | ||
+ | Básicamente equivale a una sentencia \verb if que evalúa una condición y genera una Excepción \verb AssertException | ||
+ | mostrando el mensaje asociado a la misma. De forma similar a | ||
+ | cómo hacen las excepciones, | ||
+ | sólo tienen efecto si se pasa la opción \verb -ea o \verb -enableassertions | ||
+ | forma sólo se activan cuando es necesario o interesa utilizarlas. | ||
+ | |||
+ | Veamos un ejemplo: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
. . . | . . . | ||
- | </code> | + | String cadena = "Esto es un texto"; |
+ | . . . | ||
+ | . . . | ||
+ | assertion cadena == null : "La cadena es nula"; | ||
+ | . . . | ||
+ | // También se puede especificar una condición sin mensaje | ||
+ | assertion cadena == null; | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Si ejecutamos el código anterior con la opción \verb -ea activada como opción de la JVM, se nos mostrará el siguiente mensaje de error: | ||
- | ====== Ejemplos ====== | + | \begin{verbatim} |
+ | run: | ||
+ | Exception in thread " | ||
+ | at com.sfaci.prueba.JavaApplication5.main(JavaApplication5.java: | ||
+ | / | ||
+ | BUILD FAILED (total time: 0 seconds) | ||
+ | \end{verbatim} | ||
- | ---- | ||
- | (c) 2019 Santiago Faci | + | (c) 2019-2021 Santiago Faci |
apuntes/excepciones.txt · Last modified: 2023/06/04 18:31 by Santiago Faci