CodeGym /Java blog /Tilfældig /Undtagelser i Java
John Squirrels
Niveau
San Francisco

Undtagelser i Java

Udgivet i gruppen
Hej! I dagens lektion vil vi tale om Java-undtagelser. Hverdagen er fuld af situationer, som vi ikke forudser. Du står for eksempel op på arbejde om morgenen og leder efter din telefonoplader, men du kan ikke finde den nogen steder. Du går på badeværelset for at tage et brusebad for at opdage, at rørene er frosne. Du sætter dig ind i din bil, men den starter ikke. Et menneske er ret let i stand til at klare sådanne uforudsete omstændigheder. I denne artikel vil vi forsøge at finde ud af, hvordan Java-programmer håndterer dem.

Hvad er en Java-undtagelse?

I programmeringsverdenen kaldes fejl og uforudsete situationer i udførelsen af ​​et program for undtagelser. I et program kan der forekomme undtagelser på grund af ugyldige brugerhandlinger, utilstrækkelig diskplads eller tab af netværksforbindelsen til serveren. Undtagelser kan også skyldes programmeringsfejl eller forkert brug af en API. I modsætning til mennesker i den virkelige verden skal et program vide præcis, hvordan man håndterer disse situationer. Til dette har Java en mekanisme kendt som undtagelseshåndtering.

Et par ord om søgeord

Undtagelseshåndtering i Java er baseret på brugen af ​​følgende nøgleord i programmet:
  • try - definerer en kodeblok, hvor en undtagelse kan forekomme;
  • catch - definerer en kodeblok, hvor undtagelser håndteres;
  • endelig - definerer en valgfri kodeblok, der, hvis den er til stede, udføres uanset resultaterne af prøveblokken.
Disse søgeord bruges til at skabe specielle konstruktioner i koden: prøv{}fangst , prøv{}fang{}til sidst , prøv{}endelig{} .
  • kaste - bruges til at rejse en undtagelse;
  • throws - bruges i metodesignaturen for at advare om, at metoden kan give en undtagelse.
Et eksempel på brug af nøgleord i et Java-program:

// This method reads a string from the keyboard

public String input() throws MyException { // Use throws to warn 
// that the method may throw a MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// We use a try block to wrap code that might create an exception. In this case,
// the compiler tells us that the readLine() method in the 
// BufferedReader class might throw an I/O exception
    try {
        s = reader.readLine();
// We use a catch block to wrap the code that handles an IOException  
    } catch (IOException e) {
        System.out.println(e.getMessage());
// We close the read stream in the finally block
    } finally {
// An exception might occur when we close the stream if, for example, the stream was not open, so we wrap the code in a try block
        try {
            reader.close();
// Handle exceptions when closing the read stream
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// We've decided that an empty string will prevent our program from working properly. For example, we use the result of this method to call the substring(1, 2) method. Accordingly, we have to interrupt the program by using throw to generate our own MyException exception type.
        throw new MyException("The string cannot be empty!");
    }
    return s;
}

Hvorfor har vi brug for undtagelser?

Lad os se på et eksempel fra den virkelige verden. Forestil dig, at en del af en motorvej har en lille bro med begrænset vægtkapacitet. Hvis en bil, der er tungere end broens grænse, kører over den, kan den kollapse. Situationen for chaufføren ville mildt sagt blive exceptionel. For at undgå dette opsætter transportafdelingen advarselsskilte på vejen, før noget går galt. Når en fører ser advarselsskiltet, sammenligner han sit køretøjs vægt med broens maksimale vægt. Hvis køretøjet er for tungt, tager føreren en omfartsrute. Transportafdelingen gjorde det for det første muligt for lastbilchauffører at ændre deres rute, hvis det var nødvendigt, for det andet advarede chaufførerne om farerne på hovedvejen, og for det tredje advarede chaufførerne om, at broen ikke må bruges under visse forhold. Undtagelser i Java - 2Evnen til at forhindre og løse ekstraordinære situationer i et program, så det kan fortsætte med at køre, er en grund til at bruge undtagelser i Java. Undtagelsesmekanismen lader dig også beskytte din kode (API) mod ukorrekt brug ved at validere (kontrollere) eventuelle input. Forestil dig nu, at du er transportafdelingen et øjeblik. Først skal du kende de steder, hvor bilister kan forvente ballade. For det andet skal du oprette og installere advarselsskilte. Og endelig skal du sørge for omveje, hvis der opstår problemer på hovedruten. I Java fungerer undtagelsesmekanismen på lignende måde. Under udviklingen bruger vi en prøveblok til at bygge en "undtagelsesbarriere" omkring farlige kodesektioner, vi leverer "backup-ruter" ved hjælp af en catch {}blok, og vi skriver kode, der skal køre uanset hvad i en endelig{} blok. Hvis vi ikke kan give en "backup-rute", eller vi ønsker at give brugeren ret til at vælge, skal vi i det mindste advare ham eller hende om faren. Hvorfor? Forestil dig bare indignationen hos en chauffør, der uden at se et eneste advarselsskilt når frem til en lille bro, som han ikke kan krydse! I programmering, når vi skriver vores klasser og metoder, kan vi ikke altid forudse, hvordan de kan blive brugt af andre udviklere. Som et resultat kan vi ikke forudse den 100 % korrekte måde at løse en ekstraordinær situation på. Når det er sagt, er det en god form at advare andre om muligheden for ekstraordinære situationer. Javas undtagelsesmekanisme lader os gøre dette med kastsøgeord — i det væsentlige en erklæring om, at vores metodes generelle adfærd inkluderer at kaste en undtagelse. Således ved enhver, der bruger metoden, at han eller hun skal skrive kode for at håndtere undtagelser.

Advarer andre om "besvær"

Hvis du ikke har planer om at håndtere undtagelser i din metode, men vil advare andre om, at der kan forekomme undtagelser, så brug nøgleordet throws . Dette nøgleord i metodesignaturen betyder, at metoden under visse betingelser kan give en undtagelse. Denne advarsel er en del af metodegrænsefladen og lader dens brugere implementere deres egen undtagelseshåndteringslogik. Efter kast specificerer vi de typer af undtagelser der kastes. Disse stammer normalt fra Javas undtagelsesklasse . Da Java er et objektorienteret sprog, er alle undtagelser objekter i Java. Undtagelser i Java - 3

Undtagelseshierarki

Når der opstår en fejl, mens et program kører, opretter JVM et objekt af den passende type fra Java-undtagelseshierarkiet - et sæt mulige undtagelser, der stammer fra en fælles forfader - Throwable- klassen . Vi kan opdele ekstraordinære runtime-situationer i to grupper:
  1. Situationer, hvorfra programmet ikke kan genoprette og fortsætte normal drift.
  2. Situationer, hvor genopretning er mulig.
Den første gruppe inkluderer situationer, der involverer en undtagelse, der stammer fra klassen Error . Disse er fejl, der opstår på grund af en JVM-fejl, hukommelsesoverløb eller systemfejl. De indikerer normalt alvorlige problemer, som ikke kan løses med software. I Java kontrolleres muligheden for sådanne undtagelser ikke af compileren, så de er kendt som ukontrollerede undtagelser. Denne gruppe inkluderer også RuntimeExceptions, som er undtagelser, der stammer fra undtagelsenklasse og genereres af JVM'en under kørsel. De er ofte forårsaget af programmeringsfejl. Disse undtagelser er heller ikke markeret (ikke markeret) på kompileringstidspunktet, så du er ikke forpligtet til at skrive kode for at håndtere dem. Den anden gruppe omfatter ekstraordinære situationer, der kan forudses, når du skriver programmet (og derfor bør du skrive kode for at håndtere dem). Sådanne undtagelser kaldes kontrollerede undtagelser. Når det kommer til undtagelser, er det meste af en Java-udviklers arbejde at håndtere sådanne situationer.

Oprettelse af en undtagelse

Når et program kører, genereres undtagelser enten af ​​JVM eller manuelt ved hjælp af en throw -sætning. Når dette sker, oprettes et undtagelsesobjekt i hukommelsen, programmets hovedflow afbrydes, og JVM's undtagelseshandler forsøger at håndtere undtagelsen.

Undtagelseshåndtering

I Java opretter vi kodeblokke, hvor vi forudser behovet for undtagelseshåndtering ved hjælp af try{}catch , try{}catch{}finally og try{}finally{}- konstruktionerne. Undtagelser i Java - 4Når en undtagelse kastes i en try- blok, leder JVM efter en passende undtagelseshandler i den næste catch- blok. Hvis en catch- blok har den nødvendige undtagelsesbehandler, overføres kontrollen til den. Hvis ikke, så kigger JVM længere nede i kæden af ​​fangblokke , indtil den rette handler er fundet. Efter at have udført en catch- blok, overføres kontrollen til den valgfrie endelige blok. Hvis en passende fangstblok ikke findes, så stopper JVM programmet og viser staksporet (den aktuelle stak af metodekald), efter først at have udført den endelige blok, hvis den findes. Eksempel på undtagelseshåndtering:

public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside print method: " + s);
    }

    public static void main(String[] args) {
        Print print = new Print();
        List list= Arrays.asList("first step", null, "second step");

        for (String s : list) {
            try {
                print.print(s);
            }
            catch (NullPointerException e) {
                System.out.println(e.getMessage());
                System.out.println("Exception handled. The program will continue");
            }
            finally {
                System.out.println("Inside finally block");
            }
            System.out.println("The program is running...");
            System.out.println("-----------------");
        }

    }
    }
Her er resultaterne af hovedmetoden :

Inside print method: first step
Inside finally block
The program is running...
-----------------
Exception: s is null!
Exception handled. The program will continue
Inside finally block
The program is running...
-----------------
Inside print method: second step
Inside finally block
The program is running...
-----------------
Den endelige bruges typisk til at lukke alle streams og frigøre eventuelle ressourcer, der er åbnet/allokeret i en prøveblok . Men når du skriver et program, er det ikke altid muligt at holde styr på lukningen af ​​alle ressourcer. For at gøre vores liv nemmere tilbyder Javas udviklere konstruktionen prøv-med-ressourcer , som automatisk lukker alle ressourcer, der åbnes i en prøveblok . Vores første eksempel kan omskrives med prøv-med-ressourcer :

public String input() throws MyException {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")) {
        throw new MyException ("The string cannot be empty!");
    }
    return s;
}
Takket være Java-funktioner introduceret i version 7, kan vi også kombinere fangst af heterogene undtagelser i én blok, hvilket gør koden mere kompakt og læsbar. Eksempel:

public String input() {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
        s = reader.readLine();
        if (s.equals("")) {
            throw new MyException("The string cannot be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

Bundlinjen

Ved at bruge undtagelser i Java kan du gøre dine programmer mere robuste ved at oprette "backup-ruter", bruge catch-blokke til at adskille hovedkoden fra undtagelseshåndteringskoden og bruge throws til at flytte ansvaret for undtagelseshåndtering til den, der bruger din metode .
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION