Kotlin Exception Handling Utility – Clean Logging, Centralized Catching
Kotlin Exception Handling: Tame Errors Like a Pro in 2025!
Handle runtime issues with Kotlin’s exception handling. This 2025 guide provides practical examples, a utility class, and tips to make your code crash-proof!
Key Constructs
- 🔍 try: Wraps risky code, paired with catch or finally.
- 🛡️ catch: Handles specific exceptions from try.
- ✅ finally: Runs cleanup tasks, exception or not.
- 💥 throw: Triggers custom exceptions.

Exception Types ⚠️🔍
Kotlin exceptions are unchecked, inheriting from Throwable
(Error
or Exception
). Key types:
- ➗ ArithmeticException: Division by zero.
- 📏 ArrayIndexOutOfBoundsException: Invalid array index.
- 🔄 ClassCastException: Invalid type casting.
- 📁 FileNotFoundException: Non-existent file access.
- 💾 IOException: Input/output errors.
- ⏸️ InterruptedException: Thread interruption.
- 🚫 NullPointerException: Null object access.
- 🔒 SecurityException: Security violations.
- 🔢 NumberFormatException: Invalid number conversion.
- 📉 IndexOutOfBoundsException: Invalid list/array index.
- 🌐 RemoteException: Remote service errors.
- ⚠️ IllegalStateException: Invalid state operations.
- 🚫 UnsupportedOperationException: Unsupported operations.
- 💥 RuntimeException: General runtime errors.
- 🔍 NoSuchElementException: Missing collection elements.
- 🔄 ConcurrentModificationException: Collection modified during iteration.
ExceptionUtils: Logging Utility 🐞📝
Log exceptions consistently with ExceptionUtils
.
try {
val str: String? = null
val length = str!!.length // 🚫 NullPointerException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "NullCheck: Missing string")
}
Log Output:
🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 Feature : NullCheck: Missing string 🐞 Exception : 🚫 NullPointerException 🐞 Message : null 🐞 Method : someMethod 🐞 Line no : 123 🐞 File name : (SomeFile.kt:123)
Multiple Catch Blocks 🛡️🔄
Handle different exceptions with multiple catch
blocks.
fun main() {
try {
val a = IntArray(5)
a[5] = 10 / 0 // 📏 ArrayIndexOutOfBoundsException
} catch (e: ArithmeticException) {
println("Arithmetic exception caught")
} catch (e: ArrayIndexOutOfBoundsException) {
println("Array index out of bounds caught") // 📜 Output
} catch (e: Exception) {
println("General exception caught")
}
}
Nested Try-Catch Blocks 🛡️🔗
Handle layered risks with nested try-catch
.
fun main() {
val nume = intArrayOf(4, 8, 16, 32, 64, 128, 256, 512)
val deno = intArrayOf(2, 0, 4, 4, 0, 8)
try {
for (i in nume.indices) {
try {
println("${nume[i]} / ${deno[i]} is ${nume[i] / deno[i]}") // ➗ ArithmeticException
} catch (exc: ArithmeticException) {
println("Can't divide by zero!") // 📜 Output
}
}
} catch (exc: ArrayIndexOutOfBoundsException) {
println("Element not found.") // 📜 Output
}
}
Finally Block ✅🧹
Cleanup with finally
, runs regardless of exceptions.
fun main() {
try {
val data = 10 / 5
println(data) // 📜 Output: 2
} catch (e: NullPointerException) {
println(e)
} finally {
println("Finally block always executes") // 📜 Output
}
}
Throw Keyword 💥🚨
Trigger custom exceptions with throw
.
fun main() {
try {
validate(15)
println("Code after validation check...")
} catch (e: ArithmeticException) {
println("Caught: ${e.message}") // 📜 Output: Caught: under age
}
}
fun validate(age: Int) {
if (age < 18) {
throw ArithmeticException("under age") // 💥
} else {
println("Eligible to drive")
}
}
Try as an Expression 🧠🔄
Use try
as an expression for functional error handling.
fun parseNumber(input: String?): Int = try {
input?.toInt() ?: throw IllegalArgumentException("Input is null")
} catch (e: NumberFormatException) {
println("Invalid number: $input")
-1
} catch (e: IllegalArgumentException) {
println("Error: ${e.message}")
-2
}
fun main() {
println(parseNumber("123")) // 📜 Output: 123
println(parseNumber("abc")) // 📜 Output: Invalid number: abc, -1
println(parseNumber(null)) // 📜 Output: Error: Input is null, -2
}
Resource Management with use
🧹⚙️
Auto-close resources with use
.
import java.io.BufferedReader
import java.io.StringReader
fun readFirstLine(fileName: String?): String? = try {
BufferedReader(StringReader(fileName ?: "")).use { reader ->
reader.readLine()
}
} catch (e: java.io.IOException) {
println("IO Error: ${e.message}")
null
}
fun main() {
println(readFirstLine("Hello, Kotlin!")) // 📜 Output: Hello, Kotlin!
println(readFirstLine(null)) // 📜 Output: null
}
ExceptionUtils Class 🐞📝
package com.boltuix.androidmasterypro
import android.os.RemoteException
import android.util.Log
import java.io.FileNotFoundException
import java.io.IOException
import java.io.PrintWriter
import java.io.StringWriter
/**
* Utility for logging exceptions with emojis.
*
* Usage:
* ```
* try {
* // Risky code
* } catch (e: Exception) {
* ExceptionUtils.handleException(e, "FeatureName: Description")
* }
* ```
*/
object ExceptionUtils {
private val exceptionTypeMap = mapOf(
ArithmeticException::class.java to Pair("ArithmeticException", "➗"),
ArrayIndexOutOfBoundsException::class.java to Pair("ArrayIndexOutOfBoundsException", "📏"),
ClassCastException::class.java to Pair("ClassCastException", "🔄"),
FileNotFoundException::class.java to Pair("FileNotFoundException", "📁"),
IOException::class.java to Pair("IOException", "💾"),
InterruptedException::class.java to Pair("InterruptedException", "⏸️"),
NullPointerException::class.java to Pair("NullPointerException", "🚫"),
SecurityException::class.java to Pair("SecurityException", "🔒"),
NumberFormatException::class.java to Pair("NumberFormatException", "🔢"),
IndexOutOfBoundsException::class.java to Pair("IndexOutOfBoundsException", "📉"),
RemoteException::class.java to Pair("RemoteException", "🌐"),
IllegalStateException::class.java to Pair("IllegalStateException", "⚠️"),
UnsupportedOperationException::class.java to Pair("UnsupportedOperationException", "🚫"),
RuntimeException::class.java to Pair("RuntimeException", "💥"),
NoSuchElementException::class.java to Pair("NoSuchElementException", "🔍"),
ConcurrentModificationException::class.java to Pair("ConcurrentModificationException", "🔄")
)
/**
* Retrieves supported exception types with names and emojis.
*
* @return List of triples (class, name, emoji).
*/
fun getSupportedExceptions(): List<Triple<Class<out Exception>, String, String>> {
return exceptionTypeMap.map { (clazz, pair) ->
Triple(clazz, pair.first, pair.second)
}
}
/**
* Logs a message to the console (in debug mode).
*
* @param message The message to log.
* @param level Log level (default: ERROR).
*/
private fun logMessage(message: String, level: String = "ERROR") {
if (!isDebugMode()) return
val tag = "error01"
when (level) {
"ERROR" -> Log.e(tag, message)
"DEBUG" -> Log.d(tag, message)
"WARN" -> Log.w(tag, message)
}
}
/**
* Handles an exception and logs it with an emoji (in debug mode).
*
* @param e The exception to handle.
* @param customMessage A descriptive message for the feature or context.
*/
fun handleException(e: Exception, customMessage: String) {
if (!isDebugMode()) return
try {
val (errorMessage, emoji) = exceptionTypeMap[e::class.java] ?: Pair("GenericException", "❓")
val stackElement = e.stackTrace.firstOrNull { it.className.contains("com.boltuix.androidmasterypro") }
val methodName = stackElement?.methodName ?: "Unknown"
val lineNumber = stackElement?.lineNumber?.toString() ?: "Unknown"
val fileName = stackElement?.fileName ?: "Unknown"
val stackTrace = if (e.message == null) {
StringWriter().also { sw ->
PrintWriter(sw).use { pw -> e.printStackTrace(pw) }
}.toString()
} else {
""
}
val logMessage = StringBuilder().apply {
appendLine("🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞 🐞")
appendLine("🐞 Feature : $customMessage")
appendLine("🐞 Exception : $emoji $errorMessage")
appendLine("🐞 Message : ${e.message ?: "No message"}")
appendLine("🐞 Method : $methodName")
appendLine("🐞 Line no : $lineNumber")
appendLine("🐞 File name : ($fileName:$lineNumber)")
if (stackTrace.isNotEmpty()) appendLine("🐞 Stack trace : $stackTrace")
appendLine()
}.toString()
logMessage(logMessage)
} catch (e: Exception) {
logMessage("Error handling exception: ${e.message} | Context: $customMessage")
}
}
/**
* Checks if the application is in debug mode.
*
* @return True if debug mode is enabled, false otherwise.
*/
private fun isDebugMode(): Boolean = BuildConfig.DEBUG
}
ExceptionUtils Usage Demo 🛠️
try {
val arr = IntArray(5)
val value = arr[10] // 📏 ArrayIndexOutOfBoundsException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test1: Array Index Out of Bounds Exception")
}
try {
val a: Any = "Hello"
val num = a as Int // 🔄 ClassCastException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test2: Class Cast Exception")
}
try {
val file = java.io.File("non_existent_file.txt")
val reader = java.io.FileReader(file) // 📁 FileNotFoundException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test3: File Not Found Exception")
}
try {
val inputStream = java.io.FileInputStream("non_existent_file.txt")
val data = inputStream.read() // 💾 IOException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test4: I/O Exception")
}
try {
Thread.sleep(1000)
throw InterruptedException("Thread interrupted") // ⏸️ InterruptedException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test5: Interrupted Exception")
}
try {
val str: String? = null
val length = str!!.length // 🚫 NullPointerException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test6: Null Pointer Exception")
}
try {
System.setSecurityManager(SecurityManager()) // 🔒 SecurityException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test7: Security Exception")
}
try {
val str = "abc"
val num = str.toInt() // 🔢 NumberFormatException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test8: Number Format Exception")
}
try {
throw RemoteException() // 🌐 RemoteException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test9: Remote Exception")
}
try {
throw IllegalStateException("Illegal state") // ⚠️ IllegalStateException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test10: Illegal State Exception")
}
try {
val num = 10 / 0 // ➗ ArithmeticException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test11: Arithmetic Exception")
}
try {
val list = listOf(1, 2, 3)
list[10] // 📉 IndexOutOfBoundsException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test12: Index Out of Bounds Exception")
}
try {
throw UnsupportedOperationException("Operation not supported") // 🚫 UnsupportedOperationException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test13: Unsupported Operation Exception")
}
try {
throw RuntimeException("Runtime error") // 💥 RuntimeException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test14: Runtime Exception")
}
try {
val iterator = listOf<Int>().iterator()
iterator.next() // 🔍 NoSuchElementException
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test15: No Such Element Exception")
}
try {
val list = mutableListOf(1, 2, 3)
for (item in list) {
list.remove(item) // 🔄 ConcurrentModificationException
}
} catch (e: Exception) {
ExceptionUtils.handleException(e, "Test16: Concurrent Modification Exception")
}
Last Updated: June 27, 2025
Comments
Post a Comment