Kotlin fra grunnen Unntakshåndtering

Kotlin er et moderne programmeringsspråk som kompilerer til Java bytecode. Det er gratis og åpen kildekode, og gjør koding for Android enda morsommere.  

I forrige artikkel lærte du mer om objektorientert programmering ved å grave inn abstrakte klasser, grensesnitt, arv og type aliaser i Kotlin. 

I dette innlegget fortsetter du å lære om programmering i Kotlin ved å lære om unntak og hvordan du håndterer dem. 

1. Unntakshåndtering

Unntak brukes til å indikere et problem i vår kode under et programs utførelse. Unntakshåndtering er evnen til å adressere (eller håndtere) unntaket som kan oppstå. Hvis vi ikke håndterer noe unntak som oppstår, stopper programmet vårt med å plukke opp appen umiddelbart, og krasjer vår app umiddelbart. 

Unntakshåndtering gjør at programmet vårt kan fortsette å utføre selv om det var unntak (selv om det anbefales å logge unntakene dine og rapportere dem ved hjelp av et krasjrapporteringsverktøy som Crashlytics).   

I Java har vi to typer unntak: merket og ukontrollert. Jeg forklarer dem begge kort, men vi starter med ukontrollerte unntak. 

Ukontrollerte unntak

Dette er unntak som kastes på grunn av feil i koden din. De er en direkte eller indirekte underklasse av RuntimeException super. 

Eksempler på ukontrollerte unntak inkluderer:

  • ArithmeticException: kastet når du deler med null.
  • ArrayIndexOutOfBoundExceptions: kastet når en matrise har blitt åpnet med en ulovlig indeks. 
  • SecurityException: kastet av sikkerhetsansvarlig for å angi et sikkerhetsbrudd.
  • NullPointerException: kastet når man påberoper en metode eller egenskap på et null objekt.

En metode som kan kaste et ukontrollert unntak inneholder ingen informasjon om unntaket som er kastet på metodedeklarasjonen. 

offentlig Integer divideByZero (Integer teller, Integer nevner) retur teller / nevner;  divideByZero (7, 0) // kaster ArithmeticException

Disse typer unntak kan forhindres ved å kode riktig. I koden ovenfor bør vi ha sjekket om nevneren var null før operasjonen ble utført. For disse unntakene trenger utvikleren ikke å ta unntaket ved hjelp av prøv ... fange blokkere. Med andre ord, vi er ikke tvunget av kompilatoren til å pakke inn koden som kan utløse unntaket i a prøv ... fange blokkere. I stedet bør vi bare sørge for at unntakene aldri skjer i utgangspunktet.

Husk også, Kotlin er et null sikkert språk. Med andre ord kan det hjelpe oss med å unngå å få NullPointerExceptions i vår kode. Du kan lese Nullability, Loops og Conditions posten for å få en oppdatering på null sikkerhet i Kotlin. 

Kontrollerte unntak i Java

En metode som kan kaste et kontrollert unntak, må deklareres i sin metode underskrift ved hjelp av kaster søkeord. Hvis du ringer en metode som kaster et kontrollert unntak, må du enten kaste den igjen fra funksjonen din eller for å fange den og håndtere den ved hjelp av en prøv ... fange blokkere. 

Sjekket unntak er unntak som blir sjekket på kompileringstidspunktet. Disse typer unntak arver fra Unntak klasse. Et eksempel på denne typen unntak er IOException. Dette kan oppstå når du prøver å få tilgang til en fil som ikke kan åpnes fordi den ikke eksisterer. (FileNotFoundException er en underklasse av IOException.)

// utføre i en bakgrunnstråd public void editFile (Fil fil, String text) prøv file.getParentFile (). mkdirs (); FileOutputStream fileOutputStream = ny FileOutputStream (fil); Skribentforfatter = Ny BufferedWriter (Ny OutputStreamWriter (FileOutputStream)); prøv writer.write (text); writer.flush (); fileOutputStream.getFD () synk (.);  endelig writer.close ();  fangst (IOException e) // Log unntaket e.printStackTrace (); 

I den forrige koden brukte vi en prøv ... fange blokk for å håndtere IOException inne i editFile () metode. Vi kan nå ringe editFile () Metoden som vanlig, og kompilatoren vil ikke klage. 

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

Vi ser på koden nedenfor, og har refactored metoden til å isteden bruke kaster søkeord i metoden signatur. Dette indikerer at innringere som de trenger for å håndtere unntaket IOException Det kan bli kastet når man ringer metoden editFile ().

// dette burde være i en bakgrunnsrute offentlig tomgang editFile (Fil fil, String text) kaster IOException file.getParentFile (). mkdirs (); FileOutputStream fileOutputStream = ny FileOutputStream (fil); Skribentforfatter = Ny BufferedWriter (Ny OutputStreamWriter (FileOutputStream)); prøv writer.write (text); writer.flush (); fileOutputStream.getFD () synk (.);  endelig writer.close (); 

For å ringe metoden ovenfor må vi omgir den i en prøv ... fange blokk for å håndtere unntaket.

prøv editFile (ny fil (""), "min tekst");  fangst (IOException e) e.printStackTrace (); 

Dette har vært en kort titt på unntak i Java. La oss nå se hvordan Kotlin håndterer unntak. 

2. Unntak i Kotlin

Hovedforskjellen mellom Kotlin og Java-unntaksmekanismer er at alle unntakene er ukontrollerte i Kotlin. Med andre ord, de er ikke eksplisitt erklært i funksjons signaturene, som de er i Java.

morsom editFile (fil: fil, tekst: streng) file.parentFile.mkdirs () val fileOutputStream = FileOutputStream (fil) val writer = BufferedWriter (OutputStreamWriter (fileOutputStream)) prøv writer.write (text) writer.flush () fileOutputStream .fd.sync () endelig writer.close ()

Her har vi konvertert editFile () metode til en Kotlin-funksjon. Du kan se at funksjonen ikke har kaster IOException uttalelse i sin funksjons signatur. kaster er ikke engang et søkeord i Kotlin. 

Også, vi kan ringe denne funksjonen uten å omgjøre den med prøv ... fange blokkere og kompilatoren vil ikke klage. Med andre ord er det ikke slikt som sjekkede unntak i Kotlin. Alle unntak er ikke merket. (Merk at hvis det er et unntak kastet, stopper programgjennomgangen som normalt.) 

Hvis vi mener at dette unntaket kan oppstå, bør vi fortsatt håndtere det ved å omgjøre metoden med a prøv ... fange blokk - men dette håndheves ikke av Kotlin-kompilatoren. 

prøv editFile (File (""), "text 123") fangst (e: IOException) e.printStackTrace ()

Hvis unntaket kastet inne i editFile () funksjon er en forekomst av IOException klasse, vår å fange blokkering vil bli utført, og vi skriver ut stablingssporet for feilsøkingsformål.

De prøv ... fange Blokkere

De prøve konstruere med å fange og endelig Klausuler i Kotlin ligner på Java. 

morsom foo () prøv kaste Unntak ("Unntaksmelding") fangst (e: Unntak) println ("Unntatt håndtert") til slutt println ("inside finally block")

Her kaster vi en Unntak objekt inni prøve blokkere. Legg merke til at vi ikke inkluderte ny søkeord som vi gjør i Java for å opprette en ny forekomst. Vær også oppmerksom på at vi ikke angav unntaket som vil bli kastet i funksjons signaturen som vi måtte i Java. 

Vi håndterer alle underklasser og klasser av typen Unntak i fangstblokken. Den valgfrie endelig blokkering utføres alltid - dette er hvor vi vanligvis lukker eventuelle ressurser eller tilkoblinger som tidligere ble åpnet for å forhindre ressurslekkasjer. Hvis du for eksempel åpner en fil eller oppretter en database eller nettverksforbindelse i en prøve blokkere, bør du lukke eller frigjøre den i en endelig blokkere. 

Legg merke til at i Kotlin den kaste konstruere er et uttrykk og kan kombinere med andre uttrykk.

val brev = 'c' valresultat = hvis (bokstav i 'a' ... 'z') brev annet kaste IllegalArgumentException ("Et brev må være mellom a til z") 

Også, den prøve konstruksjon kan brukes som et uttrykk.

morsom foo (nummer: Int) valresultat = prøve hvis (tall! = 1) kaste IllegalArgumentException () true fangst (e: IllegalArgumentException) false println (resultat) foo (2) // false

Her tildelte vi verdien returnert fra prøv ... fange blokkere til resultat variabel. Hvis nummeret ikke er det 1, det kaster en IllegalArgumentException og å fange blokkering er utført. De falsk uttrykk i å fange blokkverdi vil bli tildelt til resultat variabel. Hvis nummeret er 1 i stedet da ekte uttrykksverdien vil bli tildelt til resultat variabel.

Java Interop

Unntak i Kotlin oppfører seg som vanlig i Java, men jeg vil gjøre deg oppmerksom på en nyttig merknad som heter @Throws i Kotlin som kan komme til nytte. Fordi alle unntak i Kotlin ikke er merket, kan utviklere som bruker Kotlin-koden fra Java, ikke være oppmerksom på at funksjonene dine kaster unntak. Du kan imidlertid fortsatt legge til mulige unntak som kan bli kastet til en metode underskrift med @Kaste merknad. Dette vil varsle Java-oppringere som de trenger for å håndtere unntaket. 

La oss se et praktisk eksempel på denne merknaden.

/ * Functions.kt fil * / morsomt addNumberToTwo (a: Enhver): Int hvis (a! Er Int) kaste IllegalArgumentException ("Nummer må være et heltall") returnere 2 + a

Her definerte vi en Kotlin-funksjon som kan kaste et unntak IllegalArgumentException bare hvis typen som er overført til funksjonen ikke er av typen int

Vi kaller denne toppnivåfunksjonen addNumberToTwo () direkte fra Java på følgende måte:

offentlig tomrom myJavaMethod () Integer resultat = FunksjonerKt.addNumberToTwo (5); System.out.println (resultat); // 7

Dette fungerer fint; kompilatoren klager ikke. Men hvis vi ønsker å kommunisere med Java-oppringere at addNumberToTwo () toppnivå funksjon kaster et unntak, vi legger ganske enkelt til @Throws annotasjon til funksjons signaturen. 

@Throws (IllegalArgumentException :: class) morsomt addNumberToTwo (en: Enhver): Int hvis (a! Er Int) kaste IllegalArgumentException ("Nummer må være et heltall") returnere 2 + a

Dette @Throws annotering kan akseptere en kommaseparert liste over argumenter for unntaksklasser. I koden ovenfor inkluderte vi bare ett unntaksklasse-IllegalArgumentException

Nå må vi oppdatere vår Java-kode for å håndtere unntaket.

offentlig tomrom myJavaMethod () kaster ulovligArgumentException Integer resultat = FunksjonerKt.addNumberToTwo (5); System.out.println (resultat); 

Hvis vi dekompilere Kotlin addNumberToTwo () funksjon, bruk av Vis Kotlin Bytecode funksjonen (hvis du er i IntelliJ IDEA eller Android Studio, bruk Verktøy > Kotlin Vis Kotlin Bytecode), ser vi følgende Java-kode:

// ... offentlig statisk endelig int addNumberToTwo (@NotNull Object a) kaster ulovligArgumentException Intrinsics.checkParameterIsNotNull (a, "a"); hvis (! (en forekomst av Integer)) kaste (Kastbar) (ny ulovligArgumentException ("tall må være et heltall"));  ellers return 2 + ((Nummer) a) .intValue ();  // ... 

I den genererte Java-koden ovenfor (noen elementer i den genererte koden ble fjernet for korthetens skyld), kan du se at kompilatoren la til kaster søkeord til metoden signatur - fordi vi inkluderte @Throws merknad. 

Konklusjon

I denne opplæringen lærte du mer om programmering i Kotlin ved å se på unntak. Vi så at Kotlin ikke har sjekket unntak, men at alle unntakene i stedet er ukontrollerte. Vi så også på hvordan du skal håndtere unntak ved å bruke prøv ... fange blokkere og se nytten av @Throws annotasjon i Kotlin for Java-oppringere. 

For å lære mer om Kotlin-språket, anbefaler jeg at du besøker Kotlin-dokumentasjonen. Eller sjekk ut noen av våre andre Android-apputviklingsposter her på Envato Tuts!