Curso Kotlin | #15. Excepciones
Tags: spanish, kotlin, beginners, programming
Published: 2022-12-15 12:49:21

Bienvenido/a a otro capítulo del Curso de Kotlin! Podés consultar el curso completo desde [este link](https://github.com/maxwellnewage/kotlin-course) que te dejo acá. Podés seguirme por [LinkedIn](https://www.linkedin.com/in/maximilianoburgos/) o [Twitter](https://twitter.com/maxwellnewage) si querés estar al tanto de las próximas publicaciones.

Las excepciones en Kotlin nos permiten evitar comportamientos no deseados ante problemas que se presentan en tiempo de ejecución. Por ejemplo cuando se intenta dividir por cero, castear un tipo por otro no válido, intentar agregar un valor a una lista nula, entre otros casos. Hoy vamos a ver su implementación en el código.

## Manos a la obra
Usemos un ejemplo sencillo de calificaciones: si te doy más de 5 puntos estas aprobado; caso contrario estas reprobado:

```kotlin
print("Cual es tu nota final? > ")
val eval = readLine()!!
 
if(eval.toInt() >= 6){
    println("Estas aprobado")
} else {
    println("Has reprobado")
}
```

Si no entiendes alguna parte, deberías pasarte por la clase de condicionales. En caso contrario, verás que lidiamos con un ejemplo muy sencillo, el cual arroja un resultado según la condicion del número. En la variable eval utilizé el bang bang operator (!!) asumiendo que no mi variable será nula y simplificando la parte de la expresión en nuestra condición.

```kotlin
Cual es tu nota final? > 5
Has reprobado
```

Pero, ¿qué ocurre si en vez de un número, escribo una palabra?:

```
Cual es tu nota final? > mostaza
Exception in thread "main" java.lang.NumberFormatException: For input string: "mostaza"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at MainKt.main(main.kt:8)
```

Dado que el mundo todavía no esta preparado para calificar a la gente con aderezos, recibimos un NumberFormatException, la cual indica que no puede convertir mostaza a un número entero.

## Bloque Try Catch
No queremos que nuestro programa explote cuando ocurra una excepción: necesitamos capturarla y continuar el flujo normalmente. Para ello existe el bloque Try Catch, y lo implementaremos de la siguiente manera:

```kotlin
try {
    if(eval.toInt() >= 6){
        println("Estas aprobado")
    } else {
        println("Has reprobado")
    }
} catch (e: Exception) {
    println("$eval no es un número valido :(")
}
```

Dentro del cuerpo de try debemos ingresar las lineas que serán evaluadas y podrían tener una potencial excepción. Aquí es donde muchos desarrolladores cometen errores, dado que escriben medio programa dentro del bloque, lo cual es innecesario. Solo debemos ingresar lo que consideremos que podría generar una excepción. Luego en catch debemos especificar al programa que ocurrirá cuando se presente la excepción. El parámetro e de tipo Exception (clase padre de todas las excepciones) contiene el stack que vimos arriba, entre otra información útil que podremos devolver si fuera necesario. Nosotros solo indicaremos un mensaje de error:

```
Cual es tu nota final? > mostaza
mostaza no es un número valido :(
```

Esto funcionará bien siempre con “mostaza”, pero imaginemos que luego de obtener la calificación, la dividiremos por cero, porque estamos dementes:

```kotlin
println("Hora de dividir por cero! :D")
val res = eval.toInt() / 0
```

Este bloque de código irá al final de nuestro try.

```
Cual es tu nota final? > 6
Estas aprobado
Hora de dividir por cero! :D
6 no es un número valido :(
```

Como vemos, el comportamiento de nuestro programa es extraño: primero nos explica que estamos aprobados, pero luego dice que “6” no es un número válido. Esto ocurre porque no estamos distinguiendo entre excepciones. Por suerte, podemos especificarlo de la siguiente manera:

```kotlin
print("Cual es tu nota final? > ")
val eval = readLine()!!
 
try {
    if(eval.toInt() >= 6){
        println("Estas aprobado")
    } else {
        println("Has reprobado")
    }
 
    println("Hora de dividir por cero! :D")
    val res = eval.toInt() / 0
} catch (e: NumberFormatException) {
    println("$eval no es un número valido :(")
} catch (e: ArithmeticException) {
    println("$eval no se puede dividir por cero!")
}
```

Podemos utilizar todos los catch que necesitemos, siempre y cuando nos enfoquemos en las excepciones que queramos evaluar:

```
Cual es tu nota final? > 6
Estas aprobado
Hora de dividir por cero! :D
6 no se puede dividir por cero!
```

Recordemos que las excepciones se disparan en el momento en que se ejecuta la linea correspondiente dentro del try y luego salta al catch. Esto funcionaría como un break, por lo cual todo lo que haya debajo no se ejecuta. El disparador en este caso sería eval.toInt() / 0, pero si escribimos un texto:

```
Cual es tu nota final? > patata
patata no es un número valido :(
```

La excepción se va a disparar en if(eval.toInt() >= 6){. Esto ocurre antes de dividir por cero, porque nuestro número no es válido.

## A romper cosas
Capturar excepciones es importante para que nuestro programa no nos explote en la cara, pero también podemos romper cosas nosotros. Esto será muy útil cuando desarrollemos librerías y queramos arrojar nuestras propias excepciones en la cara de otros desarrolladores.

Imaginemos que creamos un programa que requiere un nombre, pero si llega vacío, lanzaremos un error:

```kotlin
print("Cual es tu nombre? >")
val name = readLine()
 
if(name.isNullOrEmpty()){
    throw Exception("El nombre no puede estar vacío!")
} else {
    print("Hola $name!")
}
```

El método isNullOrEmpty pregunta si la variable es nula o esta vacía. Esto solo podemos utilizarlo con los tipo nullable. Si corremos el programa y no introducimos un nombre, nos devolverá lo siguiente:

```
Cual es tu nombre? >
Exception in thread "main" java.lang.Exception: El nombre no puede estar vacío!
    at MainKt.main(main.kt:12)
```

Con la sentencia throw y el tipo de excepción, hemos logrado devolver un mensaje claro y detallado del error. Algo curioso es que también nos indica la linea donde se disparó la excepción (12 en mi caso).

## Conclusiones
Voy a donarles un pequeño secreto a voces en el mundo del desarrollo: La verdadera diferencia entre un desarrollador junior y uno más experimentado, es el manejo inteligente de excepciones. Si se centran en evitar que sus programas exploten y controlar el momento en el que sea importante lanzar una, van a tener un buen dominio del flujo de ejecución de sus aplicaciones. Este tema se extenderá en las siguientes clases, especialmente cuando implementemos funciones y el paradigma de la programación orientada a objetos.