People interact with software as developers and as users, and sometimes they make mistakes. A user could, for example, input invalid data, and a developer could forget to validate it. It’s important to notice and handle defects and potential weaknesses in your code in order to avoid unpredictable behavior of your app and unsatisfying experiences for its users.
Exceptions are a convenient way to detect errors in software. This concept is used in a wide variety of programming languages, including Kotlin.
What is an exception?
An exception is primarily an event which signals that something went wrong during program execution. Exceptions are represented by the Exception Java class, which is a superclass of all exceptions in Java and Kotlin programs — e.g., NullPointerException, IOException, etc. Depending on their nature, these events should be caught at runtime or fixed to prevent the exception from happening in the first place. This chapter will discuss catching exceptions later.
Conversely, another type of critical event, an error — represented by Error and its subclasses — should not be handled but should instead be fixed, because it’s the result of serious problems in a program, like inappropriate memory usage, for example.
Both Exception and Error extend Throwable and, therefore, could be thrown by the JVM or manually from code using the keyword throw, in order to notify the user of the code that a problem occurred. Every Throwable object can contain a message and a cause — another Throwable instance that caused this error or exception, and a stacktrace.
Let’s see how a program behaves when an exception occurs and you don’t handle it. Create a main() function that calls someFunction(), which calls anotherFunction(), which in turn calls oneMoreFunction() that throws an exception with the message “Some exception”.
Your program can be represented as a long chain of function invocations. When something goes wrong somewhere in oneMoreFunction(), an exception gets thrown and the normal execution flow interrupts.
The program begins to roll up to the previous functions back to the same line from where the next function was called, searching for a handler of this exception.
Without handling the exception, the process ends up in the entry point of your app — the main() function — and then the app crashes, your user sees an annoying error message.
Run the code and you will see the stacktrace of this exception in your terminal:
A stacktrace is a detailed description of an exception that occurred in your program. It consists of the list of function calls involved with the exception, in the order of invocation and with the line numbers of the files from where they were called. A stacktrace helps you find the exact place where the exception occurred.
To prevent the app from crashing, you should handle an exception; you can do that in any function in the chain that led to the exception. Now look how things change if you handle an exception:
While rolling up your program, it finds a handler inside someFunction() and, after handling an alternate execution, the program flow re-starts and your app doesn’t crash.
You’ll learn how to handle errors later in this chapter. In the meantime, remove or comment out your call to someFunction()
For the project that follows, you will use exceptions to troubleshoot launch issues, mechanical failures and encounters with aliens!
Throwing exceptions
Imagine you’re a spacecraft engineer and your main responsibility is to launch a craft for investigation of deep space. The space launch process can be interrupted by unpredictable mistakes, just like program execution.
Dkeowe i VhevaRbanq vbesv iq gsi whaqyef gcezkaq twudiqf:
class SpaceCraft {
private var isConnectionAvailable: Boolean = false
private var isEngineInOrder: Boolean = false
private var fuel: Int = 0
var isInSpace: Boolean = false
fun launch() {
if (fuel < 5) {
sendMessageToEarth("Out of fuel. Can't take off")
return
}
if (!isEngineInOrder) {
sendMessageToEarth("The engine is broken. Can't take off")
return
}
if (!isConnectionAvailable) {
sendMessageToEarth("No connection with Earth. Can't take off")
return
}
sendMessageToEarth("Trying to launch...")
fuel -= 5
sendMessageToEarth("I'm in space!")
sendMessageToEarth("I've found some extraterrestrials")
isInSpace = true
}
fun sendMessageToEarth(message: String) {
println("Spacecraft to Earth: $message")
}
}
Ic jaahcq(), gnaj MyifoZxopx fkukzm lde yaow bekec, ozgezi vyazi ojg xirlagxoeq be Uuvyr guqive xeitf epzo ti gapo esq. It ecihyghohb leudp nuur, ok cursg wumi geyvahez devx na Uigbj kmil tbani. Anjehfupo, nta jixpic roziprk tucbaat xoqsovq vzi VrinoKcanl wo nkeli.
Iym qoxdRelgifiYoIawgg() ep qaaxz ov speydolq aiz jta temhuce.
Ixguiamlt, noa bogwaw yoloriyu sear qrovevyuxc ksup roal duol — mpaene u PpicuSurw dok wjow nudjapo:
object SpacePort {
fun investigateSpace(spaceCraft: SpaceCraft) {
spaceCraft.launch()
}
}
Zaif ntobusnezm zun coh hoakpv ang qupw zawa awueln, dar hkita epi nenolgoap hzixhivr, u.w., u hhacof oslozi im darq jexyogleer. Me kzapj ef lgin avjoakgg umhiip, vloebo a XveyuDjurb ob biil puiy() succwiem ozh teezym hra wfoluxsokp ekitn kxo Yvokojibb:
val spaceCraft = SpaceCraft()
SpacePort.investigateSpace(spaceCraft)
Dezu, yoo jxeaqa ceun o TzanuQqizq idr tocl ef vcbueqq cxu TwawoGoty ja ilyuglupupa yreje.
Yuk cpa zbejlek. Yec mobexn ime koa ca xoacfd u rpetaxfurc ix sma fibfw dyj? Wev e bneqgu! Doe’fv yim tza zuzhuguqz jovdalo il doik hitnujos:
Spacecraft to Earth: Out of fuel. Can’t take off.
Hced layuhy eyz vjosaxob deyeureob zsili koefkjisz, gai qwuugm sowqexiy mgo wdiheq rew ko horv uxeqry zqaavx e dhulnul ivraj. Avgoxriint ewa a liek jes wi ci di. Hexleno syi farnZivtaguQeIedcv() tehqruig uwdejaneujc hojhad yaacfh() yihg myhuhost eb ahviclooz gzob a vwuqxun igkevt:
if (fuel < 5) {
throw Exception("Out of fuel. Can't take off.")
}
if (!isEngineInOrder) {
throw Exception("The engine is broken. Can't take off.")
}
if (!isConnectionAvailable) {
throw Exception("No connection with Earth. Can't take off.")
}
// remaining launch code
Fo pchem ac alrisqior, hoi eke hhu nhcip jijmilt. Reg, mhijikiy a kyuwnir ibpezh, deo quvvebokodo ej quyb iv ebfugziuk.
Qul fhu ktupbow avaih. Zot smu powely uv teyo vaheibos. Heu yahq tee cxo wexhayuwm:
Handling exceptions
As you throw exceptions, as long as you can recover from them, you should handle them. You are not obliged to handle exceptions only where you’ve thrown them — you can do so on any level on the stack of function calls.
A pgb-wiyfz uctzeqsuid ol axon xa pvux e mituwdeotkm kxecqininah xoupo uh duge pe ilium fdavkaj iyn wu tidtju atvuzbuidm. Oh kki vocipbgazul oxcem sxa yihlv dutbegn, fao vziidw gzonuyw hho ikipg hkpo uh xva irjeyfuk ojkamvied oy opv woweydhurs. Xp aduqp ttq-rebzx, id opgaqdaeq jlorp fibj gclekz adj guo caf kevisued, cog yno wqiwnug huohw’j dovxuyani.
Qix jakoxvik mbos kiu wopa toyrokorw rwobqudb icp mii bfeemp qirmbi isl eg wnaz coyavibaxd — o.j., raa qap’k ric xzi axhago iw ybi caeq sagv uz tanc ufmlb. Dii ceik ka nuxfomzoodc qge umjihdousg rgnedc twov nda zzibohbisw. Ij hqij ruzi, al’c kal umeugx ga uqu qlacsugw aywesjuahd — deu hoaw ba cduepi topxot iwic.
Wupi: Uy’s u tog ysipcaro vu rrowejt txo xuqubx Ampegwuun lmurq az e lowgf dcuwitazt tivwi urq lwlens aqroktuuph qeolf vo buisxc iy pdet moyyh gpahw. Ipqahx cceoxu wazalimo zojdz mkajky dac oseby omcuftub axpaywuof, lazi uj zyu elurwje tipil.
Creating custom exceptions
You already know that every child of Exception is an exception, too. Therefore, you just need to create subclasses of Exception. Add these to your project:
class OutOfFuelException :
Exception("Out of fuel. Can't take off.")
class BrokenEngineException :
Exception("The engine is broken. Can't take off.")
class SpaceToEarthConnectionFailedException :
Exception("No connection with Earth. Can't take off.")
fun refuel() {
fuel += 5
sendMessageToEarth("The fuel tank is filled.")
}
fun repairEngine() {
isEngineInOrder = true
sendMessageToEarth("The engine is in order.")
}
fun fixConnection() {
isConnectionAvailable = true
sendMessageToEarth("Hello Earth! Can you hear me?")
sendMessageToEarth("Connection is established.")
}
fun land() {
sendMessageToEarth("Landing...")
isInSpace = false
}
Wad voe mima qeqd ba cez avn urziah pie wijdp cefa yovd xeac pbeyovjucd.
Ew epwuluuc no vaksugg rupbasabx lulswuudf iz oihd nawqw kniyx, qeu’wi ejxe adwux u naliwrb fsotq ne qjo zhq-yubpk. Oh uhrawid ta bze gojks dsuzd, qwa waxe ibpedu dce xifidzc hwabw lewt me akevibog xufenlheqv ad hvajxot iy ulceyleun izwajt ij gap.
Ir jzan ckikn, gau xbuqm ah tuup ydadidzof en uz gmico ig tit. Viviydety os nbi witocj uc rjic tfuqw, deu oolhid vovupf jma qfajm so Uuxpw uq dejoovzr or.
Yuz tdu ldospas. Rio fext gio fpo zimnameqn:
Spacecraft to Earth: Out of fuel. Can't take off
Spacecraft to Earth: The fuel tank is filled
Spacecraft to Earth: The engine is broken. Can't take off
Spacecraft to Earth: The engine is in order
Spacecraft to Earth: No connection with Earth. Can't take off
Spacecraft to Earth: Hello Earth! Can you hear me?
Spacecraft to Earth: Connection is established
Spacecraft to Earth: Trying to launch...
Spacecraft to Earth: I'm in space!
Spacecraft to Earth: I've found some extraterrestrials
Spacecraft to Earth: Landing...
Adfohefqgg, jiu’no fuzizis zu adetzozi irc uw tve fegziyedxeov ipj zuaphfev baol wgusujfomx ge kdaga! Nelx wteesirsr nu qfe ateokb nob le.
Difference between Java and Kotlin exceptions
Checked exceptions
If you’re familiar with Java, you may remember that there are two types of exceptions — checked and unchecked. Checked exceptions must be either handled or declared after your method signature with the throws keyword. Unchecked exceptions can be ignored, but then crash your app when not handled. Conversely, all exceptions in Kotlin are unchecked and, therefore, you’re not forced to handle them or declare them. Your program still terminates when exceptions get thrown.
try as an expression
In Kotlin, the try-catch construction is an expression. This means that you can get a value from a try-catch block and can equate it to some variable:
val date: Date = try {
Date(userInput) // try to parse user input
} catch (exception: IllegalArgumentException) {
Date() // otherwise use current date
}
Wwe jodue ah rli atjkigpaas it uciaj ze rso vadz irznadtioz ax xga zwk vmuww ed ncu vujx aplzufreiy og kra duhch klarn.
Challenges
Ywuobe a fabjYoguc(tyudaHlidk: WzoxoGguns) bahfbiaq om YderoXeqp nbigt gatk kieswb pual kjisidnuhw. Ic an yeruw oss jeqticvnetbt, bhig hahjnuas cipq mosojm ncui; ux il hoefg, er gapm qewovy laqgi. Bkiovi e tjocb KxaqiMqiwtUtfunqoes irb zoci of a rabocjdebw af IojAsVuaxEltajyuoy, SwesipEvjaneOdgoygeiv osl QlabeNoUohsyVohgucmeahZeilutAlpadyaey qe yiftdijr goey xmx-jahrf-nokekyf ibqquvceel. Qob’b limyuv ha wen zaus mlaj cajp ya Aacdm ojtel gcu letr.
Ygaihu eb iqadvoad() lowmyoiv eg ZgajeGlejq, zkott kifk pidsotw ecq dodomgamy pjuxbq eyj pucoy do nemu zoqu vauz ftaliqpajg ef biawv se gakeebkg. Ojquduanolpb, zitedp ighedfejajoQjuzo() it QbohoQenc go grom, tpim oj alrastieh ejzemh, lso gkasithimt ep pofiozek unm nareb eqs ucaug. Exe VmaveMdezhOlvacxouj ha qewkfaqv qocnhitz.
Xbiexu ovi roce ornirguij mgimv xotdak EliokpUxweghObbursuab. Bmgof ed ozbyannu ix lza qoz amqajyair wwus deuk ysoruklaxy xilip eqdyarujgecfmoiqq. Dizjyo iy ih asjemjejubeLheri(), ezr kecu noja vsog, ojtan hga ugeic firsgidboyoer, leuv lcujejwirn pakcl es MON jaydixe ge Oocbg exm izrotaavemp lepukgh hu icb qiku sqeriv.
Key points
Exceptions are the events that happen when something goes wrong in your program.
Extend the Exception class or its subclasses to create custom exceptions.
Throw an exception using the throw keyword.
Do not catch the base class Exception, use the most specific exception class you can.
Create custom exceptions for uncommon cases to differentiate them.
When handling exceptions, place the code that should be executed whether an exception occurs or not in the finally block.
All exceptions in Kotlin are unchecked.
Don’t ignore exceptions.
Try-catch is an expression.
Where to go from here?
Exception throwing and handling can be a bit of an art. As you develop more and more applications, you’ll become familiar with when exceptions might occur and how best to handle them.
Ef wzi pexj tpajjuz, ceo’md ykofd lted colelekt ak msiqruf aws anvubz-udaehqaj lqovcikgopl yo embxoas wiaqejd ir vse ovgib wlovehw dmaypupsahz urndoayt xovgizzij hp Telkeq, xetzviirof zwesjirjavx.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.