Kotlin från grunden Undantagshantering

Kotlin är ett modernt programmeringsspråk som kompilerar till Java bytecode. Det är gratis och öppen källkod, och gör kodning för Android ännu roligare.  

I den föregående artikeln lärde du dig mer om objektorienterad programmering genom att gräva i abstrakta klasser, gränssnitt, arv och typ alias i Kotlin. 

I det här inlägget fortsätter du att lära dig om programmering i Kotlin genom att lära dig om undantag och hur du hanterar dem. 

1. Undantagshantering

Undantag används för att indikera ett problem i vår kod under ett programs körning. Undantagshantering är förmågan att ta itu med (eller hantera) det undantag som kan uppstå. Om vi ​​inte hanterar något undantag som uppstår, kommer vårt program att sluta att exekvera och kraschar vår app omedelbart. 

Undantagshantering gör det möjligt för vårt program att fortsätta exekveringen även om det fanns ett undantag (men det rekommenderas att du loggar in dina undantag och rapporterar dem med hjälp av ett kraschrapporteringsverktyg som Crashlytics).   

I Java har vi två typer av undantag: markerad och okontrollerad. Jag förklarar dem kortfattat, men vi börjar med obekanta undantag. 

Avmarkerade undantag

Det här är undantag som kastas på grund av brister i din kod. De är en direkt eller indirekt underklass av RuntimeException superklass. 

Exempel på okontrollerade undantag är:

  • ArithmeticException: kastas när du delar upp med noll.
  • ArrayIndexOutOfBoundExceptions: kastas när en array har nåts med ett olagligt index. 
  • SecurityException: kastas av säkerhetschefen för att ange en säkerhetsöverträdelse.
  • NullPointerException: kastas när man anropar en metod eller egenskap på ett nullobjekt.

En metod som kan kasta ett obefogat undantag innehåller ingen information om det undantag som gjorts på metoddeklarationen. 

public Integer divideByZero (Integer täljare, integer nämnare) retur täljare / nämnare;  divideByZero (7, 0) // kaster AritmeticException

Dessa typer av undantag kan förebyggas genom att koda rätt. I koden ovan borde vi ha kontrollerat om nämnaren var noll innan du utförde operationen. För dessa undantag behöver utvecklaren inte fånga undantaget med hjälp av försök fånga blockera. Med andra ord, vi är inte tvungna av kompilatorn att paketera koden som kan utlösa undantaget i a försök fånga blockera. Istället bör vi bara se till att undantagen aldrig uppstår i första hand.

Kom också ihåg, Kotlin är ett null säkert språk. Det kan med andra ord hjälpa oss att undvika att få NullPointerExceptions i vår kod. Du kan läsa Nullability, Loops och Conditions posten för att få en uppdatering på null säkerhet i Kotlin. 

Kontrollerade undantag i Java

En metod som kan kasta ett kontrollerat undantag måste deklareras i sin metod signatur med hjälp av kastar nyckelord. Om du ringer en metod som kastar ett kontrollerat undantag, måste du antingen kasta den igen från din funktion eller att fånga den och hantera den med hjälp av en försök fånga blockera. 

Kontrollerade undantag är undantag som kontrolleras vid sammanställningstiden. Sådana undantag ärva från Undantag klass. Ett exempel på denna typ av undantag är IOException. Det här kan inträffa när du försöker komma åt en fil som inte kan öppnas eftersom den inte existerar. (FileNotFoundException är en underklass av IOException.)

// utföra i en bakgrundstråd public void editFile (Filfil, Stringtext) försök file.getParentFile (). mkdirs (); FileOutputStream fileOutputStream = ny FileOutputStream (fil); Writer writer = new BufferedWriter (ny OutputStreamWriter (fileOutputStream)); försök writer.write (text); writer.flush (); fileOutputStream.getFD () synk ().;  äntligen writer.close ();  fånga (IOException e) // Logga in undantaget e.printStackTrace (); 

I den föregående koden använde vi en försök fånga blockera för att hantera IOException inuti editFile () metod. Vi kan nu ringa editFile () Metod som vanligt, och kompilatorn kommer inte att klaga. 

editFile (ny fil (""), "min text");

Titta på koden nedan har vi refactored metoden för att istället använda kastar sökord i metodens signatur. Detta indikerar att ringer som de behöver hantera undantaget IOException som kan kastas när man ringer metoden editFile ().

// detta borde vara i en bakgrundstråd public void editFile (filfil, strängtext) kasta IOException file.getParentFile (). mkdirs (); FileOutputStream fileOutputStream = ny FileOutputStream (fil); Writer writer = new BufferedWriter (ny OutputStreamWriter (fileOutputStream)); försök writer.write (text); writer.flush (); fileOutputStream.getFD () synk ().;  äntligen writer.close (); 

För att ringa metoden ovan måste vi omge den i en försök fånga blockera för att hantera undantaget.

försök editFile (ny fil (""), "min text");  fånga (IOException e) e.printStackTrace (); 

Detta har varit en kort titt på undantag i Java. Låt oss nu se hur Kotlin hanterar undantag. 

2. Undantag i Kotlin

Huvudskillnaden mellan mekanismerna Kotlin och Java är att alla undantag är okontrollerade i Kotlin. Med andra ord, de är inte uttryckligen deklarerade i funktions signaturerna, som de är i Java.

roligt editFile (fil: fil, text: String) file.parentFile.mkdirs () val fileOutputStream = FileOutputStream (fil) val writer = BufferedWriter (OutputStreamWriter (fileOutputStream)) försök writer.write (text) writer.flush () fileOutputStream .fd.sync () äntligen writer.close ()

Här har vi konverterat editFile () metod för en Kotlin-funktion. Du kan se att funktionen inte har kastar IOException uttalande i dess funktions signatur. kastar är inte ens ett nyckelord i Kotlin. 

Vi kan också ringa den här funktionen utan att omge den med försök fånga blockera och kompilatorn kommer inte att klaga. Det är med andra ord ingen sådan sak som kontrollerade undantag i Kotlin. Alla undantag är avmarkerade. (Observera att om ett undantag kastas, slutar programkörningen som vanligt.) 

Om vi ​​tror att detta undantag kan uppstå, bör vi fortfarande hantera det genom att omge metoden med a försök fånga block-men detta verkställs inte av Kotlin-kompilatorn. 

försök editFile (File (""), "text 123") fånga (e: IOException) e.printStackTrace ()

Om undantaget kastas inuti editFile () funktion är en förekomst av IOException klass, vår fånga blocket kommer att utföras, och vi skriver ut stapelspåret för debugging.

De försök fånga Blockera

De Prova konstruera med fånga och till sist klausulerna i Kotlin liknar den i Java. 

(exception) println ("Exception-hanterad") äntligen println ("inside finally block")

Här kastar vi en Undantag föremål inuti Prova blockera. Observera att vi inte inkluderade ny sökord som vi gör i Java för att skapa en ny instans. Observera också att vi inte angav det undantag som kommer att kastas i funktions signaturen som vi skulle behöva i Java. 

Vi hanterar alla underklasser och klasser av typ Undantag i fångstblocket. Den frivilliga till sist block exekveras alltid-det här är där vi stänger vanligtvis eventuella resurser eller anslutningar som tidigare öppnades för att förhindra läckage av resurser. Om du till exempel öppnar en fil eller skapar en databas eller nätverksanslutning i en Prova blockera, bör du stänga eller befria det i en till sist blockera. 

Observera att i Kotlin den kasta konstruera är ett uttryck och kan kombinera med andra uttryck.

val brev = 'c' valresultat = om (bokstaven i 'a' ... 'z') bokstäver annars kasta IllegalArgumentException ("Ett brev måste vara mellan a till z") 

Även Prova konstruktion kan användas som ett uttryck.

roligt foo (tal: Int) valresultat = försök om (nummer! = 1) kasta IllegalArgumentException () true fångst (e: IllegalArgumentException) false println (resultat) foo (2) // false

Här tilldelade vi värdet returnerat från försök fånga blockera till resultat variabel. Om numret inte är det 1, det kastar en IllegalArgumentException och den fånga blocket körs. De falsk uttryck i fånga blockvärdet kommer att tilldelas till resultat variabel. Om numret är 1 istället då Sann expressionsvärdet kommer att tilldelas till resultat variabel.

Java Interop

Undantag i Kotlin beter sig som vanligt i Java, men jag vill göra dig medveten om en användbar anmärkning som heter @throws i Kotlin som kan komma till nytta. Eftersom alla undantag i Kotlin är avmarkerade, kanske utvecklare som konsumerar din Kotlin-kod från Java kanske inte är medvetna om att dina funktioner slår undantag. Du kan dock fortfarande lägga till de möjliga undantagen som kan kastas till en metod signatur med @Kasta anteckning. Detta kommer att varna Java-uppringare som de behöver för att hantera undantaget. 

Låt oss se ett praktiskt exempel på denna anteckning.

/ * Functions.kt fil * / kul addNumberToTwo (a: Any): Int om (a! Är Int) kasta IllegalArgumentException ("Numret måste vara ett heltal") returnera 2 + a

Här definierade vi en Kotlin-funktion som kan ta ett undantag IllegalArgumentException endast om typen som passerat till funktionen inte är av typen int

Vi kallar den här toppnivån addNumberToTwo () direkt från Java på följande sätt:

public void myJavaMethod () Integerresultat = FunktionerKt.addNumberToTwo (5); System.out.println (resultat); // 7

Det fungerar bra kompilatorn klagar inte. Men om vi vill kommunicera med Java-uppringare att addNumberToTwo () toppnivån fungerar ett undantag, vi lägger helt enkelt till @throws annotering till funktions signaturen. 

@Throws (IllegalArgumentException :: class) kul addNumberToTwo (a: Any): Int om (a! Är Int) kasta IllegalArgumentException ("Numret måste vara ett heltal") returnera 2 + a

Detta @throws annotering kan acceptera en kommaseparerad lista över argument av undantagsklasser. I koden ovan inkluderade vi bara en undantagsklass-IllegalArgumentException

Nu måste vi uppdatera vår Java-kod för att hantera undantaget.

public void myJavaMethod () kastar IllegalArgumentException Integer result = FunctionsKt.addNumberToTwo (5); System.out.println (resultat); 

Om vi ​​dekompilerar Kotlin addNumberToTwo () funktion, med hjälp av Visa Kotlin Bytecode funktionen (om du är i IntelliJ IDEA eller Android Studio, använd Verktyg > Kotlin Visa Kotlin Bytecode) ser vi följande Java-kod:

// ... offentliga statiska slutliga int addNumberToTwo (@NotNull Object a) kastar IllegalArgumentException Intrinsics.checkParameterIsNotNull (a, "a"); om (! (en instans av Integer)) kasta (Kastbar) (ny IllegalArgumentException ("Nummer måste vara ett heltal"));  else return 2 + ((Number) a) .intValue ();  // ... 

I den genererade Java-koden ovan (vissa element i den genererade koden avlägsnades för korthetens skull) kan du se att kompilatorn lagt till kastar sökord till metodens signatur - eftersom vi inkluderade @throws anteckning. 

Slutsats

I denna handledning lärde du dig mer om programmering i Kotlin genom att titta på undantag. Vi såg att Kotlin inte har kontrollerade undantag men att alla undantag istället är okontrollerade. Vi tittade också på hur man hanterar undantag med hjälp av försök fånga blockera och se användbarheten av @throws anteckning i Kotlin för Java-anropare. 

För att lära mig mer om Kotlins språket rekommenderar jag att du besöker Kotlins dokumentation. Eller kolla in några av våra andra Android App-utvecklingsposter här på Envato Tuts!