Sunday 18 July 2021

Android Java to Kotlin migration by example part 11: basic exceptions

Today I'll show you how to catch and throw an exception in Kotlin.

The program illustrating the problem will be simple code, doing integer division. Such division throws an ArithemeticException if the divider is 0

Traditionally, let's begin with Java:

Listing 1 (Java)

import static java.lang.System.out;

public class MainClass {

static int divide(int a, int b) {
return a / b;
}

public static void main(String[] args) {
out.println("" + divide(6, 2));

try{
out.println(""+divide(3,0));
}catch(ArithmeticException ae){
out.println("division by 0!");
}
out.println("" + divide(3, 0));

}
}

We call our divide method 3 times: with (6,3) arguments (which simply gives us result: 2), with (3,0) arguments inside the try...catch block (which results in catching the exception and printing division by 0! to console, and finally with (3,0) arguments without try...catch block, which results in end of program execution, with message:

Listing 2 (result)

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at MainClass.divide(MainClass.java:6)
    at MainClass.main(MainClass.java:17)

So the program prints altogether:

Listing 3 (result)

3
division by 0!
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at MainClass.divide(MainClass.java:6)
    at MainClass.main(MainClass.java:17)

First, the result is simply computed. Then, as integer division by 0 is not possible, the program throws the ArithmeticException exception. The program continues, because we catch it. Then, the program throws it again, and - as it's not caught this time, the program execution ends.

The Kotlin version of program from Listing 1 is pretty straightforward:

Listing 4 (Kotlin)

package com.mypackage

import java.lang.ArithmeticException

fun divide(a: Int, b: Int): Int{
return a/b
}

fun main() {
println(""+ divide(6,2))
try{
println(""+ divide(3,0))
}catch (ae: ArithmeticException){
println("division by 0!")
}
println(""+ divide(3,0))
}

As mentioned in part 1 of this tutorial, the exception type declaration in catch block is a bit diffferent in Kotlin. The results are the similar:

3
division by 0!
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.mypackage.MainKt.divide(main.kt:6)
    at com.mypackage.MainKt.main(main.kt:16)
    at com.mypackage.MainKt.main(main.kt)

The only difference is the additional level of stacktrace in the logs... Which I, frankly, don't understand :D May have something to do with my main class configured in the project, being com.mypackage.MainKt?

But what if we want to define out own, custom exception? Let's define a simple one in Java and throw it in our divide method when the divisor is 0 (and then let's catch it instead of the ArithmeticException):

Listing 5 (Java)

import static java.lang.System.out;

class ReallyException extends Exception{
public ReallyException(String errorMessage) {
super(errorMessage);
}
}
public class MainClass {

static int divide(int a, int b) throws ReallyException {
if(b==0)
throw new ReallyException("Really? By 0?");
return a / b;
}

public static void main(String[] args) throws ReallyException {
out.println("" + divide(6, 2));

try{
out.println(""+divide(3,0));
}catch(ReallyException ae){
out.println("Exception message: " + ae.getMessage());
}
out.println("" + divide(3, 0));

}
}

Please not that as the ReallyException is not caught everywhere it could appear, we have to add the throws ReallyException directive to the main() method. The execution result is as follows:

Listing 6 (result)

3
Exception message: Really? By 0?
Exception in thread "main" ReallyException: Really? By 0?
    at MainClass.divide(MainClass.java:12)
    at MainClass.main(MainClass.java:24)

The Kotlin version of the program from Listing 5 would look like this:

Listing 7 (Kotlin)

package com.mypackage

class ReallyException(message:String): Exception(message)

fun divide(a: Int, b: Int): Int{
if(b==0)
throw ReallyException("Really? By 0?")
return a/b
}

fun main() {
println(""+ divide(6,2))
try{
println(""+ divide(3,0))
}catch (ae: ReallyException){
println("Exception message: " + ae.message)
}
println(""+ divide(3,0))
}

Traditional Kotlin brevity shows up: the (trivial) definition of the exception, which in Java took us 5 lines of code, here becomes... just 1 line :) Also, there is not need to declare our main() function throws anything.

One more thing: try in Kotlin, similarly to if and when, is an expression, which means it can return something. To be specific: it returns either the contents of try block in case exception doesn't occur, or catch block content in case of exception. Like this:

Listing 8 (Kotlin)

package com.mypackage

import java.lang.ArithmeticException

fun divide(a: Int, b: Int): Int{
return a/b
}

fun main() {

val result1 =
try { divide(4,2) } catch (e: ArithmeticException) { 9999 }
val result2 =
try { divide(4,0) } catch (e: ArithmeticException) { 9999 }

println(result1)
println(result2)
}

... resulting in:

2
9999

... as the first call simply returns 2, and the second one results in an exception, and therefore returns contents of  catch block, in our case being number 9999.

No comments:

Post a Comment

Python crash course part 10: inheritance and polymorphism

In the last part we've shown how to create and use a class in Python. Today we're going to talk about inheritance: wchich means cre...