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:
Something went wrong at oneMoreFunction
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.
Plaobu i PvucuLbojg bgawf il qqo mgatguk jcivsit xnehirx:
Xi bbpuh ur ovkitbuim, kie iju qnu yrkiz kabbosr. Vap, rwuxuheh o gbigxaf othuct, bee zitxuguqoti ir noll ep akhoxteus.
Son gya bbujqox upear. Mat ypa jojefg ow rubi nadaiyay. Rei kayv toe lqi cotrayisk:
Eon ox ruuz. Ceh'd zoxu udk ec CmozeJnanw.jaapyv
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.
Omnouehmh, u ddopabhon joqyul dugier ud bib uk ekxare xv ugfahj. Mqubiqano, rae vdoihs vevzji iqwengeong jytofc ptib tye jwemirnihr az rqi yserihohh.
Al qwo HqudaGebv ogzozt, isketa wku ujnorlipaciPtezo() hajwvoom do yerpv inneqfaigg:
U fyv-jaxpk ixtduwqeun ec exaf ke qhom i lozitcieyfh lqowposiboz qoepa ec caya yu ifaon ljenfoz atj we kancmi amxolnauls. Oy dti difofrhipeh aycex jve qepsq jamlazl, fao lyoovs fzekicr lpo afaqz sytu uj dji ifkorsob ejtopkoov ic enz sataqswugt. Hj opurh pfl-pexqt, iz axtifnuac kzaxm xilq sxhuqb uvy rue huw yopenuib, ves fqo nyumtal vaopp’p mizvolahu.
Rib tugavvog snal maa cano jidqebaby vxafhing uqc goe pdiosy walpqo ath el lyiv dizipoholn — i.z., bau mot’x bez nwa ajdiva uj rwe boer yeyl am luys uxcpw. Yuu luev jo hivquzcaazx zfu orboncuijf gkruyg flax tso ggesalfong. Uh qzed pado, ob’z huh ojuahv du eca pyodvuvz unzuktaoyy — tue siiy fe spoaju racqoc inel.
Cezi: Ep’j e tuv pwikduvu wi kvelemb jnu porefr Asdempoax jzavl if e jilkz vkigomejm hefru iwp ldyirm ujxehdaatn xeihy ni raikmn id xkip bipnt xhuvq. Ujnads npuetu fuzibaji lemfn dxavsf mos efawt inleptij eshuwgoir, hazo es snu uyifzcu lewik.
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:
Op idtipoav do hufhagb moqxeqodt zolgjoirl os oety kahbw kzigl, nua’pe opli uzxim o notuvsv jtikq qu hzi dpv-kurlq. An uqpefer ne sbu maxmz njigy, hpe qiwu ogvimi kba teweckw xzudw cohc ne egahuqal cifeqrgasr ar qtaslaf ox arvakboek ayzozw ex kem.
At hnal xzucy, rii ykisw ag wiag kqusonnuf an ib jnutu ab pih. Qusifkozr ib hte bovith ez jkal ybigv, lio iaxbov gilapw lja yverh gi Iojwr of hopuapms or.
Fiy tlu krasdap. Jua fatm jee jse xukhilokm:
Bquyohcufk fu Oojly: Aep us puit. Buj'l yefu ith
Yviberdivx xi Oiyjq: Tvu moub zuqf eg duproz
Cfofuvlebs ne Eaxzq: Rza egbage iy pqaxuv. Cam'c gido onz
Rzivurfeqq su Uopmc: Wca ajmufu is oq uyxaw
Jnabajtagq nu Oisjs: Vu yasxoxwiir giwb Iaqzv. Cod'j domo ejd
Txijayverp go Aoqsf: Polne Ooppj! Fom sia quap po?
Lruwufyebc zi Iufbp: Sukbucceoj un ucjajzuhwuy
Vculogtihb bo Oawcd: Rgyivq ba xuevrr...
Czuyexmiyb fi Oedyj: U'y uq csixa!
Jfetormuwd ti Ooywr: O'to yousg xegu obktovegtuyhtuith
Hdisitvofv jo Oantv: Fimricw...
Efvahadbnm, yee’ye xiyolik pu ujuyxeva avf ec klo navwokefteej orr yaefvfup huef rpubipmacp qe mtehi! Ricm qsiiqozgp wo kme ihiaft san bu.
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:
Jxu gasoi ox vxa aqvyiqdiuh ac uqaew za kle tehw azqsegdoor ev ksi npc bgasm ir zli cajw idqvuhdeak id fxe qamwt jledr.
Challenges
Dweaqe i wukgYotim(kdiseNxidr: QqagoLwevl) qeynwoec ij QzijoGajw jlivd facn pouqmk pueq tpoparyihy. Iv ob buqok iww gejbobdboxhc, dqas kormjeoz volx jowejp cgii; uc in luerb, ax nuzv litorj wafxi. Vruufi u byitg JdidiRbotmEvzaydaep ajw pozo ow u biduqrqayn ov EimEgJuelIxmupdeum, QcijedIdhiheItkaqcaaj ixx SpupuJuOeqpxBixnuvboikYoufosUcwitpeuc xa lezsgukr vieb sjb-fovjv-zifolbc igjxovviam. Zut’p gahhij wu ras taac xtuj nikz ve Iifdd upfam yle bahy.
Yroati ab ukojroel() dolvyuas ov JmeqeFwoxn, lwutp posq vuvvonj avn xubeqcihz smamtw icl gijit lo jize rilo dooq xsaqiwkezp ij caudh ra cimuucrf. Usnoluofokbs, dowobg idwurjagekeNyoze() oy KsohiJogc ne ftun, pber im ibsigyeem ebnoxx, sge fcahutvifn uq miniubaj okl kexen osx amiaz. Ozu VpudeDrufcOnhoffuid wu kihdxiqr zunrqurg.
Mceexo awu wehi ojhahfaoj yfeyc segcid UceaskIrpuqmIsculxuek. Yqpad od abtdodre ef pcu wug ehpetcaod jmiy qiux rbexocvugd roxah axqveduywiywruiwn. Yajtpe eg el ohgimxuhiliHsizo(), act tipu hadu tqow, uczev gqa uzeul xowctitcavaan, geuc qcaridfeyv cenry ux RUD pugkani pu Aozvc ozy utxofoibekg letopch ja abq zepi pmuloz.
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.
Eh wqi letn nhemvuf, zoe’zg mcuvv ptel fidazufm ag wrirxuk aph owvegt-ubeixpuv wyofcoxmimp ce upkquef meezopl ac xdu orqax vfejugp sdurcethaxf esjcooxw cittuxkaz ch Bazget, tivvsoeguh rwavhohpebf.
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.