CodeGym /Java blog /Tilfældig /Undtagelser: fangst og håndtering
John Squirrels
Niveau
San Francisco

Undtagelser: fangst og håndtering

Udgivet i gruppen
Hej! Jeg hader at nævne det, men en stor del af en programmørs arbejde er at håndtere fejl. Oftest hans eller hendes egen. Det viser sig, at der ikke er nogen mennesker, der ikke laver fejl. Og sådanne programmer er der heller ikke. Undtagelser: fangst og håndtering - 1 Selvfølgelig, når man beskæftiger sig med en fejl, er det vigtigste at forstå dens årsag. Og mange ting kan forårsage fejl i et program. På et tidspunkt spurgte Javas skabere sig selv, hvad der skulle gøres med de mest sandsynlige programmeringsfejl? Det er ikke realistisk at undgå dem helt, programmører er i stand til at skrive ting, du ikke engang kan forestille dig. :) Så vi er nødt til at give sproget en mekanisme til at arbejde med fejl. Med andre ord, hvis der er en fejl i dit program, har du brug for en slags script til, hvad du skal gøre næste gang. Hvad skal et program helt præcist gøre, når der opstår en fejl? I dag vil vi stifte bekendtskab med denne mekanisme. Det kaldes " undtagelser i Java ".

Hvad er en undtagelse?

En undtagelse er en usædvanlig, uplanlagt situation, der opstår, mens et program kører. Der er mange undtagelser. For eksempel skrev du kode, der læser tekst fra en fil og viser den første linje.

public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
Men hvad hvis der ikke er en sådan fil! Programmet vil generere en undtagelse: FileNotFoundException. Output: Undtagelse i tråden "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Systemet kan ikke finde den angivne sti) I Java er hver undtagelse repræsenteret af en separat klasse. Alle disse undtagelsesklasser stammer fra en fælles "forfader" - Throwableforældreklassen. En undtagelsesklasses navn afspejler normalt kortfattet, hvorfor undtagelsen opstod:
  • FileNotFoundException(filen blev ikke fundet)

  • ArithmeticException(der opstod en undtagelse under udførelse af en matematisk operation)

  • ArrayIndexOutOfBoundsException(indekset er uden for arrayets grænser). For eksempel opstår denne undtagelse, hvis du forsøger at vise position 23 i et array, der kun har 10 elementer.
I alt har Java næsten 400 sådanne klasser! Hvorfor så mange? For at gøre dem mere bekvemme for programmører at arbejde med. Forestil dig dette: du skriver et program, og mens det kører, genererer det en undtagelse, der ser sådan ud:

Exception in thread "main"
Øhhhh. :/ Det hjælper ikke meget. Det er ikke klart, hvad fejlen betyder, eller hvor den kom fra. Der er ingen nyttige oplysninger her. Men det store udvalg af undtagelsesklasser i Java giver programmøren det, der betyder mest: typen af ​​fejl og dens sandsynlige årsag (indlejret i klassenavnet). Det er noget helt andet at se

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
Det er straks klart, hvad problemet kan være, og hvor man skal begynde at grave for at løse problemet! Undtagelser, ligesom forekomster af alle klasser, er objekter.

Undtagelser fra fangst og håndtering

Java har specielle kodeblokke til at arbejde med undtagelser: try, catchog finally. Undtagelser: fangst og håndtering - 2 Kode, hvor programmøren mener, at der kan forekomme en undtagelse, placeres i tryblokken. Det betyder ikke, at der vil ske en undtagelse her. Det betyder, at det kan forekomme her, og programmøren er opmærksom på denne mulighed. Den type fejl, du forventer at opstå, placeres i catchblokken. Dette indeholder også al den kode, der skal udføres, hvis der opstår en undtagelse. Her er et eksempel:

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");
   }
}
Output: Fejl! Fil ikke fundet! Vi sætter vores kode i to blokke. I den første blok forventer vi, at der kan opstå en "Fil ikke fundet"-fejl. Dette er tryblokken. I den anden fortæller vi programmet, hvad det skal gøre, hvis der opstår en fejl. Og den specifikke fejltype: FileNotFoundException. Hvis vi sætter en anden undtagelsesklasse i blokkens parentes catch, FileNotFoundExceptionbliver den ikke fanget.

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Error! File not found!");
   }
}
Output: Undtagelse i tråden "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Systemet kan ikke finde den angivne sti) Koden i catchblokken kørte ikke, fordi vi "konfigurerede" denne blok at fange ArithmeticException, og koden i tryblokken kastede en anden type: FileNotFoundException. Vi har ikke skrevet nogen kode til at håndtere FileNotFoundException, så programmet viser standardoplysningerne for FileNotFoundException. Her skal du være opmærksom på tre ting. Nummer et. Når en undtagelse opstår på en linje i tryblokken, vil koden, der følger, ikke blive udført. Udførelse af programmet "springer" straks til catchblokken. For eksempel:

public static void main(String[] args) {
   try {
       System.out.println("Divide by zero");
       System.out.println(366/0);// This line of code will throw an exception

       System.out.println("This");
       System.out.println("code");
       System.out.println("will not");
       System.out.println("be");
       System.out.println("executed!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
Output: Divider med nul Programmet hoppede til catch-blokken! Fejl! Du kan ikke dividere med nul! På den anden linje i tryblokken forsøger vi at dividere med 0, hvilket resulterer i en ArithmeticException. Følgelig tryvil linje 3-9 i blokken ikke blive udført. Som vi sagde, begynder programmet straks at udføre catchblokken. Nummer to. Der kan være flere catchblokke. Hvis koden i tryblokken måske ikke giver én, men flere forskellige typer undtagelser, kan du skrive en catchblok for hver af dem.

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
      
       System.out.println("Error! File not found!");
      
   } catch (ArithmeticException e) {

       System.out.println("Error! Division by 0!");
      
   }
}
I dette eksempel har vi skrevet to catchblokke. Hvis der FileNotFoundExceptionopstår a i tryblokken, vil den første catchblok blive udført. Hvis en ArithmeticExceptionopstår, vil den anden blok blive udført. Du kunne skrive 50 catchblokke, hvis du ville. Selvfølgelig er det bedre ikke at skrive kode, der kan give 50 forskellige slags undtagelser. :) Tredje. Hvordan ved du, hvilke undtagelser din kode kan give? Nå, du kan måske gætte nogle af dem, men det er umuligt for dig at holde alt i dit hoved. Java-kompileren kender derfor de mest almindelige undtagelser og de situationer, hvor de kan forekomme. For eksempel, hvis du skriver kode, som compileren ved kan give to typer undtagelser, kompileres din kode ikke, før du håndterer dem. Vi vil se eksempler på dette nedenfor. Nu nogle ord om undtagelseshåndtering. Der er 2 måder at håndtere undtagelser på. Vi har allerede stødt på den første: metoden kan håndtere undtagelsen selv i en catch()blok. Der er en anden mulighed: metoden kan genkaste undtagelsen op i opkaldsstakken. Hvad betyder det? For eksempel har vi en klasse med samme printFirstString()metode, som læser en fil og viser dens første linje:

public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
På nuværende tidspunkt kompilerer vores kode ikke, fordi den har uhåndterede undtagelser. I linje 1 angiver du stien til filen. Compileren ved, at en sådan kode nemt kunne producere en FileNotFoundException. I linje 3 læser du teksten fra filen. Denne proces kan nemt resultere i en IOException(input/output fejl). Nu siger compileren til dig, "Dude, jeg vil ikke godkende denne kode, og jeg vil ikke kompilere den, før du fortæller mig, hvad jeg skal gøre, hvis en af ​​disse undtagelser opstår. Og de kan helt sikkert ske baseret på den kode, du skrev !" Der er ingen måde at komme udenom: du skal klare begge dele! Vi kender allerede til den første undtagelseshåndteringsmetode: vi skal sætte vores kode i en tryblok og tilføje to catchblokke:

public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error, file not found!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("File input/output error!");
       e.printStackTrace();
   }
}
Men dette er ikke den eneste mulighed. Vi kunne simpelthen kaste undtagelsen højere i stedet for at skrive fejlhåndteringskode inde i metoden. Dette gøres ved hjælp af nøgleordet throwsi metodedeklarationen:

public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Efter søgeordet throwsangiver vi en kommasepareret liste over alle de typer undtagelser, som metoden kan give. Hvorfor? Nu, hvis nogen vil kalde printFirstString()metoden i programmet, bliver han eller hun (ikke dig) nødt til at implementere undtagelseshåndtering. Antag for eksempel, at en af ​​dine kolleger et andet sted i programmet skrev en metode, der kalder din printFirstString()metode:

public static void yourColleagueMethod() {

   // Your colleague's method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
Vi får en fejl! Denne kode vil ikke kompilere! Vi skrev ikke undtagelseshåndteringskode i printFirstString()metoden. Som følge heraf falder denne opgave nu på skuldrene af dem, der bruger metoden. Med andre ord methodWrittenByYourColleague()har metoden nu de samme 2 muligheder: den skal enten bruge en try-catchblok til at håndtere begge undtagelserne eller genkaste dem.

public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   // The method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
I det andet tilfælde skal den næste metode i opkaldsstakken – den der ringer methodWrittenByYourColleague()– håndtere undtagelserne. Det er derfor, vi kalder dette "at kaste eller videregive undtagelsen". Hvis du kaster undtagelser opad ved hjælp af nøgleordet throws, vil din kode kompilere. På dette tidspunkt ser det ud til, at compileren siger: "Okay, okay. Din kode indeholder en masse potentielle undtagelser, men jeg vil kompilere den. Men vi vender tilbage til denne samtale!" Og når du kalder en metode, der har uhåndterede undtagelser, opfylder compileren sit løfte og minder dig om dem igen. Til sidst vil vi tale om finallyblokken (undskyld ordspillet). Dette er den sidste del af try-catch-finallyundtagelseshåndteringens triumvirat..

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error! File not found!");
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
   }
}
I dette eksempel vil koden inde i finallyblokken blive udført i begge tilfælde. Hvis koden i tryblokken kører fuldt ud uden at give nogen undtagelser, finallyvil blokken køre til sidst. Hvis koden inde i tryblokken afbrydes af en undtagelse, og programmet hopper til blokken catch, finallyvil blokken stadig køre efter koden inde i catchblokken. Hvorfor er dette nødvendigt? Dens hovedformål er at udføre obligatorisk kode: kode, der skal udføres uanset omstændighederne. For eksempel frigør det ofte nogle ressourcer, der bruges af programmet. I vores kode åbner vi en strøm for at læse information fra filen og videregive den til objektet BufferedReader. Vi skal lukke vores læser og frigive ressourcerne. Dette skal gøres uanset hvad - hvornår programmet fungerer, som det skal, og hvornår det giver en undtagelse. Blokken finallyer et meget praktisk sted at gøre dette:

public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
Nu er vi sikre på, at vi tager os af ressourcerne, uanset hvad der sker, når programmet kører. :) Det er ikke alt, du behøver at vide om undtagelser. Fejlhåndtering er et super vigtigt emne i programmering. Masser af artikler er viet til det. I den næste lektion finder vi ud af, hvilke typer undtagelser der er, og hvordan du opretter dine egne undtagelser. :) Vi ses!
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION