Skip to content

Instantly share code, notes, and snippets.

@mochadwi

mochadwi/blog.md Secret

Created June 22, 2021 16:05
Show Gist options
  • Save mochadwi/fc67eb7638af745746eb41fda3af155b to your computer and use it in GitHub Desktop.
Save mochadwi/fc67eb7638af745746eb41fda3af155b to your computer and use it in GitHub Desktop.

Problems: Exception Handling

Java eliminates the problems we might find on a specific operation in specific programming language (back then), see this examples

https://gist.github.com/8ccfca71b9bc3cc63ede3b8fd133105d

Referenced from: https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07

Writing the above handling seems to much error-prone if there's no proper linter (pipeline) and a strict code review process.

An alternative: Throw Exception

Java then introduce the throws keyword as a compiler checks that we needs to check or handle it because this unique concept of checked exceptions would solve the error-prone of error-handling using a manual if condition with try/catch but that's not the case exception designed in Kotlin.

Checked exceptions is something to guard our codebase so we are recommended to catch that particular method when invoked, e.g:

https://gist.github.com/25d386b5337e23e3fa81fbdf92b209cb

References from: https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt(java.lang.String)

The above checked exception allowing us to have the compiler checks to handle it with try/catch for example:

Compiler checks:

Screen Shot 2021-06-21 at 10.13.54 AM.png

If we didn't handle the checked exceptions on method .read it'll show a compiler error checks

Warning checks:

Screen Shot 2021-06-21 at 9.46.09 AM.png

This code still compiled & runs, but might produce NPE in the runtime

The above approach was still something tedious to write especially the anti-pattern for this simple exceptions

https://gist.github.com/074bc454213d35cfa2539c89a2133486

We'll not cover up the gritty details about the above anti-pattern but you can see here for details: https://stackoverflow.com/q/409563/3763032

TL;DR: The anti-pattern stated that we should catch only the relevant exception so we know for sure what to handle, instead of catch the general class Exception that will throw any possible (almost everything) that (un)intended as well

Multicatch exist!

Prior to Java 7 this is not possible, since the Java 7, now we can write a simple "or" for the exception, see here for details: https://www.geeksforgeeks.org/multicatch-in-java/

Let's see the sneak-peek of what it looks like both in Java & Kotlin for the multicatch exception:

Screen Shot 2021-06-20 at 5.59.06 PM.png

Well, in Java we had what we called a multicatch exception using a smiple | symbol and voila, it's more readable but how about in Kotlin?

Unfortunately the kotlin by design it's not desired purpose to have a multicatch exception as this ticket https://youtrack.jetbrains.com/issue/KT-7128 (still opened from 6yr ago)

And we're ended up abusing every possible exception as shown in this

The difference with Kotlin approach

Screen Shot 2021-06-20 at 6.21.22 PM.png

Yes the above is our codebase approach back then :))) when handling the TUS protocol because its variety of possible exception thrown inside the try statement :(

There'a a follow up statement regarding the multicatch in this following resources that recommended to watch on the wekeends

Video: https://www.youtube.com/watch?v=KZc_0LjF7_Q

Later, we modify our code to be more readable with an alternative of multicatch exception, and inspired by the community to have this extensions instead:

https://gist.github.com/8f9326ee891729394e1a117a8f9cce3d

Referenced here: https://stackoverflow.com/a/49407498/3763032

Problems

We solve most of our exception problems back then with the above nice little extension for a while, until we use a heavy lambda action & coroutines (and yes we use Streams in our Java code as well).

Psssttt don't tell anyone, we also invested heavily on building a interopability like suspend function to be called in Java :)

https://gist.github.com/275e0bf6e9c9776fefb5cf559bef276f

Our kotlin codes:

https://gist.github.com/b4a8508c572465300526e9c0acd0ead2

Also many more like making our Java APIs to be deprecated and called the Kotlin version the interopability in Kotlin comes at a price such as the above condition suspend and many annotation we used such as JvmOverloads, JvmName, JvmStatic etc

Why the exception is not mixed well in the lambda? Let's see the following examples:

https://gist.github.com/c5a659932558d76529b91f66259e0b8a

Referenced here: https://www.baeldung.com/java-lambda-exceptions

The above code inside .forEach might be problems when there's a 0 values in the list and thrown the ArithmeticException: / by zero. That's bad!

Even we modify our code to be have an exception like this

https://gist.github.com/16778dcbf74d11fcf8a452fb644234e6

But that's another tedious & challenging code to write :) also we're losing the conciseness of the lambda approach.

Writing a wrapper for the try catch also convenient but that's another tech debt to introduce :))) as shown in here from Baeldung

More examples shown how much boilerplate to write with lambda function that returns a simple checked exception as explained details in this articles here from DZone

tl;dr a wrapper workaround: https://stackoverflow.com/a/18198349/3763032

So how Kotlin Design its Exception?

The concept is the same with Java checked exception as a return value of functions with an annotation called @Throws, see here from official kotlin docs

Kotlin also aware about pre-conditions (alternatively in Java we used Guava) turns out Kotlin has it in their SDK

A preconditions is a mechanism to throw an exception that we unable to detect at compile time

e.g require(Boolean) {}:

https://gist.github.com/3f1cfc9ca96a8a5dc2b531a68588f62b

Referenced from: https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07#:~:text=handling%20program%20logic

TL;DR:

Checked Exceptions: @Throws(NullPointerException::class) fun doSomething() we need to handle it before compilation otherwise it'll show a compile-error

Preconditions: to check runtime or program (or logic) error such as the above snippet using require(Boolean) {}

Kotlin Contract (compile-time): This is require a separate discussion, but worth to read how Kotlin allowing us to write the extension or method that's has some kind of linter to fails the compile See here: https://engineering.premise.com/using-kotlins-contract-apis-for-smarter-helper-functions-6b5b482e23b4

We are recommended to avoid code smell in our kotlin code as stated from Roman Elizarov here:

Screen Shot 2021-06-20 at 7.50.47 PM.png

Dual-use APIs

You might familiar with this kind of extensions in Kotlin, such as:

https://gist.github.com/b3f4261e1a25dee976db02e7d917555b

Why kotlin bother to create a different method just for the sake of a nullability?

It's for us to avoid this writing try/catch style:

https://gist.github.com/847e71d6bf0228c7c5dc8b8f067c4534

Instead we can use the .toIntOrNull() and our code now is more readable:

https://gist.github.com/7c99305303a75f16e8da7fd8c2eb4f5a

From a list or collection & map has their own extensions of a dual-use APIs for our conveniences e.g: getOrNull!

The power of elvis operator ?: that really convenient to be used when dealing with nullability

This concepts introduces was to leverage the nullability features in Kotlin there's a supportive statement why null is not a foe or such-called a billion dollar mistakes (but a friends), see here: https://elizarov.medium.com/null-is-your-friend-not-a-mistake-b63ff1751dd5

Why kotlin doesn't have the ternary operator like in Java: https://youtu.be/0FF19HJDqMo?t=1358

Or go to this kotlin discussions: https://discuss.kotlinlang.org/t/ternary-operator/2116/24

Designing the API

For us when writing the code, whether we ships and SDK to be consumed by fellow developers or internally, we need to bear in mind that:

  1. use exceptions for logic errors
  2. type-safe results for everything else
  3. if not logic error, write a wrapper to convert exceptions to a desired return values

Therefore our caller will be freed to such length from handling the old try/catch! :(

P.S.:

  1. If it single error condition, success or failure? Use null as a failure and a type-safe result for success
  2. If it a multiple error condition, take a bit of time to write a wrapper (explained in more details later)

https://gist.github.com/ba5ea0dae2ea8b2688cab5e91e1a8f6d

We define a sealed class for the type-safe result of ParseException instead a simpler failure to return null, because we (for example) wants to return the errorOfset.

Why sealed class? the result of .parse and .errorOfset was returning a different data type, therefore we wrap it as a sealed class instead.

This is might be a rare case, but as our guidelines for the multiple error conditions or a different return values for failure cases

Input or Outputs failures

As previously stated about require(Boolean) {} this is a good preconditions so that the caller side can have a more centralized (self-documenting) code that we need to avoid adding the negative values for it, e.g:

https://gist.github.com/5de4dedb953915f2469fa10234f0b0b5

Referenced from: https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07

Asynchronous and Coroutines Exceptions

In kotlin this is by principles is a first class citizen supported for the coroutineScope & launch that indicate cancellation or failures (internally use the checked exceptions)

See full details about exception in coroutines here: https://medium.com/androiddevelopers/exceptions-in-coroutines-ce8da1ec060c#:~:text=Coroutines%20use%20the%20regular%20Kotlin,treat%20exceptions%20in%20different%20ways.

There's a handy extensions called .runCatching and for the Kotlin Flow we can also using .catch operator to handle the exceptions, therefore no need to use the old-school try-catch anymore

Bonus

It's also recommended to catch up with kotlin community on a slack, youtrack & github issue for examples:

  1. Kotlin/kotlinx.coroutines#1147 (this is where the coroutines discussion takes places)
  2. https://twitter.com/kotlin/status/1022114553302331392?s=20 (kotlinlang.slack.com) we can find many Kotlin related library here (also: Android, Square, community libs etc)
  3. If wants to know more about the Kotlin design and enhancement we can starred this repo for sure: https://github.com/Kotlin/KEEP
  4. A curated Kotlin newsletter: http://www.kotlinweekly.net/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment