CodeGym /Java blogg /Slumpmässig /Undantag: fångst och hantering
John Squirrels
Nivå
San Francisco

Undantag: fångst och hantering

Publicerad i gruppen
Hej! Jag hatar att nämna det, men en stor del av en programmerares arbete är att hantera fel. Oftast hans eller hennes egen. Det visar sig att det inte finns några människor som inte gör misstag. Och det finns inga sådana program heller. Undantag: fångst och hantering - 1 Naturligtvis, när man hanterar ett fel, är det viktigaste att förstå dess orsak. Och många saker kan orsaka buggar i ett program. Vid något tillfälle frågade Javas skapare sig själva vad som skulle göras med de mest troliga programmeringsfelen? Att helt undvika dem är inte realistiskt, programmerare kan skriva saker du inte ens kan föreställa dig. :) Så vi måste ge språket en mekanism för att arbeta med fel. Med andra ord, om det finns ett fel i ditt program behöver du något slags skript för vad du ska göra härnäst. Vad exakt ska ett program göra när ett fel uppstår? Idag kommer vi att bekanta oss med denna mekanism. Det kallas " undantag i Java ".

Vad är ett undantag?

Ett undantag är en exceptionell, oplanerad situation som inträffar medan ett program körs. Det finns många undantag. Till exempel skrev du kod som läser text från en fil och visar den första raden.

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 tänk om det inte finns någon sådan fil! Programmet genererar ett undantag: FileNotFoundException. Utdata: Undantag i tråden "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Systemet kan inte hitta den angivna sökvägen) I Java representeras varje undantag av en separat klass. Alla dessa undantagsklasser härrör från en gemensam "förfader" - Throwableföräldraklassen. En undantagsklasss namn återspeglar vanligtvis kortfattat varför undantaget inträffade:
  • FileNotFoundException(filen hittades inte)

  • ArithmeticException(ett undantag inträffade när en matematisk operation utfördes)

  • ArrayIndexOutOfBoundsException(indexet är bortom gränserna för arrayen). Detta undantag inträffar till exempel om du försöker visa position 23 i en array som bara har 10 element.
Sammanlagt har Java nästan 400 sådana klasser! Varför så många? För att göra dem mer bekväma för programmerare att arbeta med. Föreställ dig det här: du skriver ett program, och medan det körs genererar det ett undantag som ser ut så här:

Exception in thread "main"
Åhhhh. :/ Det hjälper inte mycket. Det är inte klart vad felet betyder eller var det kom ifrån. Det finns ingen användbar information här. Men det stora utbudet av undantagsklasser i Java ger programmeraren det som är viktigast: typen av fel och dess troliga orsak (inbäddad i klassnamnet). Det är en helt annan sak att se

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
Det är direkt klart vad problemet kan vara och var man ska börja gräva för att lösa problemet! Undantag, som instanser av alla klasser, är objekt.

Undantag för fångst och hantering

Java har speciella kodblock för att arbeta med undantag: try, catchoch finally. Undantag: fångst och hantering - 2 Kod där programmeraren tror att ett undantag kan inträffa placeras i tryblocket. Det betyder inte att ett undantag kommer att inträffa här. Det betyder att det kan inträffa här, och programmeraren är medveten om denna möjlighet. Typen av fel som du förväntar dig ska uppstå placeras i catchblocket. Denna innehåller också all kod som ska köras om ett undantag inträffar. Här är ett exempel:

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!");
   }
}
Utdata: Fel! Filen hittades inte! Vi lägger vår kod i två block. I det första blocket förväntar vi oss att ett "File not found"-fel kan uppstå. Det här är tryblocket. I den andra berättar vi för programmet vad det ska göra om ett fel uppstår. Och den specifika feltypen: FileNotFoundException. Om vi ​​sätter en annan undantagsklass inom parentesen av blocket, catchkommer vi FileNotFoundExceptioninte att fångas.

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!");
   }
}
Utdata: Undantag i tråden "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Systemet kan inte hitta den angivna sökvägen) Koden i catchblocket kördes inte, eftersom vi "konfigurerade" detta block att fånga ArithmeticException, och koden i tryblocket gav en annan typ: FileNotFoundException. Vi skrev ingen kod att hantera FileNotFoundException, så programmet visar standardinformationen för FileNotFoundException. Här måste du vara uppmärksam på tre saker. Nummer ett. När ett undantag inträffar på någon rad i tryblocket kommer koden som följer inte att exekveras. Utförande av programmet "hoppar" omedelbart till catchblocket. Till exempel:

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!");
   }
}
Utgång: Dividera med noll Programmet hoppade till fångstblocket! Fel! Du kan inte dividera med noll! På den andra raden i tryblocket försöker vi dividera med 0, vilket resulterar i en ArithmeticException. Följaktligen kommer raderna 3-9 i tryblocket inte att exekveras. Som vi sa börjar programmet omedelbart exekvera blocket catch. Nummer två. Det kan finnas flera catchblock. Om koden i tryblocket kanske inte ger ett, utan flera olika typer av undantag, kan du skriva ett catchblock för vart och ett av 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 det här exemplet har vi skrivit två catchblock. Om a FileNotFoundExceptioninträffar i blocket kommer trydet första blocket att exekveras. catchOm en ArithmeticExceptioninträffar kommer det andra blocket att exekveras. Du kunde skriva 50 catchblock om du ville. Naturligtvis är det bättre att inte skriva kod som kan skapa 50 olika typer av undantag. :) Tredje. Hur vet du vilka undantag din kod kan ge? Tja, du kanske kan gissa några av dem, men det är omöjligt för dig att hålla allt i huvudet. Java-kompilatorn känner därför till de vanligaste undantagen och de situationer där de kan uppstå. Till exempel, om du skriver kod som kompilatorn vet kan ge två typer av undantag, kompileras inte din kod förrän du hanterar dem. Vi kommer att se exempel på detta nedan. Nu några ord om undantagshantering. Det finns två sätt att hantera undantag. Vi har redan stött på det första: metoden kan hantera själva undantaget i ett catch()block. Det finns ett andra alternativ: metoden kan kasta om undantaget upp i anropsstacken. Vad betyder det? Till exempel har vi en klass med samma printFirstString()metod, som läser en fil och visar dess första rad:

public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
För närvarande kompilerar inte vår kod eftersom den har obehandlade undantag. På rad 1 anger du sökvägen till filen. Kompilatorn vet att sådan kod lätt kan producera en FileNotFoundException. På rad 3 läser du texten från filen. Denna process kan lätt resultera i ett IOException(inmatnings-/utmatningsfel). Nu säger kompilatorn till dig, "Du, jag kommer inte att godkänna den här koden och jag kommer inte att kompilera den förrän du berättar för mig vad jag ska göra om ett av dessa undantag inträffar. Och de kan säkert hända baserat på koden du skrev !" Det finns inget sätt att komma runt det: du måste hantera båda! Vi känner redan till den första undantagshanteringsmetoden: vi måste lägga vår kod i ett tryblock och lägga till två catchblock:

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 detta är inte det enda alternativet. Vi kunde helt enkelt kasta undantaget högre istället för att skriva felhanteringskod inuti metoden. Detta görs med hjälp av nyckelordet throwsi metoddeklarationen:

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 nyckelordet throwsanger vi en kommaseparerad lista över alla typer av undantag som metoden kan ge upphov till. Varför? Om någon nu vill anropa printFirstString()metoden i programmet måste han eller hon (inte du) implementera undantagshantering. Anta till exempel att någon av dina kollegor någon annanstans i programmet skrev en metod som anropar din printFirstString()metod:

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 ett fel! Den här koden kommer inte att kompileras! Vi skrev inte undantagshanteringskod i printFirstString()metoden. Som ett resultat faller denna uppgift nu på axlarna av dem som använder metoden. Med andra ord methodWrittenByYourColleague()har metoden nu samma 2 alternativ: den måste antingen använda ett try-catchblock för att hantera båda undantagen, eller kasta om 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 andra fallet måste nästa metod i anropsstacken – den som anropar – methodWrittenByYourColleague()hantera undantagen. Det är därför vi kallar detta "att kasta eller förpassa undantaget". Om du kastar undantag uppåt med nyckelordet throwskompileras din kod. Vid det här laget verkar kompilatorn säga: "Okej, okej. Din kod innehåller en massa potentiella undantag, men jag kommer att kompilera den. Men vi återkommer till den här konversationen!" Och när du anropar någon metod som har obehandlade undantag, uppfyller kompilatorn sitt löfte och påminner dig om dem igen. Till sist ska vi prata om finallyblocket (förlåt för ordleken). Detta är den sista delen av try-catch-finallytriumviratet för undantagshantering..

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!");
   }
}
finallyI det här exemplet kommer koden inuti blocket att exekveras i båda fallen. Om koden i tryblocket körs i sin helhet utan att göra några undantag, finallykommer blocket att köras till slut. Om koden inuti tryblocket avbryts av ett undantag och programmet hoppar till blocket, catchkommer finallyblocket fortfarande att köras efter koden inuti catchblocket. Varför är detta nödvändigt? Dess huvudsakliga syfte är att exekvera obligatorisk kod: kod som måste utföras oavsett omständigheterna. Till exempel frigör det ofta vissa resurser som används av programmet. I vår kod öppnar vi en ström för att läsa information från filen och skicka den till objektet BufferedReader. Vi måste stänga vår läsare och frigöra resurserna. Detta måste göras oavsett vad - när programmet fungerar som det ska och när det ger ett undantag. Blocket finallyär ett mycket bekvämt ställe att göra detta:

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 är vi säkra på att vi tar hand om resurserna, oavsett vad som händer när programmet körs. :) Det är inte allt du behöver veta om undantag. Felhantering är ett superviktigt ämne inom programmering. Många artiklar ägnas åt det. I nästa lektion tar vi reda på vilka typer av undantag som finns och hur du skapar dina egna undantag. :) Vi ses då!
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION