Wednesday, November 1, 2017

Kotlin From Scratch: Exception Handling

Kotlin From Scratch: Exception Handling

Kotlin is a modern programming language that compiles to Java bytecode. It's free and open source, and makes coding for Android even more fun.  

In the previous article, you learned more about object-oriented programming by digging into abstract classes, interfaces, inheritance, and type aliases in Kotlin. 

In this post, you'll continue to learn about programming in Kotlin by learning about exceptions and how to handle them. 

1. Exception Handling

Exceptions are used to indicate a problem in our code during a program's execution. Exception handling is the capability to address (or handle) the exception that might occur. If we don't handle any exception that occurs, our program will stop execution abruptly—crashing our app immediately. 

Exception handling allows our program to continue execution even if there was an exception (though it is highly recommended to log your exceptions and report them using a crash reporting tool like Crashlytics).   

In Java, we have two kinds of exceptions: checked and unchecked. I'll briefly explain both of them, but we'll start with unchecked exceptions. 

Unchecked Exceptions

These are exceptions that are thrown because of flaws in your code. They are a direct or indirect subclass of the RuntimeException superclass. 

Examples of unchecked exceptions include:

  • ArithmeticException: thrown when you divide by zero.
  • ArrayIndexOutOfBoundExceptions: thrown when an array has been accessed with an illegal index. 
  • SecurityException: thrown by the security manager to indicate a security violation.
  • NullPointerException: thrown when invoking a method or property on a null object.

A method that might throw an unchecked exception doesn't contain any information about the exception thrown on its method declaration. 

These types of exception can be prevented by coding right. In the code above, we should have checked if the denominator was zero before performing the operation. For these exceptions, the developer doesn't need to catch the exception using the try...catch block. In other words, we aren't forced by the compiler to wrap the code that might trigger the exception in a try...catch block. Instead, we should just make sure the exceptions never occur in the first place.

Also, remember, Kotlin is a null safe language. In other words, it can help us avoid getting NullPointerExceptions in our code. You can read the Nullability, Loops, and Conditions post to get a refresher on null safety in Kotlin. 

Checked Exceptions in Java

A method that might throw a checked exception needs to declare so in its method signature using the throws keyword. If you call a method that throws a checked exception, you either need to throw it again from your function or to catch it and handle it using a try...catch block. 

Checked exceptions are exceptions that are checked at compile time. These kinds of exceptions inherit from the Exception class. An example of this kind of exception is IOException. This can occur when you try to access a file that can't be opened because it doesn't exist. (FileNotFoundException is a subclass of IOException.)

In the preceding code, we used a try...catch block to handle the IOException inside the editFile() method. We can now call the editFile() method as normal, and the compiler won't complain. 

Looking at the code below, we've refactored the method to instead use the throws keyword in the method signature. This indicates to callers that they need to handle the exception IOException that might be thrown when calling the method editFile().

To call the method above, we need to surround it in a try...catch block to handle the exception.

This has been a brief look at exceptions in Java. Let's now see how Kotlin handles exceptions. 

2. Exceptions in Kotlin

The main difference between Kotlin and Java exception mechanisms is that all exceptions are unchecked in Kotlin. In other words, they are not explicitly declared in the function signatures, as they are in Java.

Here, we have converted the editFile() method to a Kotlin function. You can see that the function doesn't have the throws IOException statement in its function signature. throws isn't even a keyword in Kotlin. 

Also, we can call this function without surrounding it with the try...catch block—and the compiler won't complain. In other words, there's no such thing as checked exceptions in Kotlin. All exceptions are unchecked. (Note that if there is an exception thrown, program execution will stop as normal.) 

If we think this exception might arise, we should still handle it by surrounding the method with a try...catch block—but this is not enforced by the Kotlin compiler. 

If the exception thrown inside the editFile() function is an instance of the IOException class, our catch block will be executed, and we simply print the stack trace for debugging purposes.

The try...catch Block

The try construct with catch and finally clauses in Kotlin is similar to that of Java. 

Here, we are throwing an Exception object inside the try block. Notice we didn't include the new keyword as we do in Java to create a new instance. Also notice that we didn't specify the exception that will be thrown in the function signature as we would have to in Java. 

We handle all subclasses and classes of type Exception in the catch block. The optional finally block is always executed—this is where we typically close any resources or connections that were previously opened so as to prevent resource leaks. For example, if you open a file or create a database or network connection in a try block, you should close or free it in a finally block. 

Note that in Kotlin the throw construct is an expression and can combine with other expressions.

Also, the try construct can be used as an expression.

Here, we assigned the value returned from the try...catch block to the result variable. If the number is not 1, it throws an IllegalArgumentException and the catch block is executed. The false expression in the catch block value will be assigned to the result variable. If the number is 1 instead, then the true expression value will be assigned to the result variable.

Java Interop

Exceptions in Kotlin behave as normal in Java—but I want to make you aware of a useful annotation called @Throws in Kotlin that might come in handy. Because all exceptions in Kotlin are unchecked, developers who consume your Kotlin code from Java might not be aware that your functions throw exceptions. However, you can still add the possible exceptions that might be thrown to a method signature with the @Throw annotation. This will alert Java callers that they need to handle the exception. 

Let's see a practical example of this annotation.

Here, we defined a Kotlin function that can throw an exception IllegalArgumentException only if the type passed to the function is not of type Int

We call this top-level function addNumberToTwo() directly from Java in the following way:

This works fine; the compiler isn't complaining. However, if we want to communicate with Java callers that the addNumberToTwo() top-level function throws an exception, we simply add the @Throws annotation to the function signature. 

This @Throws annotation can accept a comma-separated list of arguments of exception classes. In the code above, we just included one exception class—IllegalArgumentException

Now we have to update our Java code to handle the exception.

If we decompile the Kotlin addNumberToTwo() function, using the Show Kotlin Bytecode feature (if you're in IntelliJ IDEA or Android Studio, use Tools > Kotlin Show Kotlin Bytecode), we'll see the following Java code:

In the generated Java code above (some elements of the generated code were removed for brevity's sake), you can see that the compiler added the throws keyword to the method signature—because we included the @Throws annotation. 

Conclusion

In this tutorial, you learned more about programming in Kotlin by looking into exceptions. We saw that Kotlin doesn't have checked exceptions but that instead, all exceptions are unchecked. We also looked at how to handle exceptions using the try...catch block and saw the usefulness of the @Throws annotation in Kotlin for Java callers. 

To learn more about the Kotlin language, I recommend visiting the Kotlin documentation. Or check out some of our other Android app development posts here on Envato Tuts!

  • Android SDK
    Java vs. Kotlin: Should You Be Using Kotlin for Android Development?
    Jessica Thornsby
  • Android SDK
    Introduction to Android Architecture Components
    Tin Megali
  • Android SDK
    Get Started With RxJava 2 for Android
    Jessica Thornsby
  • Android SDK
    Concurrency in RxJava 2
    Chike Mgbemena


No comments:

Post a Comment