JavaRush /Blog Java /Random-ES /Excepciones en Java: captura y manejo

Excepciones en Java: captura y manejo

Publicado en el grupo Random-ES
¡Hola! Odio decírtelo, pero una gran parte del trabajo de un programador consiste en lidiar con errores. Y la mayoría de las veces, con los suyos. Da la casualidad de que no hay personas que no cometan errores. Y tampoco existen tales programas. Por supuesto, lo principal a la hora de solucionar un error es comprender su causa. Y puede haber muchas razones para esto en el programa. En un momento, los creadores de Java se enfrentaron a una pregunta: ¿qué hacer con estos errores potenciales en los programas? Evitarlos por completo no es realista. Los programadores pueden escribir algo que es imposible de imaginar :) Esto significa que es necesario incorporar en el lenguaje un mecanismo para lidiar con errores. En otras palabras, si se ha producido algún error en el programa, se necesita un script para seguir trabajando. ¿Qué debe hacer exactamente el programa cuando ocurre un error? Hoy nos familiarizaremos con este mecanismo. Y se llama “Excepciones .

¿Qué es una excepción en Java?

Una excepción es alguna situación excepcional y no planificada que ocurrió durante la operación del programa. Puede haber muchos ejemplos de excepciones en Java. Por ejemplo, escribiste un código que lee texto de un archivo y muestra la primera línea en la consola.
public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
¡Pero ese archivo no existe! El resultado del programa será una excepción - FileNotFoundException. Conclusión:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Cada excepción está representada por una clase separada en Java. Todas las clases de excepción provienen de un "antepasado" común: la clase principal Throwable. El nombre de la clase de excepción suele reflejar brevemente el motivo de su aparición:
  • FileNotFoundException(archivo no encontrado)
  • ArithmeticException(excepción al realizar una operación matemática)
  • ArrayIndexOutOfBoundsException(el número de la celda de la matriz se especifica más allá de su longitud). Por ejemplo, si intenta enviar una matriz de celdas [23] a la consola para una matriz de longitud 10.
¡Hay casi 400 clases de este tipo en Java! ¿Porqué tantos? Precisamente para que a los programadores les resulte más cómodo trabajar con ellos. Imagínese: usted escribió un programa y, cuando se ejecuta, arroja una excepción similar a esta:
Exception in thread "main"
Uh-uh :/ Nada está claro. No está claro qué tipo de error es y de dónde viene. No hay información útil. Pero gracias a tal variedad de clases, el programador obtiene lo principal para sí mismo: el tipo de error y su causa probable, que está contenida en el nombre de la clase. Después de todo, es algo completamente diferente de ver en la consola:
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
¡Inmediatamente queda claro cuál podría ser el problema y “en qué dirección excavar” para resolverlo! Las excepciones, como cualquier instancia de clase, son objetos.

Captura y manejo de excepciones

Para trabajar con excepciones en Java, existen bloques de código especiales try: catchy finally. Excepciones: interceptación y procesamiento - 2El código en el que el programador espera que se produzcan excepciones se coloca en un bloque try. Esto no significa que necesariamente se producirá una excepción en este lugar. Esto significa que puede suceder allí y el programador lo sabe. El tipo de error que espera recibir se coloca en un bloque catch(“catch”). Aquí también es donde se coloca todo el código que debe ejecutarse si ocurre una excepción. He aquí un ejemplo:
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("¡Error! ¡Archivo no encontrado!");
   }
}
Conclusión:

Ошибка! Файл не найден!
Ponemos nuestro código en dos bloques. En el primer bloque esperamos que se produzca el error "Archivo no encontrado". Este es un bloque try. En el segundo, le indicamos al programa qué hacer si ocurre un error. Además, existe un tipo específico de error: FileNotFoundException. Si pasamos catchotra clase de excepción entre corchetes de bloque, no será detectada.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("¡Error! ¡Archivo no encontrado!");
   }
}
Conclusión:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
El código del bloque catchno funcionó porque "configuramos" este bloque para interceptar ArithmeticExceptiony el código del bloque tryarrojó otro tipo: FileNotFoundException. No escribimos un script para FileNotFoundException, por lo que el programa muestra en la consola la información que se muestra de forma predeterminada para FileNotFoundException. Aquí debes prestar atención a 3 cosas. Primero. Tan pronto como ocurre una excepción en cualquier línea de código en un bloque de prueba, el código posterior ya no se ejecutará. La ejecución del programa “saltará” inmediatamente al bloque catch. Por ejemplo:
public static void main(String[] args) {
   try {
       System.out.println("Dividir un número por cero");
       System.out.println(366/0);//esta línea de código generará una excepción

       System.out.println("Este");
       System.out.println("código");
       System.out.println("No");
       System.out.println("voluntad");
       System.out.println("¡hecho!");

   } catch (ArithmeticException e) {

       System.out.println("¡El programa saltó al bloque catch!");
       System.out.println("¡Error! ¡No puedes dividir por cero!");
   }
}
Conclusión:

Делим число на ноль 
Программа перепрыгнула в блок catch! 
Ошибка! Нельзя делить на ноль! 
En el bloque tryde la segunda línea, intentamos dividir un número entre 0, lo que resultó en una excepción ArithmeticException. Después de esto, las líneas 6 a 10 del bloque tryya no se ejecutarán. Como decíamos, el programa inmediatamente comenzó a ejecutar el bloque catch. Segundo. Puede haber varios bloques catch. Si el código de un bloque trypuede generar no uno, sino varios tipos de excepciones, puedes escribir tu propio bloque para cada una de ellas catch.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("¡Error! ¡Archivo no encontrado!");

   } catch (ArithmeticException e) {

       System.out.println("¡Error! ¡División por 0!");

   }
}
En este ejemplo escribimos dos bloques catch. Si tryocurre en el bloque FileNotFoundException, se ejecutará el primer bloque catch. Si sucede ArithmeticException, se ejecutará el segundo. Puedes escribir al menos 50 bloques catch, pero, por supuesto, es mejor no escribir código que pueda generar 50 tipos diferentes de errores :) En tercer lugar. ¿Cómo sabes qué excepciones podría generar tu código? Bueno, por supuesto, puedes adivinar algunas cosas, pero es imposible tenerlo todo en tu cabeza. Por lo tanto, el compilador de Java conoce las excepciones más comunes y sabe en qué situaciones pueden ocurrir. Por ejemplo, si escribió código y el compilador sabe que pueden ocurrir dos tipos de excepciones durante su operación, su código no se compilará hasta que las maneje. Veremos ejemplos de esto a continuación. Ahora con respecto al manejo de excepciones. Hay 2 formas de procesarlos. Ya hemos conocido el primero: el método puede manejar la excepción de forma independiente en el bloque catch(). Hay una segunda opción: el método puede generar una excepción en la pila de llamadas. ¿Qué significa? Por ejemplo, en nuestra clase tenemos un método -el mismo- printFirstString()que lee un archivo y muestra su primera línea en la consola:
public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Actualmente nuestro código no se compila porque tiene excepciones no controladas. En la línea 1 indicas la ruta al archivo. El compilador sabe que dicho código puede conducir fácilmente a FileNotFoundException. En la línea 3 lees el texto del archivo. En este proceso, puede ocurrir fácilmente IOExceptionun error durante la entrada-salida (Input-Output) . Ahora el compilador te dice: “Amigo, no aprobaré este código ni lo compilaré hasta que me digas qué debo hacer si ocurre una de estas excepciones. ¡Y definitivamente pueden suceder según el código que escribiste! . ¡No hay ningún lugar adonde ir, debes procesar ambos! La primera opción de procesamiento ya nos resulta familiar: debemos colocar nuestro código en un bloque tryy agregar dos bloques catch:
public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("¡Error, archivo no encontrado!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("¡Error al ingresar/salir datos del archivo!");
       e.printStackTrace();
   }
}
Pero ésta no es la única opción. Podemos evitar escribir un script para el error dentro del método y simplemente lanzar la excepción al principio. Esto se hace usando la palabra clave throws, que está escrita en la declaración del método:
public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Después de la palabra, throwsenumeramos, separados por comas, todos los tipos de excepciones que este método puede generar durante la operación. ¿Por qué se hace esto? Ahora, si alguien en el programa quiere llamar al método printFirstString(), tendrá que implementar el manejo de excepciones él mismo. Por ejemplo, en otra parte del programa, uno de sus colegas escribió un método dentro del cual llama a su método printFirstString():
public static void yourColleagueMethod() {

   //...el método de tu colega hace algo

   //...y en un momento llama a su método printFirstString() con el archivo que necesita
   printFirstString("C:\\Usuarios\\Eugene\\Escritorio\\testFile.txt");
}
¡Error, el código no se compila! printFirstString()No escribimos un script de manejo de errores en el método . Por tanto, la tarea recae sobre quienes utilizarán este método. Es decir, el método yourColleagueMethod()ahora enfrenta las mismas 2 opciones: debe procesar ambas excepciones que "volaron" hacia él usando try-catcho reenviarlas más.
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   //...el método hace algo

   //...y en un momento llama a su método printFirstString() con el archivo que necesita
   printFirstString("C:\\Usuarios\\Eugene\\Escritorio\\testFile.txt");
}
En el segundo caso, el procesamiento recaerá sobre los hombros del siguiente método en la pila: el que llamará yourColleagueMethod(). Es por eso que este mecanismo se llama "lanzar una excepción hacia arriba" o "pasar a la cima". Cuando lanzas excepciones usando throws, el código se compila. En ese momento, el compilador parece decir: “Está bien, está bien. Su código contiene un montón de posibles excepciones, pero lo compilaré de todos modos. ¡Volveremos a esta conversación! Y cuando llamas a un método en algún lugar del programa que no ha manejado sus excepciones, el compilador cumple su promesa y te las recuerda nuevamente. Finalmente, hablaremos del bloque finally(perdón por el juego de palabras). Esta es la última parte del triunvirato de manejo de excepciones try-catch-finally. Su peculiaridad es que se ejecuta bajo cualquier escenario de operación del programa.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("¡Error! ¡Archivo no encontrado!");
       e.printStackTrace();
   } finally {
       System.out.println("¡Y aquí está el último bloque!");
   }
}
En este ejemplo, el código dentro del bloque finallyse ejecuta en ambos casos. Si el código del bloque tryse ejecuta por completo y no genera una excepción, el bloque se activará al final finally. Si el código interno tryse interrumpe y el programa salta al bloque catch, después de ejecutar el código interno catch, el bloque seguirá seleccionado finally. ¿Por qué es necesario? Su objetivo principal es ejecutar la parte requerida del código; esa parte que debe completarse independientemente de las circunstancias. Por ejemplo, suele liberar algunos recursos utilizados por el programa. En nuestro código, abrimos una secuencia para leer información de un archivo y pasarla a un archivo BufferedReader. readerEs necesario cerrar el nuestro y liberar recursos. Esto debe hacerse en cualquier caso: no importa si el programa funciona como se esperaba o genera una excepción. Es conveniente hacer esto en bloque finally:
public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println("¡Y aquí está el último bloque!");
       if (reader != null) {
           reader.close();
       }
   }
}
Ahora estamos absolutamente seguros de que nos hemos ocupado de los recursos ocupados, independientemente de lo que suceda mientras se ejecuta el programa :) Eso no es todo lo que necesita saber sobre las excepciones. El manejo de errores es un tema muy importante en programación: se le dedica más de un artículo. En la próxima lección aprenderemos qué tipos de excepciones existen y cómo crear la tuya propia :) ¡Nos vemos allí!
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION