🎯 Exemplos recomendados
Balanced sample collections from various categories for you to explore
Exemplos de Tratamento de Erros Android Kotlin
Exemplos de tratamento de erros Android Kotlin incluindo captura de exceções, registro e validação de parâmetros
💻 Registro de Logs kotlin
🟢 simple
⭐⭐⭐
Escrever logs em arquivos e console com vários níveis e formatos
⏱️ 20 min
🏷️ kotlin, android, logging
Prerequisites:
Basic Kotlin, Android SDK
// Android Kotlin Logging Examples
// Using android.util.Log and file-based logging
import android.util.Log
import android.content.Context
import java.io.File
import java.io.FileWriter
import java.io.PrintWriter
import java.io.StringWriter
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
// 1. Basic Android Logging
class BasicLogger {
companion object {
private const val TAG = "BasicLogger"
}
// Debug log
fun logDebug(message: String) {
Log.d(TAG, message)
}
// Info log
fun logInfo(message: String) {
Log.i(TAG, message)
}
// Warning log
fun logWarning(message: String) {
Log.w(TAG, message)
}
// Error log
fun logError(message: String) {
Log.e(TAG, message)
}
// Error log with exception
fun logError(message: String, throwable: Throwable) {
Log.e(TAG, message, throwable)
}
// Verbose log
fun logVerbose(message: String) {
Log.v(TAG, message)
}
// What a terrible failure log
fun logWtf(message: String) {
Log.wtf(TAG, message)
}
}
// 2. File-based Logging
class FileLogger(private val context: Context) {
private val logFile = File(context.filesDir, "app.log")
// Write log to file
fun writeLog(level: String, tag: String, message: String) {
try {
val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
.format(Date())
val logEntry = "[$timestamp] [$level] [$tag] $message\n"
FileWriter(logFile, true).use { writer ->
writer.write(logEntry)
}
} catch (e: Exception) {
Log.e("FileLogger", "Failed to write log", e)
}
}
// Debug log to file
fun d(tag: String, message: String) {
writeLog("DEBUG", tag, message)
Log.d(tag, message)
}
// Info log to file
fun i(tag: String, message: String) {
writeLog("INFO", tag, message)
Log.i(tag, message)
}
// Warning log to file
fun w(tag: String, message: String) {
writeLog("WARN", tag, message)
Log.w(tag, message)
}
// Error log to file
fun e(tag: String, message: String) {
writeLog("ERROR", tag, message)
Log.e(tag, message)
}
// Error log with throwable
fun e(tag: String, message: String, throwable: Throwable) {
writeLog("ERROR", tag, "$message: ${throwable.message}")
Log.e(tag, message, throwable)
}
// Read log file
fun readLogs(): String {
return try {
if (logFile.exists()) {
logFile.readText()
} else {
"No log file found"
}
} catch (e: Exception) {
"Error reading logs: ${e.message}"
}
}
// Clear log file
fun clearLogs() {
try {
if (logFile.exists()) {
logFile.delete()
Log.i("FileLogger", "Log file cleared")
}
} catch (e: Exception) {
Log.e("FileLogger", "Failed to clear logs", e)
}
}
// Get log file size
fun getLogFileSize(): Long {
return if (logFile.exists()) {
logFile.length()
} else {
0L
}
}
}
// 3. Structured Logging
class StructuredLogger(private val context: Context) {
private val fileLogger = FileLogger(context)
private val tag = "StructuredLogger"
// Log structured data
fun logInfo(level: String, message: String, metadata: Map<String, Any?>) {
val metadataString = metadata.map { (key, value) ->
"$key=$value"
}.joinToString(", ")
val fullMessage = "$message [$metadataString]"
when (level.uppercase()) {
"DEBUG" -> fileLogger.d(tag, fullMessage)
"INFO" -> fileLogger.i(tag, fullMessage)
"WARN" -> fileLogger.w(tag, fullMessage)
"ERROR" -> fileLogger.e(tag, fullMessage)
}
}
// Log user action
fun logUserAction(action: String, userId: String?, details: Map<String, Any?>) {
logInfo("INFO", "User action: $action", mapOf(
"userId" to userId,
"timestamp" to System.currentTimeMillis(),
"details" to details.toString()
))
}
// Log API call
fun logApiCall(endpoint: String, method: String, statusCode: Int?, responseTime: Long) {
logInfo("INFO", "API call", mapOf(
"endpoint" to endpoint,
"method" to method,
"statusCode" to statusCode,
"responseTime" to responseTime
))
}
// Log error with context
fun logError(error: Throwable, context: Map<String, Any?>) {
val sw = StringWriter()
error.printStackTrace(PrintWriter(sw))
fileLogger.e(tag, "Error: ${error.message}\nContext: $context\nStack: ${sw.toString()}")
}
}
// 4. Logger with Levels
class LevelLogger(private val context: Context) {
enum class LogLevel { VERBOSE, DEBUG, INFO, WARN, ERROR }
private var currentLevel = LogLevel.INFO
fun setLevel(level: LogLevel) {
currentLevel = level
}
// Log at specified level
fun log(level: LogLevel, tag: String, message: String) {
if (level.ordinal >= currentLevel.ordinal) {
when (level) {
LogLevel.VERBOSE -> Log.v(tag, message)
LogLevel.DEBUG -> Log.d(tag, message)
LogLevel.INFO -> Log.i(tag, message)
LogLevel.WARN -> Log.w(tag, message)
LogLevel.ERROR -> Log.e(tag, message)
}
}
}
// Convenience methods
fun v(tag: String, message: String) = log(LogLevel.VERBOSE, tag, message)
fun d(tag: String, message: String) = log(LogLevel.DEBUG, tag, message)
fun i(tag: String, message: String) = log(LogLevel.INFO, tag, message)
fun w(tag: String, message: String) = log(LogLevel.WARN, tag, message)
fun e(tag: String, message: String) = log(LogLevel.ERROR, tag, message)
}
// 5. Crash Reporting Logger
class CrashReportingLogger(private val context: Context) {
private val crashFile = File(context.filesDir, "crash.log")
// Capture uncaught exception
fun captureException(thread: Thread, throwable: Throwable) {
try {
val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
.format(Date())
val report = StringBuilder()
report.appendLine("=== CRASH REPORT ===")
report.appendLine("Timestamp: $timestamp")
report.appendLine("Thread: ${thread.name}")
report.appendLine("Exception: ${throwable.javaClass.simpleName}")
report.appendLine("Message: ${throwable.message}")
report.appendLine("\nStack Trace:")
report.appendLine(getStackTrace(throwable))
// Log to file
FileWriter(crashFile, true).use { writer ->
writer.write(report.toString())
writer.write("\n\n")
}
Log.e("CrashReporter", "Crash captured", throwable)
} catch (e: Exception) {
Log.e("CrashReporter", "Failed to capture crash", e)
}
}
// Get stack trace as string
private fun getStackTrace(throwable: Throwable): String {
val sw = StringWriter()
val pw = PrintWriter(sw)
throwable.printStackTrace(pw)
return sw.toString()
}
// Read crash reports
fun readCrashReports(): String {
return try {
if (crashFile.exists()) {
crashFile.readText()
} else {
"No crash reports found"
}
} catch (e: Exception) {
"Error reading crash reports: ${e.message}"
}
}
// Clear crash reports
fun clearCrashReports() {
try {
if (crashFile.exists()) {
crashFile.delete()
}
} catch (e: Exception) {
Log.e("CrashReporter", "Failed to clear crash reports", e)
}
}
}
// 6. Performance Logging
class PerformanceLogger(private val context: Context) {
private val fileLogger = FileLogger(context)
private val tag = "PerformanceLogger"
// Measure execution time
fun <T> measureTime(tag: String, operation: String, block: () -> T): T {
val startTime = System.nanoTime()
return try {
val result = block()
val endTime = System.nanoTime()
val durationMs = (endTime - startTime) / 1_000_000.0
fileLogger.i(tag, "$operation completed in ${String.format("%.2f", durationMs)}ms")
result
} catch (e: Exception) {
val endTime = System.nanoTime()
val durationMs = (endTime - startTime) / 1_000_000.0
fileLogger.e(tag, "$operation failed after ${String.format("%.2f", durationMs)}ms: ${e.message}")
throw e
}
}
// Log memory usage
fun logMemoryUsage(tag: String, context: String) {
val runtime = Runtime.getRuntime()
val usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024
val maxMemory = runtime.maxMemory() / 1024 / 1024
val totalMemory = runtime.totalMemory() / 1024 / 1024
fileLogger.i(tag, "Memory [$context]: Used=${usedMemory}MB, Total=${totalMemory}MB, Max=${maxMemory}MB")
}
// Start a timer
fun startTimer(operation: String): Timer {
return Timer(operation)
}
// Timer class
inner class Timer(private val operation: String) {
private val startTime = System.nanoTime()
fun end() {
val endTime = System.nanoTime()
val durationMs = (endTime - startTime) / 1_000_000.0
fileLogger.i(tag, "$operation took ${String.format("%.2f", durationMs)}ms")
}
}
}
// 7. Remote Logging (Simplified)
class RemoteLogger(private val context: Context) {
private val fileLogger = FileLogger(context)
// Queue logs for remote upload
private val logQueue = mutableListOf<String>()
// Add log to queue
fun queueLog(level: String, tag: String, message: String) {
val logEntry = mapOf(
"timestamp" to System.currentTimeMillis(),
"level" to level,
"tag" to tag,
"message" to message
)
synchronized(logQueue) {
logQueue.add(logEntry.toString())
}
// Keep queue size manageable
if (logQueue.size > 1000) {
logQueue.removeAt(0)
}
}
// Upload logs (simulated)
fun uploadLogs(): Boolean {
return try {
synchronized(logQueue) {
if (logQueue.isNotEmpty()) {
println("Uploading ${logQueue.size} log entries...")
// In real app, send to remote server
logQueue.clear()
true
} else {
false
}
}
} catch (e: Exception) {
fileLogger.e("RemoteLogger", "Upload failed: ${e.message}")
false
}
}
// Get queue size
fun getQueueSize(): Int {
return synchronized(logQueue) {
logQueue.size
}
}
}
// Main demonstration
fun demonstrateLogging(context: Context) {
println("=== Android Kotlin Logging Examples ===\n")
// 1. Basic logging
println("--- 1. Basic Android Logging ---")
val basicLogger = BasicLogger()
basicLogger.logVerbose("Verbose message")
basicLogger.logDebug("Debug message")
basicLogger.logInfo("Info message")
basicLogger.logWarning("Warning message")
basicLogger.logError("Error message")
try {
throw RuntimeException("Test exception")
} catch (e: Exception) {
basicLogger.logError("Caught exception", e)
}
// 2. File logging
println("\n--- 2. File Logging ---")
val fileLogger = FileLogger(context)
fileLogger.d("FileLog", "Debug log to file")
fileLogger.i("FileLog", "Info log to file")
fileLogger.w("FileLog", "Warning log to file")
fileLogger.e("FileLog", "Error log to file")
println("Log file size: ${fileLogger.getLogFileSize()} bytes")
// 3. Structured logging
println("\n--- 3. Structured Logging ---")
val structuredLogger = StructuredLogger(context)
structuredLogger.logUserAction("login", "user123", mapOf(
"ip" to "192.168.1.1",
"userAgent" to "Mozilla/5.0"
))
structuredLogger.logApiCall("/api/users", "GET", 200, 125)
try {
throw RuntimeException("API error")
} catch (e: Exception) {
structuredLogger.logError(e, mapOf("endpoint" to "/api/users"))
}
// 4. Level logging
println("\n--- 4. Level Logging ---")
val levelLogger = LevelLogger(context)
levelLogger.setLevel(LevelLogger.LogLevel.WARN)
levelLogger.v("LevelLog", "This won't be logged")
levelLogger.d("LevelLog", "This won't be logged")
levelLogger.i("LevelLog", "This won't be logged")
levelLogger.w("LevelLog", "This will be logged")
levelLogger.e("LevelLog", "This will be logged")
// 5. Performance logging
println("\n--- 5. Performance Logging ---")
val perfLogger = PerformanceLogger(context)
perfLogger.logMemoryUsage("PerfLog", "Before operation")
val result = perfLogger.measureTime("PerfLog", "Test operation") {
Thread.sleep(100)
"Operation result"
}
println("Result: $result")
perfLogger.logMemoryUsage("PerfLog", "After operation")
// Using timer
val timer = perfLogger.startTimer("Manual timer")
Thread.sleep(50)
timer.end()
// 6. Remote logging
println("\n--- 6. Remote Logging ---")
val remoteLogger = RemoteLogger(context)
remoteLogger.queueLog("INFO", "RemoteLog", "Log entry 1")
remoteLogger.queueLog("ERROR", "RemoteLog", "Log entry 2")
remoteLogger.queueLog("WARN", "RemoteLog", "Log entry 3")
println("Queue size: ${remoteLogger.getQueueSize()}")
remoteLogger.uploadLogs()
println("Queue size after upload: ${remoteLogger.getQueueSize()}")
println("\n=== All Logging Examples Completed ===")
}
💻 Validação de Parâmetros kotlin
🟢 simple
⭐⭐
Validar parâmetros de função usando require, check e validadores personalizados
⏱️ 15 min
🏷️ kotlin, android, validation
Prerequisites:
Basic Kotlin
// Android Kotlin Parameter Validation Examples
// Using Kotlin's built-in validation features
// 1. Basic Validation with require()
class BasicValidation {
// Validate positive number
fun calculateDiscount(price: Double, discount: Double): Double {
require(price > 0) { "Price must be positive, was: $price" }
require(discount in 0.0..100.0) { "Discount must be between 0 and 100, was: $discount" }
return price * (1 - discount / 100)
}
// Validate string parameters
fun createUsername(firstName: String, lastName: String): String {
require(firstName.isNotBlank()) { "First name cannot be blank" }
require(lastName.isNotBlank()) { "Last name cannot be blank" }
return "${firstName.lowercase()}_${lastName.lowercase()}"
}
// Validate collection
fun getFirstElement(list: List<String>): String {
require(list.isNotEmpty()) { "List cannot be empty" }
return list.first()
}
// Validate range
fun setVolume(volume: Int): Int {
require(volume in 0..100) { "Volume must be between 0 and 100, was: $volume" }
return volume
}
// Validate with multiple conditions
fun processUser(name: String, age: Int, email: String): Boolean {
require(name.isNotBlank()) { "Name cannot be blank" }
require(age in 18..120) { "Age must be between 18 and 120, was: $age" }
require(email.contains("@")) { "Email must contain '@'" }
println("User validated: $name, $age, $email")
return true
}
}
// 2. State Validation with check()
class StateValidation {
private var initialized = false
private var connected = false
// Initialize before use
fun initialize() {
initialized = true
println("Initialized")
}
// Connect to server
fun connect() {
check(initialized) { "Must initialize before connecting" }
connected = true
println("Connected")
}
// Send data
fun sendData(data: String) {
check(connected) { "Must be connected to send data" }
println("Data sent: $data")
}
// Check state before operation
fun performOperation() {
check(initialized) { "Not initialized" }
check(connected) { "Not connected" }
println("Operation performed")
}
}
// 3. Custom Validation Functions
class CustomValidators {
// Validate email format
fun isValidEmail(email: String): Boolean {
val emailRegex = Regex("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")
return emailRegex.matches(email)
}
// Validate and return or throw
fun validateEmail(email: String): String {
require(isValidEmail(email)) { "Invalid email format: $email" }
return email
}
// Validate phone number
fun isValidPhoneNumber(phone: String): Boolean {
val phoneRegex = Regex("^\\+?[1-9]\\d{1,14}$")
return phoneRegex.matches(phone)
}
// Validate URL
fun isValidUrl(url: String): Boolean {
try {
java.net.URL(url).toURI()
return true
} catch (e: Exception) {
return false
}
}
// Validate password strength
enum class PasswordStrength { WEAK, MEDIUM, STRONG }
fun checkPasswordStrength(password: String): PasswordStrength {
if (password.length < 8) {
return PasswordStrength.WEAK
}
val hasUpperCase = password.any { it.isUpperCase() }
val hasLowerCase = password.any { it.isLowerCase() }
val hasDigit = password.any { it.isDigit() }
val hasSpecial = password.any { !it.isLetterOrDigit() }
return when {
hasUpperCase && hasLowerCase && hasDigit && hasSpecial -> PasswordStrength.STRONG
hasUpperCase && hasLowerCase && hasDigit -> PasswordStrength.MEDIUM
else -> PasswordStrength.WEAK
}
}
// Validate password with minimum strength
fun validatePassword(password: String, minStrength: PasswordStrength = PasswordStrength.MEDIUM): String {
val strength = checkPasswordStrength(password)
require(strength.ordinal >= minStrength.ordinal) {
"Password strength must be at least $minStrength, was: $strength"
}
return password
}
// Validate date range
fun isValidDateRange(start: java.util.Date, end: java.util.Date): Boolean {
return start.before(end) || start.equals(end)
}
// Validate and sanitize string
fun sanitizeAndValidate(input: String, maxLength: Int = 100): String {
val sanitized = input.trim()
require(sanitized.isNotEmpty()) { "Input cannot be empty" }
require(sanitized.length <= maxLength) { "Input exceeds maximum length of $maxLength" }
return sanitized
}
}
// 4. Validation with Error Collection
class ValidationCollector {
// Collect multiple validation errors
fun validateUser(data: Map<String, Any?>): ValidationResult {
val errors = mutableListOf<String>()
val name = data["name"] as? String
if (name.isNullOrBlank()) {
errors.add("Name is required")
}
val age = data["age"] as? Int
if (age == null) {
errors.add("Age is required")
} else if (age !in 18..120) {
errors.add("Age must be between 18 and 120")
}
val email = data["email"] as? String
if (email.isNullOrBlank()) {
errors.add("Email is required")
} else if (!email.contains("@")) {
errors.add("Email must contain '@'")
}
return ValidationResult(
isValid = errors.isEmpty(),
errors = errors
)
}
// Validation result data class
data class ValidationResult(
val isValid: Boolean,
val errors: List<String>
) {
fun getErrorString(): String {
return errors.joinToString("; ")
}
}
// Validate with early return
fun validateUserEarlyReturn(data: Map<String, Any?>): ValidationResult {
val name = data["name"] as? String
if (name.isNullOrBlank()) {
return ValidationResult(false, listOf("Name is required"))
}
val age = data["age"] as? Int
if (age == null || age !in 18..120) {
return ValidationResult(false, listOf("Age must be between 18 and 120"))
}
return ValidationResult(true, emptyList())
}
}
// 5. Business Logic Validation
class BusinessValidators {
// Validate payment amount
fun validatePaymentAmount(amount: Double, balance: Double): Boolean {
require(amount > 0) { "Payment amount must be positive" }
require(amount <= balance) { "Insufficient funds: balance=$balance, amount=$amount" }
return true
}
// Validate inventory
fun validateInventory(itemId: String, quantity: Int, stock: Int): Boolean {
require(quantity > 0) { "Quantity must be positive" }
require(quantity <= stock) { "Insufficient stock: available=$stock, requested=$quantity" }
return true
}
// Validate order
fun validateOrder(items: Map<String, Int>, stock: Map<String, Int>): Boolean {
require(items.isNotEmpty()) { "Order cannot be empty" }
for ((itemId, quantity) in items) {
val availableStock = stock[itemId] ?: 0
require(quantity <= availableStock) {
"Item $itemId: insufficient stock (available=$availableStock, requested=$quantity)"
}
}
return true
}
// Validate shipping address
data class Address(
val street: String,
val city: String,
val state: String,
val zipCode: String,
val country: String
)
fun validateAddress(address: Address): Boolean {
require(address.street.isNotBlank()) { "Street cannot be blank" }
require(address.city.isNotBlank()) { "City cannot be blank" }
require(address.state.isNotBlank()) { "State cannot be blank" }
require(address.zipCode.isNotBlank()) { "Zip code cannot be blank" }
require(address.country.isNotBlank()) { "Country cannot be blank" }
// Validate zip code format (US example)
val zipRegex = Regex("^\\d{5}(-\\d{4})?$")
require(zipRegex.matches(address.zipCode)) { "Invalid zip code format" }
return true
}
}
// 6. Validation Utils
class ValidationUtils {
// Generic range validator
fun <T : Comparable<T>> validateRange(
value: T,
min: T,
max: T,
paramName: String
): T {
require(value in min..max) {
"$paramName must be between $min and $max, was: $value"
}
return value
}
// Validate not null
fun <T> requireNotNull(value: T?, paramName: String): T {
return requireNotNull(value) { "$paramName cannot be null" }
}
// Validate not blank
fun requireNotBlank(value: String?, paramName: String): String {
require(!value.isNullOrBlank()) { "$paramName cannot be blank" }
return value
}
// Validate positive
fun requirePositive(value: Int, paramName: String): Int {
require(value > 0) { "$paramName must be positive, was: $value" }
return value
}
fun requirePositive(value: Double, paramName: String): Double {
require(value > 0) { "$paramName must be positive, was: $value" }
return value
}
// Validate non-negative
fun requireNonNegative(value: Int, paramName: String): Int {
require(value >= 0) { "$paramName must be non-negative, was: $value" }
return value
}
// Validate size
fun <T> validateSize(
collection: Collection<T>,
minSize: Int,
maxSize: Int,
paramName: String
): Collection<T> {
require(collection.size in minSize..maxSize) {
"$paramName size must be between $minSize and $maxSize, was: ${collection.size}"
}
return collection
}
}
// Main demonstration
fun demonstrateParameterValidation() {
println("=== Android Kotlin Parameter Validation Examples ===\n")
// 1. Basic validation
println("--- 1. Basic Validation with require() ---")
val basicValidation = BasicValidation()
val discount = basicValidation.calculateDiscount(100.0, 15.0)
println("Discounted price: $$discount")
val username = basicValidation.createUsername("John", "Doe")
println("Username: $username")
try {
basicValidation.setVolume(150)
} catch (e: IllegalArgumentException) {
println("Validation error: ${e.message}")
}
// 2. State validation
println("\n--- 2. State Validation with check() ---")
val stateValidation = StateValidation()
stateValidation.initialize()
stateValidation.connect()
stateValidation.sendData("Hello")
try {
val stateValidation2 = StateValidation()
stateValidation2.sendData("Test")
} catch (e: IllegalStateException) {
println("State error: ${e.message}")
}
// 3. Custom validators
println("\n--- 3. Custom Validators ---")
val customValidators = CustomValidators()
val email = "[email protected]"
println("Is valid email: ${customValidators.isValidEmail(email)}")
val phone = "+1234567890"
println("Is valid phone: ${customValidators.isValidPhoneNumber(phone)}")
val url = "https://example.com"
println("Is valid URL: ${customValidators.isValidUrl(url)}")
val passwordStrength = customValidators.checkPasswordStrength("Pass123!")
println("Password strength: $passwordStrength")
// 4. Validation collector
println("\n--- 4. Validation Collector ---")
val collector = ValidationCollector()
val userData = mapOf(
"name" to "John Doe",
"age" to 25,
"email" to "[email protected]"
)
val result = collector.validateUser(userData)
println("Validation result: ${result.isValid}")
if (!result.isValid) {
println("Errors: ${result.getErrorString()}")
}
// 5. Business validation
println("\n--- 5. Business Logic Validation ---")
val businessValidators = BusinessValidators()
val paymentValid = businessValidators.validatePaymentAmount(50.0, 100.0)
println("Payment valid: $paymentValid")
val address = BusinessValidators.Address(
street = "123 Main St",
city = "New York",
state = "NY",
zipCode = "10001",
country = "USA"
)
val addressValid = businessValidators.validateAddress(address)
println("Address valid: $addressValid")
// 6. Validation utils
println("\n--- 6. Validation Utils ---")
val utils = ValidationUtils()
val validRange = utils.validateRange(50, 0, 100, "value")
println("Validated range: $validRange")
val notNull = utils.requireNotNull("value", "param")
println("Not null: $notNull")
val positive = utils.requirePositive(10, "count")
println("Positive: $positive")
val list = listOf(1, 2, 3)
val validList = utils.validateSize(list, 1, 5, "items")
println("Validated list size: ${validList.size}")
println("\n=== All Parameter Validation Examples Completed ===")
}
💻 Captura de Exceções kotlin
🟡 intermediate
⭐⭐⭐
Tratar exceções usando blocos try-catch, exceções personalizadas e estratégias de recuperação de erros
⏱️ 25 min
🏷️ kotlin, android, error handling
Prerequisites:
Intermediate Kotlin
// Android Kotlin Exception Catching Examples
// Using Kotlin exception handling mechanisms
// 1. Basic Exception Handling
class BasicExceptionHandling {
// Simple try-catch
fun divideNumbers(a: Int, b: Int): Double? {
return try {
(a.toDouble() / b.toDouble()).also {
println("Result: $it")
}
} catch (e: ArithmeticException) {
println("Division by zero: ${e.message}")
null
} catch (e: Exception) {
println("Unexpected error: ${e.message}")
null
}
}
// Try-catch-finally
fun processFile(filePath: String): String? {
var content: String? = null
try {
val file = java.io.File(filePath)
content = file.readText()
println("File read successfully")
} catch (e: java.io.FileNotFoundException) {
println("File not found: ${e.message}")
} catch (e: java.io.IOException) {
println("IO error: ${e.message}")
} catch (e: Exception) {
println("Unexpected error: ${e.message}")
} finally {
println("File processing attempt completed")
}
return content
}
// Try-catch with resource cleanup
fun processFileWithCleanup(filePath: String): String? {
val file = java.io.File(filePath)
return try {
if (file.exists()) {
file.readText().also {
println("Content length: ${it.length}")
}
} else {
println("File does not exist")
null
}
} catch (e: Exception) {
println("Error processing file: ${e.message}")
null
}
}
// Nested try-catch
fun nestedExceptionHandling() {
try {
println("Outer try block")
try {
println("Inner try block")
val result = 10 / 0
} catch (e: ArithmeticException) {
println("Inner catch: ${e.message}")
throw RuntimeException("Re-throwing from inner")
}
} catch (e: RuntimeException) {
println("Outer catch: ${e.message}")
}
}
}
// 2. Custom Exceptions
class CustomExceptions {
// Custom exception class
class ValidationException(message: String) : Exception(message)
class NetworkException(message: String, val statusCode: Int? = null) : Exception(message)
class DatabaseException(message: String, val errorCode: String) : Exception(message)
// Throw and catch custom exception
fun validateAge(age: Int) {
if (age < 0) {
throw ValidationException("Age cannot be negative: $age")
}
if (age > 150) {
throw ValidationException("Age exceeds maximum: $age")
}
println("Age $age is valid")
}
// Handle custom exception
fun processUserAge(age: Int): Boolean {
return try {
validateAge(age)
true
} catch (e: ValidationException) {
println("Validation failed: ${e.message}")
false
}
}
// Network operation with custom exception
fun fetchFromServer(endpoint: String): String? {
if (endpoint.isEmpty()) {
throw NetworkException("Endpoint cannot be empty", null)
}
// Simulate network call
return try {
// Simulated response
"Data from $endpoint"
} catch (e: Exception) {
throw NetworkException("Network error: ${e.message}", 500)
}
}
// Handle network exception
fun safeFetch(endpoint: String): String? {
return try {
fetchFromServer(endpoint)
} catch (e: NetworkException) {
println("Network error (status ${e.statusCode}): ${e.message}")
null
}
}
// Multiple custom exceptions
fun databaseOperation(operation: String): Boolean {
return try {
when (operation) {
"connect" -> true
"query" -> true
else -> throw DatabaseException("Unknown operation: $operation", "OP_UNKNOWN")
}
} catch (e: DatabaseException) {
println("DB error [${e.errorCode}]: ${e.message}")
false
}
}
}
// 3. Exception Chaining
class ExceptionChaining {
// Exception chaining with cause
fun loadDataFromFile(filePath: String): String {
return try {
val file = java.io.File(filePath)
file.readText()
} catch (e: java.io.IOException) {
throw RuntimeException("Failed to load data from file: $filePath", e)
}
}
// Catch and re-throw with additional context
fun processData(filePath: String): Int {
return try {
val data = loadDataFromFile(filePath)
data.length
} catch (e: RuntimeException) {
throw RuntimeException("Failed to process data from: $filePath", e)
}
}
// Handle chained exception
fun safeProcessData(filePath: String): Int? {
return try {
processData(filePath)
} catch (e: RuntimeException) {
println("Error: ${e.message}")
println("Cause: ${e.cause?.message}")
// Print stack trace of cause
e.cause?.printStackTrace()
null
}
}
// Add suppression
@Suppress("TooGenericExceptionCaught")
fun handleWithSuppression(): String? {
return try {
// Some operation
"Success"
} catch (e: Exception) {
println("Caught exception: ${e.message}")
null
}
}
}
// 4. Kotlin-specific Exception Handling
class KotlinExceptionHandling {
// Result type for error handling
fun divideSafely(a: Int, b: Int): Result<Double> {
return try {
Result.success(a.toDouble() / b.toDouble())
} catch (e: ArithmeticException) {
Result.failure(e)
}
}
// Use Result type
fun performDivision(): String? {
val result = divideSafely(10, 0)
return result.fold(
onSuccess = { value ->
println("Result: $value")
value.toString()
},
onFailure = { error ->
println("Error: ${error.message}")
null
}
)
}
// Nullable return type
fun parseToInt(value: String): Int? {
return try {
value.toInt()
} catch (e: NumberFormatException) {
println("Invalid number: $value")
null
}
}
// Elvis operator with exception
fun getNameOrThrow(map: Map<String, String?>): String {
return map["name"] ?: throw IllegalArgumentException("Name is required")
}
// Require for validation
fun processAmount(amount: Double) {
require(amount > 0) { "Amount must be positive, was: $amount" }
require(amount <= 1_000_000) { "Amount exceeds maximum" }
println("Amount processed: $$amount")
}
// Check for state validation
fun processPayment(balance: Double, amount: Double) {
check(balance >= amount) { "Insufficient funds: balance=$balance, required=$amount" }
println("Payment processed")
}
// RunCatching
fun safeOperation(): Int? {
val result = runCatching {
"10".toInt() * 2
}
return result.getOrNull()
}
// Multiple operations with runCatching
fun chainOperations(): String? {
val result = runCatching {
val num = "10".toInt()
val doubled = num * 2
"Result: $doubled"
}.onFailure { e ->
println("Operation failed: ${e.message}")
}
return result.getOrNull()
}
}
// 5. Advanced Error Recovery
class ErrorRecovery {
// Retry mechanism
fun <T> retryOperation(
operation: () -> T,
maxAttempts: Int = 3,
delayMs: Long = 1000
): T? {
var lastException: Exception? = null
repeat(maxAttempts) { attempt ->
try {
return operation()
} catch (e: Exception) {
lastException = e
println("Attempt ${attempt + 1} failed: ${e.message}")
if (attempt < maxAttempts - 1) {
Thread.sleep(delayMs)
}
}
}
println("All $maxAttempts attempts failed")
return null
}
// Fallback strategy
fun <T> tryWithFallback(
primary: () -> T,
fallback: () -> T
): T {
return try {
primary()
} catch (e: Exception) {
println("Primary failed, using fallback: ${e.message}")
fallback()
}
}
// Multiple fallbacks
fun <T> tryMultipleFallbacks(
operations: List<Pair<String, () -> T>>
): T? {
for ((name, operation) in operations) {
try {
val result = operation()
println("Success with: $name")
return result
} catch (e: Exception) {
println("Failed with $name: ${e.message}")
}
}
println("All operations failed")
return null
}
// Circuit breaker pattern (simplified)
class CircuitBreaker<T>(
private val operation: () -> T,
private val failureThreshold: Int = 3
) {
private var failureCount = 0
private var lastFailureTime: Long = 0
private var state = State.CLOSED
enum class State { CLOSED, OPEN, HALF_OPEN }
fun execute(): T? {
if (state == State.OPEN) {
val timeSinceFailure = System.currentTimeMillis() - lastFailureTime
if (timeSinceFailure > 60000) { // 1 minute cooldown
state = State.HALF_OPEN
println("Circuit breaker entering HALF_OPEN state")
} else {
println("Circuit breaker is OPEN, rejecting request")
return null
}
}
return try {
val result = operation()
if (state == State.HALF_OPEN) {
state = State.CLOSED
failureCount = 0
println("Circuit breaker reset to CLOSED")
}
result
} catch (e: Exception) {
failureCount++
lastFailureTime = System.currentTimeMillis()
if (failureCount >= failureThreshold) {
state = State.OPEN
println("Circuit breaker opened after $failureCount failures")
}
throw e
}
}
}
// Execute with circuit breaker
fun <T> executeWithCircuitBreaker(operation: () -> T): T? {
val circuitBreaker = CircuitBreaker(operation)
return try {
circuitBreaker.execute()
} catch (e: Exception) {
println("Circuit breaker operation failed: ${e.message}")
null
}
}
}
// 6. Exception Logging
class ExceptionLogger {
// Log exception with context
fun logException(context: String, exception: Exception) {
println("[$context] Exception: ${exception.javaClass.simpleName}")
println("[$context] Message: ${exception.message}")
println("[$context] Stack trace:")
exception.stackTrace.forEach { element ->
println("[$context] at $element")
}
}
// Log with custom severity
enum class Severity { ERROR, WARNING, INFO }
fun logWithSeverity(
severity: Severity,
message: String,
exception: Exception? = null
) {
val timestamp = java.util.Date()
println("[$timestamp] [$severity] $message")
exception?.let {
println("[$timestamp] [$severity] Caused by: ${it.message}")
}
}
// Collect exception details
fun captureExceptionDetails(exception: Exception): ExceptionDetails {
return ExceptionDetails(
type = exception.javaClass.simpleName,
message = exception.message,
cause = exception.cause?.message,
stackTrace = exception.stackTrace.joinToString("\n") { " at $it" }
)
}
// Exception details data class
data class ExceptionDetails(
val type: String,
val message: String?,
val cause: String?,
val stackTrace: String
)
}
// Main demonstration
fun demonstrateExceptionCatching() {
println("=== Android Kotlin Exception Catching Examples ===\n")
// 1. Basic exception handling
println("--- 1. Basic Exception Handling ---")
val basicHandler = BasicExceptionHandling()
basicHandler.divideNumbers(10, 2)
basicHandler.divideNumbers(10, 0)
basicHandler.processFile("nonexistent.txt")
// 2. Custom exceptions
println("\n--- 2. Custom Exceptions ---")
val customExceptions = CustomExceptions()
val ages = listOf(25, -5, 200, 30)
ages.forEach { age ->
val isValid = customExceptions.processUserAge(age)
println("Age $age valid: $isValid")
}
// 3. Exception chaining
println("\n--- 3. Exception Chaining ---")
val chaining = ExceptionChaining()
chaining.safeProcessData("nonexistent.txt")
// 4. Kotlin-specific handling
println("\n--- 4. Kotlin-Specific Handling ---")
val kotlinHandler = KotlinExceptionHandling()
kotlinHandler.performDivision()
kotlinHandler.parseToInt("123")
kotlinHandler.parseToInt("abc")
// 5. Error recovery
println("\n--- 5. Error Recovery ---")
val recovery = ErrorRecovery()
var attempts = 0
val result = recovery.retryOperation(
operation = {
attempts++
if (attempts < 3) {
throw RuntimeException("Simulated failure")
}
"Success after $attempts attempts"
},
maxAttempts = 5
)
println("Retry result: $result")
// 6. Fallback
val fallbackResult = recovery.tryWithFallback(
primary = { throw RuntimeException("Primary failed") },
fallback = { "Fallback value" }
)
println("Fallback result: $fallbackResult")
// 7. Exception logging
println("\n--- 6. Exception Logging ---")
val logger = ExceptionLogger()
try {
throw RuntimeException("Test exception")
} catch (e: Exception) {
logger.logException("TestContext", e)
}
logger.logWithSeverity(ExceptionLogger.Severity.ERROR, "Critical error occurred")
println("\n=== All Exception Catching Examples Completed ===")
}