In this blog post, we will be looking into what are Exceptions, what are its types and how it is handled in the Kotlin language.
What are Exceptions?
An Exception can be explained as an event/condition which a user encounters when the program is executed. This might lead to abruptly termination of the program or even the crash of the application.
What are different types of Exceptions?
Those of you, who have studied Java might classify it into types:
- Checked Exceptions
- Unchecked Exceptions
Let’s look into each of them one by one:
Checked Exception
Checked Exceptions are the exceptions that are handled at the compile time. The compiler will give you an error if you do not handle the exception while writing the code. The exceptions can be handled by writing the try/catch block around the lines of code where an exception might be introduced or by using throws keyword around the method definition in java.
Let’s have a look at the simple example of Checked Exception:
public static void main(String[] args) { FileReader file = new FileReader("main/raw/temp.json"); BufferedReader fileInput = new BufferedReader(file); int eof; while ((eof = file.read()) != -1) { err.print(i); } fileInput.close(); }
If you will try to compile the above code, it will give you compile time error i.e It gives you Checked Exception warning, which you can mitigate by either using the try/catch block or by adding an exception to the method signature.
public static void main(String[] args) { try { FileReader file = new FileReader("main/raw/temp.json"); BufferedReader fileInput = new BufferedReader(file); int i; while ((i = file.read()) != -1) { err.print(i); } fileInput.close(); } catch (IOException e) { Log.d("Exception", "" + e); } }
public static void main(String[] args) throws IOException { FileReader file = new FileReader("main/raw/temp.json"); BufferedReader fileInput = new BufferedReader(file); int i; while ((i = file.read()) != -1) { err.print(i); } fileInput.close(); }
An important point to note here is that Kotlin does not have support for the Checked Exceptions just like some other programming languages like C++, Objective C, and C# which support only Unchecked Exceptions. Hence, In kotlin, developers do not need to worry about all those try/catch blocks!
Unchecked Exceptions
Unchecked Exceptions are those exceptions which are not checked by the compiler and are introduced in the code due to bad programming style.
All the unchecked Exceptions are subclasses of RuntimeException class. Some of the most common Unchecked Exceptions among many are:
- ActivityNotFoundException
- ArrayIndexOutOfBound Exception
Let’s look into one of the simple example of Unchecked Exception where we will be printing the contents of the file
fun main() { readFileContents() } fun readFileContents() { File("app/src/main/java/testfile.txt").forEachLine { println(it) } }
Output of the above program is:
Hello this is a test file This file may contain a lot of data. My Name is Sarabjit Bagga
What might have happened if testfile.txt was not present or we had a typo while writing the name? Right, An Application Crash! Since, Kotlin does not support Checked Exception, it becomes responsibility of the programmer to put the following code under try/catch block and log the exception and terminate the application gracefully. Let’s modify our code:
fun main() { try { readFileContents() } catch (e: IOException) { println("Exception Caught") println(e.localizedMessage) } finally{ println("Finally Executed") } } @Throws(IOException::class) fun readFileContents() { File("app/src/main/java/testfile1.txt").forEachLine { println(it) } }
When we execute the above program , we get the following output
Exception Caught app/src/main/java/testfile1.txt (No such file or directory) Finally Executed
Now, you might be wondering what is this @Throws Annotation over the method readFileContents()? Actually, this is a good practice to tell the compiler what exceptions will be thrown by this method as the same will be translated to the JVM method. For example, when the above method will be translated into the JVM method it will look like something like this:
void readFileContents() throws IOException{.....}
Like in Java, when try/catch block is completed, if followed by finally block that is executed regardless of try/catch result. Generally, this method is used to let go of the memory occupied by variables which might not be needed anymore.
One of the coolest features of the Kotlin language is that Exceptions are also treated as Expressions i.e you can get a value from the Exception Handling method. Let’s look into it with a simple program:
fun main() { val result = checkIsInputValid(inputNumber()) if (result == -1) { println("Table Cannot be printed") } else { printTable(result) } } fun checkIsInputValid(res: String?): Int { try { return res!!.toInt() } catch (exception: NumberFormatException) { println("Invalid Number Entered") return -1 } } fun inputNumber(): String? { print("Please Enter a number to print the table: ") return readLine(); } fun printTable(num: Int) { for (i in 1..10) { println(num * i) } }
Let’s look at the output, when we supply input as 2
Please Enter a number to print the table: 2 2 4 6 8 10 12 14 16 18 20
Let’s also look at the output, when we give invalid input
Please Enter a number to print the table: Sarabjit Bagga Invalid Number Entered Table Cannot be printed
Moving on, What about Custom Exceptions in Kotlin? Can we create Custom Exceptions in the Kotlin language? Let’s look into the same:
class TestStudent(val name: String, val age: Int) { fun studentDetails() { println("Student Name is $name and age is $age") } @Throws(RuntimeException::class) fun validateStudentName() { if (name.matches(Regex(".*\\d+.*"))) { throw ValidateDataException("name : $name : contains digits") } } @Throws(RuntimeException::class) fun validateStudentAge() { if (age < 3 || age > 18) { throw ValidateDataException("Student age $age does not qualify.") } } } class ValidateDataException(message: String) : RuntimeException(message) fun main() { val student = TestStudent("Sarabjit Bagga9", 30) student.validateStudentName() student.validateStudentAge() student.studentDetails() }
If you look at the above code, the output will be this:
Exception in thread "main" com.example.exceptions.InvalidNameException: name : Sarabjit Bagga9 : contains digits at com.example.exceptions.TestStudent.validateStudentName(TestStudent.kt:12) at com.example.exceptions.TestStudentKt.main(TestStudent.kt:29) at com.example.exceptions.TestStudentKt.main(TestStudent.kt)
So what exactly happened? So we created a custom class ValidateDataException which extends the RunTimeException and passed the parameter value to the RunTimeException class.
An important point to note here is to send a customized exception we use Throw keyword as shown in the above example and passing your customized message as the parameter of the object of the defined custom class(ValidateDataException).
One more concept which we should have a look is at the Nothing keyword:
Nothing Keyword
The best example to link Nothing is with keyword void of Java. Nothing in kotlin has no instances. It is used to represent a value that never exists. A function which has a return type of Nothing means it returns nothing. Let’s look at the simple example:
fun main() { try { canThrowException() } catch (e: IOException) { println("Exception Caught") } finally { println("Finally Executed") } } @Throws(IOException::class) fun canThrowException(): Nothing { throw IOException("Could not read the file") }
So we can say that the method canThrowException return Nothing and is of type void as per java Convention.
I hope with this blog post, you have acquired knowledge of handling Exceptions in Kotlin. Feel free to comment or reach out to me for any queries. Until the next one, stay tuned…