Excepții Java de ce aveți nevoie în sfârșit. Excepțiile și gestionarea acestora. Care sunt excepțiile

Despre ce și de ce este vorba în acest articol?

Articolul vorbește despre excepții în limbajul Java, metode de gestionare a acestora și câteva caracteristici de lucru cu excepții. Acest articol a fost scris pentru un seminar despre tehnologiile Java susținut de i.Point.

Care sunt excepțiile?

Excepțiile sau evenimentele excepționale sunt evenimente care perturbă fluxul normal de execuție a programului.

Deci, de fiecare dată când apare o eroare în timpul execuției programului, programul aruncă o excepție - în acest moment este creat un obiect excepție special (obiect-excepție), de acum înainte îl vom numi pur și simplu excepție. Acest obiect conține informații despre eroarea care a apărut: tipul de eroare, precum și o înregistrare a stării programului la momentul în care a apărut eroarea. Lansarea unei excepții și trecerea acesteia la runtime este apelată aruncând o excepție(excepție aruncare). Să vedem cum sunt aruncate excepții la executarea unui program în Java:

A apărut o problemă în timpul execuției primei metode, după care a fost aruncată o excepție. În momentul în care este aruncată o excepție, Java începe să caute un handler potrivit pentru aceasta, trecând obiectul în stiva de apeluri până când este găsit un handler de excepție.

Tipuri de excepții în Java

Să aruncăm o privire la ierarhia claselor de obiecte de excepție în Java:

După cum putem vedea, toate excepțiile au un strămoș comun - Throwable. Are două subclase importante - Excepție și Eroare. Excepțiile sunt rezultatul unor probleme întâlnite în cadrul unui program care sunt, în principiu, rezolvabile și previzibile. Erorile reprezintă mai mult decât probleme serioase, care, conform specificației Java, nu ar trebui încercat să fie interceptat într-o aplicație scrisă în mod rezonabil (de exemplu, apare o eroare OutOfMemoryError în cazurile în care JVM-ul nu are suficientă memorie pentru a executa programul). În plus, Exception are un copil important, RuntimeException. Această clasă și descendenții ei reprezintă excepții care sunt aruncate în timpul „funcționării normale a mașinii Java” (exemplele de astfel de excepții includ încercările de a folosi referințe la obiecte nule, diviziunea la zero sau depășirile de matrice).

În Java, toate excepțiile sunt împărțite în trei tipuri: excepții verificate (verificate), erori (Erori) și excepții de rulare (RuntimeExceptions) - ultimele două tipuri sunt, de asemenea, combinate în categoria excepțiilor neverificate. Care este diferența? Toate excepțiile controlate foarte simplu sunt acele erori care pot fi procesate în timpul execuției programului, după cum probabil ați ghicit, toți descendenții clasei Exception (dar nu RuntimeException) aparțin acestui tip; Excepțiile verificate trebuie să fie tratate în codul programului, fie prin includerea într-un bloc try-catch, fie declarate în semnătura metodei.

Excepțiile neverificate nu necesită manipulare obligatorie, deoarece reprezintă situații în care eroarea nu depinde direct de programator (de exemplu, a apărut o eroare în hardware), sau cele când nu are rost să procesăm eroarea, deoarece este mai ușor să faci modificări la cod - acestea includ toți descendenții claselor Error și RuntimeException.

Cum să gestionăm excepțiile?

Toate implementari moderne Limbile Java respectă principiul gestionarea sau declararea excepțiilor(Cerința Catch sau Specificare), care afirmă că codul care are potențialul de a arunca o excepție controlată trebuie fie să fie inclus într-un bloc try-catch (astfel, în blocul catch oferim un handler pentru excepție), fie trebuie să fie anunta că metoda noastră poate arunca o astfel de excepție (după cuvântul cheie throws, după numele metodei).

Să ne uităm la câteva exemple:

//Nota: Această clasă nu se va compila prin design! import java. io .*; import java. util. Vector; clasă publică ListOfNumbers ( vector privat Vector ; privat static final int SIZE = 10 ; public ListOfNumbers () ( vector = vector nou (SIZE ) ; for (int i = 0 ; i< SIZE ; i ++ ) { vector . addElement (new Integer (i )) ; } } public void writeList () { < SIZE ; i ++ ) { out . println (" Value at: " + i + " = " + vector . elementAt (i )) ; } out . close () ; } }

Acest cod nu se va compila deoarece Constructorul FileWriter ne cere să gestionăm IOException. Codul scris corect ar trebui să arate cam așa:

Încercați ( //Excepție verificată netratată IOException PrintWriter out = nou PrintWriter (nou FileWriter ( " OutFile.txt " )) ; pentru (int i = 0; i< SIZE ; i ++ ) { // metoda elementAt aruncă o excepție neverificată ArrayIndexOutOfBoundsException afară . println(" Valoare la: " + i + " = " + vector . elementAt (i )) ; ) catch (IOException e )( //Încercăm să corectăm cumva situația dacă a apărut o eroare la crearea fișierului OutFile.txt) prinde (Excepție e )( //Dacă este generată o excepție non-IOException în blocul try, controlul va trece aici) in sfarsit ( //În orice caz, trebuie să închidem fișierul. if (out != null )( out . close () ; ) )

Acesta este modul în care gestionăm IOException. Fiți atenți la ordinea în care sunt declarate blocurile catch - dacă le schimbați, codul nu se va compila, deoarece IOException este o subclasă de excepție, atunci codul de gestionare a IOException va deveni inaccesibil și compilatorul va arunca o eroare. O atenție deosebită merită un bloc final - codul din acest bloc este întotdeauna executat, indiferent de ceea ce sa întâmplat în blocurile try and catch.

Pe lângă gestionarea directă a excepției folosind un bloc try-catch, o putem declara pur și simplu, lăsând utilizatorii metodei să se ocupe ei înșiși de această problemă:

Public void writeList() aruncă IOException ( //acum nu trebuie să ne ocupăm noi de excepție.}

Procesați sau declarați?

Când ar trebui să gestionăm excepțiile și când ar trebui să le declarăm? O întrebare foarte simplă... este păcat că nu există un răspuns clar la ea. În general, trebuie respectate următoarele reguli:

Gestionați excepția când puteți; declarați o excepție atunci când trebuie să faceți acest lucru.

Ce rezultă din asta? În general, o metodă ar trebui să transmită o excepție apelantului numai dacă ea însăși nu are suficiente informații pentru a gestiona excepția.

Beneficiile pe care ni le oferă utilizarea excepțiilor

scrieți aici despre codurile de eroare și extindeți lista

  1. Separarea codului normal și codul de gestionare a erorilor
  2. Abilitatea de a trece excepții pentru procesarea stivei de apeluri
  3. Gruparea și tratarea erorilor după tip

Probleme de gestionare a excepțiilor

„Excepții pierdute”

În general, excepțiile în Java sunt foarte convenabile și simple, dar, din păcate, au și un dezavantaj. Deși excepțiile sunt indicatori ai problemelor din program și nu trebuie ignorate, este posibil ca excepția să se piardă pur și simplu. Acest lucru se poate întâmpla dacă scriem incorect codul în blocul final. Să ne uităm la un exemplu simplu:

// Cum poate fi aruncată excepția. clasa VeryImportantException extinde Exception ( public String toString () ( return " O excepție foarte importantă! " ; ) ) clasa HoHumException extinde Exception ( public String toString () ( returnează " O excepție trivială " ; ) ) public class LostMessage ( void f () aruncă VeryImportantException (aruncă un nou VeryImportantException () ; ) void dispose () aruncă HoHumException (aruncă un nou HoHumException () ; ) public static void main ( String args ) aruncă o excepție ( LostMessage lm = new LostMessage () ; ftry () ; ftry (lm) ; ; ) în cele din urmă ( lm . dispune ( ) ; ) )

Ce obținem în urma executării acestui cod?

Excepție în firul „principal” O ​​excepție banală
la LostMessage.dispose(LostMessage.java:21)
la LostMessage.main(LostMessage.java:29)

Oh, groază, am pierdut VeryImportantException, care era foarte importantă pentru noi, și am primit în schimb una mai puțin semnificativă.
Prin urmare, atunci când scrieți cod în blocul final, trebuie să fiți foarte atenți ca o astfel de pierdere de informații să nu aibă loc.

Bună, Habr! Vă prezint atenției o traducere a articolului Fixing 7 Common Java Exception Handling Mistakes de Thorben Janssen.

Gestionarea unei excepții este una dintre cele mai comune, dar nu neapărat una dintre cele mai ușoare sarcini. Acesta este încă unul dintre subiectele discutate frecvent în rândul echipelor cu experiență și există câteva bune practici și greșeli comune de care ar trebui să fii conștient.

Iată câteva lucruri de evitat atunci când gestionați excepții în aplicația dvs.

Eroare 1: se declară java.lang.Exception sau java.lang.Throwable

După cum știți deja, trebuie fie să declarați, fie să gestionați o excepție verificată. Dar excepțiile bifate nu sunt singurele pe care le puteți specifica. Puteți folosi orice subclasă java.lang.Throwable în clauza throws. Deci, în loc să specificați cele două excepții diferite pe care le aruncă următorul fragment de cod, puteți utiliza pur și simplu excepția java.lang.Exception în clauza throws.

Public void doNotSpecifyException() aruncă excepție ( doSomething(); ) public void doSomething() aruncă NumberFormatException, IllegalArgumentException ( // face ceva )
Dar asta nu înseamnă că trebuie să o faci. Specificarea Excepție sau Throwable face aproape imposibil să le gestionați corect atunci când apelați metoda dvs. Singura informație pe care o primește metoda dvs. de apelare este că ceva ar putea merge prost. Dar nu distribuiți nicio informație despre niciun eveniment excepțional care ar putea avea loc. Ascundeți aceste informații în spatele motivelor generice pentru a arunca excepții. Devine și mai rău atunci când aplicația dvs. se modifică în timp. Aruncarea excepțiilor generice ascunde toate modificările excepțiilor la care apelantul trebuie să se aștepte și să le gestioneze. Acest lucru poate duce la mai multe erori neașteptate, care trebuie găsite în cazul de testare în loc de o eroare a compilatorului.

Folosiți clase concrete

Este mult mai bine să specificați cele mai specifice clase de excepție, chiar dacă trebuie să utilizați mai multe dintre ele. Aceasta raportează dispozitiv de apelare, ce evenimente excepționale trebuie tratate. De asemenea, vă permite să actualizați clauza throw atunci când metoda dvs. aruncă o excepție suplimentară. În acest fel, clienții tăi sunt conștienți de modificări și chiar primesc o eroare dacă modificați excepțiile aruncate. O astfel de excepție este mult mai ușor de găsit și gestionat decât o excepție care apare doar atunci când este rulat un anumit caz de testare.

Public void specifySpecificExceptions() aruncă NumberFormatException, IllegalArgumentException ( doSomething(); )

Greșeala 2: Prinderea excepțiilor generice

Severitatea acestei erori depinde de ce componenta software implementezi și unde prinzi excepția. Ar putea fi bine să prindeți java.lang.Exception în metoda principală a dvs aplicații Java SE. Dar ar trebui să preferați să prindeți anumite excepții dacă implementați o bibliotecă sau lucrați la straturile mai profunde ale aplicației dvs.

Acest lucru oferă mai multe beneficii. Această abordare vă permite să gestionați fiecare clasă de excepții în mod diferit și vă împiedică să identificați excepții la care nu vă așteptați.

Dar rețineți că primul bloc catch care se ocupă de clasa de excepție sau una dintre super-clasele sale îl va prinde. Așa că asigurați-vă că prindeți mai întâi clasa cea mai specifică. ÎN altfel IDE-urile dvs. vor afișa un mesaj de eroare sau de avertizare despre un bloc de cod inaccesibil.

Încercați ( doSomething(); ) catch (NumberFormatException e) ( // gestionează NumberFormatException log.error(e); ) catch (IllegalArgumentException e) ( // gestionează IllegalArgumentException log.error(e); )

Greșeala 3: Înregistrarea și eliminarea excepțiilor

Aceasta este una dintre cele mai populare erori în gestionarea excepțiilor Java. Poate părea logic să înregistrați excepția acolo unde este aruncată și apoi să o redirecționați către apelant, care poate implementa o gestionare specifică pentru un anumit caz de utilizare. Dar nu ar trebui să faci asta din trei motive:

1. Nu aveți suficiente informații despre cazul de utilizare pe care apelantul metodei dvs. dorește să îl implementeze. O excepție poate face parte din comportamentul așteptat și poate fi gestionată de client. În acest caz, nu este nevoie să îl înregistrați. Aceasta se va adăuga mesaj fals eroare într-un fișier jurnal, care ar trebui să fie filtrat de echipa dumneavoastră de operațiuni.

2. Mesajul jurnal nu furnizează nicio informație care să nu facă deja parte din excepția în sine. Urmărirea și urmărirea stivei sale ar trebui să conțină toate informațiile necesare despre evenimentul excepțional. Mesajul îl descrie, iar urmărirea stivei conține detalii despre clasa, metoda și linia pe care a avut loc.

3. Puteți înregistra aceeași excepție de mai multe ori când o înregistrați în fiecare bloc de captură care o prinde. Acest lucru va strica statisticile din instrumentul dvs. de monitorizare și va face fișierul jurnal dificil de citit pentru echipa dvs. de operațiuni și dezvoltare.

Înregistrați excepția acolo unde o gestionați

Astfel, cel mai bine este să înregistrați o excepție atunci când o gestionați. Cum ar fi următorul fragment de cod. Metoda doSomething aruncă o excepție. Metoda doMore o specifică pur și simplu deoarece dezvoltatorul nu are suficiente informații pentru a o procesa. Acesta este apoi procesat în metoda doEvenMore, care scrie și un mesaj de jurnal.

Public void doEvenMore() ( try ( doMore(); ) catch (NumberFormatException e) ( // gestionează NumberFormatException ) catch (IllegalArgumentException e) ( // gestionează IllegalArgumentException ) ) public void doMore() aruncă NumberFormatException, IllegalArgumentException (doArgumentException(doSomethException) ) public void doSomething() aruncă NumberFormatException, IllegalArgumentException ( // face ceva )

Greșeala 4: Utilizarea excepțiilor pentru a controla fluxul

Utilizarea excepțiilor pentru a controla fluxul aplicației dvs. este considerată un anti-model din două motive principale:

Ele funcționează practic ca o instrucțiune Go To, deoarece anulează execuția unui bloc de cod și merg la primul bloc catch care se ocupă de excepție. Acest lucru face codul foarte greu de citit.

Ele nu sunt la fel de eficiente ca structurile generale de control Java. După cum sugerează și numele, ar trebui să le folosiți numai pentru evenimente excepționale, iar JVM-ul nu le optimizează în același mod ca alt cod. Deci, este mai bine să folosiți condițiile potrivite pentru a vă întrerupe buclele sau declarațiile if-else care cod de blocuri trebuie executat.

Eroare 5: Eliminați cauza excepției

Uneori, poate fi necesar să includeți o excepție în alta. Poate că echipa dvs. a decis să folosească o excepție specifică afacerii cu coduri de eroare și procesare uniformă. Nu este nimic în neregulă cu această abordare decât dacă abordați cauza.

Când aruncați o nouă excepție, ar trebui să setați întotdeauna excepția originală ca cauză. În caz contrar, veți pierde mesajul și urma stivei care descriu evenimentul excepțional care a provocat excepția dvs. Clasa Exception și toate subclasele sale oferă mai multe metode de constructor care iau excepția originală ca parametru și o setează ca cauză.

Greșeala 6: Generalizarea excepțiilor

Când generalizați o excepție, prindeți una anume, cum ar fi NumberFormatException, și aruncați în schimb o excepție nespecifică java.lang. Este similar, dar chiar mai rău decât prima eroare pe care am descris-o în acest articol. Nu numai că ascunde informații despre cazul de eroare specific din API-ul dvs., dar face și accesul dificil.

Public void doNotGeneralizeException() aruncă o excepție ( try ( doSomething (); ) catch (NumberFormatException e) ( aruncă o nouă excepție (e); ) catch (IllegalArgumentException e) ( aruncă o nouă excepție (e); ) )
Așa cum puteți vedea în următorul fragment de cod, chiar dacă știți ce excepții ar putea arunca o metodă, nu le puteți prinde pur și simplu. Trebuie să capturați clasa generică Exception și apoi să verificați tipul cauzei acesteia. Acest cod nu este doar greu de implementat, dar este și greu de citit. Devine și mai rău dacă combinați această abordare cu eroarea 5. Aceasta elimină toate informațiile despre evenimentul excepțional.

Încercați ( doNotGeneralizeException(); ) catch (Exception e) ( if (e.getCause() instanceof NumberFormatException) ( log.error("NumberFormatException: " + e); ) else if (e.getCause() instanceof IllegalArgumentException) ( jurnal .error("Excepție neașteptată: " + e); else ( log.error ("Excepție neașteptată: " + e); ) )
Deci care abordare este cea mai bună?

Fii specific și păstrează motivul pentru care a apărut excepția.

Excepțiile pe care le aruncați ar trebui să fie întotdeauna cât mai specifice posibil. Și dacă includeți o excepție, ar trebui să setați și excepția inițială ca cauză, astfel încât să nu pierdeți urma stivei și alte informații care descriu evenimentul excepțional.

Încercați ( doSomething(); ) catch (NumberFormatException e) ( aruncați o nouă excepție MyBusinessException (e, ErrorCode.CONFIGURATION_ERROR); ) catch (IllegalArgumentException e) (aruncă o nouă MyBusinessException (e, ErrorCode.UNEXPECTED); )

Greșeala 7: Adăugarea de conversii de excepție inutile

După cum am explicat mai devreme, poate fi util să includeți excepțiile în excepții personalizate dacă setați excepția originală ca cauză. Dar unii arhitecți trec peste bord și introduc o clasă specială de excepție pentru fiecare nivel arhitectural. Deci prind excepția în stratul de persistență și o aruncă în MyPersistenceException. Stratul de afaceri îl prinde și îl împachetează într-o MyBusinessException și aceasta continuă până când ajunge la stratul API sau este gestionat.

Public void persistCustomer(Customer c) throws MyPersistenceException ( // persist a Customer ) public void manageCustomer(Customer c) throws MyBusinessException ( // gestionează un Client try ( persistCustomer(c); ) catch (MyPersistenceException e) ( throw new MyBusinessException , e.getCode()); ) public void createCustomer(Customer c) aruncă MyApiException ( // creează o încercare de client ( manageCustomer(c); ) catch (MyBusinessException e) ( aruncă o nouă excepție MyApiException(e, e.getCode()) ) )
Este ușor de observat că acestea clase suplimentare excepțiile nu oferă niciun beneficiu. Ele introduc pur și simplu straturi suplimentare care învelesc excepția. Și deși ar fi distractiv să împachetezi un cadou în o mulțime de hârtie colorată, nu este o abordare bună a dezvoltării software.

Asigurați-vă că adăugați informații

Gândiți-vă doar la codul care trebuie să gestioneze excepția sau la el însuși atunci când trebuie să găsiți problema care a cauzat excepția. Mai întâi trebuie să parcurgeți mai multe straturi de excepții pentru a găsi cauza principală. Și până astăzi nu am văzut niciodată o aplicație care să fi adoptat această abordare și să adauge informatii utile cu fiecare strat de excludere. Ei fie generalizează mesajul și codul de eroare, fie furnizează informații redundante.

Prin urmare, aveți grijă la numărul de clase de excepții personalizate pe care le introduceți. Ar trebui să vă întrebați întotdeauna dacă noua clasa excepții pentru informații suplimentare sau alte beneficii. În cele mai multe cazuri, nu aveți nevoie de mai mult de un nivel de excepții personalizate pentru a realiza acest lucru.

Public void persistCustomer(Customer c) ( // persistă un Client ) public void manageCustomer(Customer c) aruncă MyBusinessException ( // gestionează un Client aruncă un nou MyBusinessException(e, e.getCode()); ) public void createCustomer(Client c) aruncă MyBusinessException ( // creează un Customer manageCustomer(c); )


2. Care este ierarhia excepțiilor.
3. Este posibil/necesar să gestionăm erorile jvm?
4. Care sunt diferitele moduri de a gestiona excepțiile?
5. Ce scrie? cuvânt cheie aruncări?
6. Ce are special blocul finally? Este întotdeauna îndeplinită?
7. Nu poate exista nici un bloc de captură atunci când prindeți excepții?
8. Vă puteți gândi la o situație în care un bloc final nu va fi executat?
9. Un bloc catch poate prinde mai multe excepții (din aceleași ramuri de moștenire și diferite)?
10. Ce știi despre excepțiile bifate/neverificate?
11. Ce este special la RuntimeException?
12. Cum să scrieți propria excepție („personalizată”)? Ce motive te vor ghida atunci când alegi tipul de excepție: bifată/nebifată?
13. Ce operator vă permite să forțați să fie aruncată o excepție?
14. Există condiții suplimentare pentru o metodă care ar putea crea o excepție?
15. Metoda principală poate arunca o excepție extern și, dacă da, unde va fi tratată această excepție?
16. Dacă o instrucțiune return este conținută atât într-un bloc catch, cât și într-un bloc final, care este „mai important”?
17. Ce știți despre OutOfMemoryError?
18. Ce știi despre SQLException? Cărui tip bifat sau nebifat aparține și de ce?
19. Ce este eroarea? Când se utilizează Error? Dați un exemplu de eroare.
20. Ce construct este folosit în Java pentru a gestiona excepțiile?
21. Să presupunem că există un bloc try-finally. A apărut o excepție în blocul try și execuția s-a mutat în blocul final. O excepție a apărut și în blocul finally. Care dintre cele două excepții va „arunca” din blocul try-finally? Ce se întâmplă cu a doua excepție?
22. Să presupunem că există o metodă care poate arunca IOException și FileNotFoundException în ce ordine ar trebui să meargă blocurile catch? Câte blocuri catch vor fi executate?

Răspunsuri

1. Definiți conceptul de „excepție”

Excepţie este o problemă (eroare) care apare în timpul execuției programului. Excepții pot apărea în multe cazuri, de exemplu:

  1. Utilizatorul a introdus date incorecte.
  2. Fișierul pe care programul îl accesează nu a fost găsit.
  3. Conexiunea de rețea la server a fost pierdută în timpul transferului de date. etc.

Toate excepțiile din Java sunt obiecte. Prin urmare, acestea pot fi generate nu numai automat atunci când apare o situație excepțională, ci și create de însuși dezvoltatorul.

2. Care este ierarhia excepțiilor.

Excepțiile sunt împărțite în mai multe clase, dar toate au un strămoș comun - clasa Throwable. Descendenții săi sunt subclasele Excepție și Eroare.

Excepțiile sunt rezultatul unor probleme dintr-un program care sunt, în principiu, rezolvabile și previzibile. De exemplu, împărțirea la zero a avut loc în numere întregi.

Erorile sunt probleme mai grave care, conform specificației Java, nu ar trebui încercate să fie tratate program propriu, deoarece sunt legate de probleme la nivel JVM. De exemplu, excepții de acest fel apar dacă memoria disponibilă pentru mașina virtuală s-a epuizat. Program memorie suplimentarăîncă nu va putea furniza JVM-ul.

În Java, toate excepțiile sunt împărțite în două tipuri: excepții verificate (verificate) și excepții neverificate (neverificate), care includ erori (Erori) și excepții de rulare (RuntimeExceptions, un descendent al clasei Exception).

Excepțiile certificate sunt erori care pot și ar trebui gestionate într-un program toți descendenții clasei Exception (dar nu RuntimeException) aparțin acestui tip;

3. Este posibil/necesar să gestionăm erorile jvm?

O poți procesa, dar nu ar trebui să o faci. Dezvoltatorul nu are instrumente pentru a gestiona erorile de sistem și mașini virtuale.

4. Care sunt diferitele moduri de a gestiona excepțiile?

Java are cinci cuvinte cheie pentru gestionarea excepțiilor:

  1. încerca— acest cuvânt cheie este folosit pentru a marca începutul unui bloc de cod care ar putea duce la o eroare.
  2. captură— un cuvânt cheie pentru a marca începutul unui bloc de cod conceput pentru a intercepta și gestiona excepțiile.
  3. in sfarsit— un cuvânt cheie pentru a marca începutul unui bloc de cod, care este opțional. Acest bloc este plasat după ultimul bloc'captură'. Oricum, controlul este transmis blocului „finally”.
  4. arunca- servește la generarea de excepții.
  5. aruncări

Forma generală a construcției pentru „prinderea” unei situații excepționale este următoarea:

Mai multe detalii http://www.quizful.net/post/java-exceptions

5. Ce înseamnă cuvântul cheie throws?

aruncări— un cuvânt cheie care este scris în semnătura unei metode și denotă că metoda poate arunca o excepție cu tipul specificat.

6. Ce are special blocul finally? Este întotdeauna îndeplinită?

Când se aruncă o excepție, execuția metodei este direcționată de-a lungul unei căi neliniare. Aceasta poate fi o sursă de probleme. De exemplu, o metodă deschide un fișier la intrare și îl închide la ieșire. Pentru a preveni ratarea închiderii fișierelor din cauza gestionării excepțiilor, a fost propus un mecanism in sfarsit.

Cuvânt cheie in sfarsit creează un bloc de cod care va fi executat după finalizarea blocului încerca/prinde, dar înainte de codul care îl urmează. Blocul va fi executat indiferent dacă se aruncă sau nu o excepție. Operator in sfarsit nu este necesar, însă fiecare operator încerca necesită fie captură, sau in sfarsit. Cod în bloc in sfarsit va fi îndeplinită Întotdeauna.

7. Nu poate exista nici un bloc de captură atunci când prindeți excepții?

Această notație este validă dacă există o clauză try() finally(). Dar nu are prea mult sens într-o astfel de intrare, este totuși mai bine să aveți un bloc de captură în care să fie procesată excepția necesară.

Șir x = „z”; încercați ( x="234"; ) în cele din urmă ( x = „În cele din urmă"; )

Șir x = "z" ;

incearca (

x = "234" ;

) in sfarsit (

x = „În sfârșit” ;

8. Vă puteți gândi la o situație în care un bloc final nu va fi executat?

Blocul final nu este întotdeauna executat, de exemplu în această situație:

încercați ( System.exit(0); ) catch(Exception e) ( e.printStackTrace(); ) în cele din urmă ( )

incearca (

Sistem. ieșire(0);

) prinde (Excepția e) (

e. printStackTrace();

) in sfarsit ( )

Aici este în sfârșit inaccesibil, deoarece sistemul iese din program. În termeni generali: atunci când un jvm moare, nu are timp pentru final (de aici puteți veni cu alte exemple despre cum să omorâți un jvm și să răspundeți la întrebarea din titlu).

9. Un bloc catch poate prinde mai multe excepții (din aceleași ramuri de moștenire și diferite)?

ÎN Java 7 A devenit disponibilă o nouă construcție care vă permite să capturați mai multe excepții cu un singur bloc de captură:

încercați ( ... ) catch(IOException | SQLException ex) ( logger.log(ex); aruncați ex; )

incearca (

. . .

) catch (IOException | SQLException ex ) (

logger. log(ex);

arunca ex ;

10. Ce știi despre excepțiile bifate/neverificate?

Toate situațiile excepționale sunt împărțite în „verificate” și „neverificate” (vezi imaginea de la începutul articolului). Această proprietate este inerentă „rizomului” (Throwable, Error, Exception, RuntimeException) și este moștenită. Nu este vizibil în codul sursă al clasei de excepție.
În alte exemple, rețineți că Throwable și Exception și toți descendenții lor (cu excepția descendenților Error și RuntimeException) sunt bifați
- Error și RuntimeException și toți descendenții lor - nebifate
excepție verificată = excepție verificată verificată de compilator.

Subiectul este suficient de larg pentru a se potrivi într-un singur răspuns. De exemplu, puteți vedea exemplele lui Golovach: http://habrahabr.ru/company/golovachcourses/blog/225585/

Și, de asemenea, de la quizful.net

1. Excepțiile verificate sunt cele care trebuie gestionate de un bloc catch sau descrise în semnătura metodei. Nebifat nu poate fi procesat sau descris.
2. Excepții nebifate în Java - moștenite de la RuntimeException, bifate - de la Exception (fără a include debifate).

Excepțiile verificate diferă de excepțiile necontrolate din Java prin aceea că:
1) Disponibilitate/procesare Verificat se verifică excepțiile în stadiul de compilare. Disponibilitate\procesare Nebifat apar excepții in timpul executiei.

11. Ce este special la RuntimeException?

public class RuntimeException extinde Exception - clasa de bază pentru erori de rulare. Se referă la excepții netratate (neprinse\nebifate). După cum se precizează în descrierea clasei, este o superclasă ale cărei excepții pot fi aruncate în timpul funcționării normale a JVM-ului.

12. Cum să scrieți propria excepție („personalizată”)? Ce motive te vor ghida atunci când alegi tipul de excepție: bifată/nebifată?

Trebuie să moșteniți din clasa de bază tipul de excepție necesar (de exemplu, Exception sau RuntimeException).

clasă publică ExcClass extinde Excepție ( private String someString; public ExcClass (String șir) ( this.someString = șir; System.out.println("Exception ExcClass"); ) public void myOwnExceptionMsg() ( System.err.println("This este o excepție de masaj pentru șir: " + someString); ) ) public class TestExc ( public static void main(String args) ( încercați ( String s = "SomeString"; aruncați noi ExcClass(s); ) catch (ExcClass ex) (ex. .myOwnExceptionMsg() ) ) //Excepție de ieșire ExcClass Acesta este un masaj de excepție pentru șir: SomeString

clasa publică ExcClass extinde Excepția (

private String someString ;

public ExcClass(șir șir) (

acest. someString = șir ;

Sistem. afară . println("Excepție ExcClass");

public void myOwnExceptionMsg() (

Sistem. a greșit. println( „Acesta este un masaj cu excepție pentru șir:”+someString);

clasa publica TestExc(

incearca (

String s = "SomeString" ;

arunca noi ExcClass(e);

) prinde (ExcClass ex ) (

ex. myOwnExceptionMsg();

//Concluzie

Excepție ExcClass

Acesta este un masaj de excepție pentru șir: SomeString

Trebuie să vă ghidați după definiția tipului de excepție. În funcție de ceea ce doriți să procesați sau să vedeți, trebuie să moșteniți din clasa dorită.

13. Ce operator vă permite să forțați să fie aruncată o excepție?

aruncă o nouă excepție();

14. Există condiții suplimentare pentru o metodă care ar putea crea o excepție?

Dacă aceasta este o excepție verificată, atunci trebuie declarată în semnătura metodei.

Public void someMethod() aruncă excepție ( )

public void someMethod() aruncă o excepție (

15. Metoda principală poate arunca o excepție extern și, dacă da, unde va fi tratată această excepție?

Poate că va fi transferat la Java Virtual Machine (JVM).

16. Dacă o instrucțiune return este conținută atât într-un bloc catch, cât și într-un bloc final, care este „mai important”?

Se întoarce dintr-un bloc final.

Public static void main(String args) ( String what = method(); System.out.println(what); ) public static String method() ( try ( return "SomeString"; ) finally ( return "Finally message"; ) ) //Ieșire mesajul final

public static void main (Argumente șir) (

String what = metoda () ;

Sistem. afară . println(ce);

Metoda String statică publică() (

incearca (

returnează „SomeString”;

) in sfarsit (

returnează „Mesajul în sfârșit”;

//Concluzie

In sfarsit mesaj

17. Ce știți despre OutOfMemoryError?

OutOfMemoryError este aruncat atunci când mașina virtuală Java nu poate aloca (aloca) un obiect din cauza memoriei insuficiente și colectorul de gunoi nu poate elibera mai mult.

Zona de memorie ocupată de un proces java este formată din mai multe părți. Tipul OutOfMemoryError depinde de care dintre ele a rămas fără spațiu.

1. java.lang.OutOfMemoryError: spațiu heap Java
Nu există suficient spațiu pe heap, care este zona de memorie în care sunt plasate obiectele create programatic în aplicația dvs. Mărimea este specificată de parametrii -Xms și -Xmx. Dacă încercați să creați un obiect și nu mai rămâne spațiu în heap, veți primi această eroare. De obicei, problema constă într-o scurgere de memorie, dintre care există foarte multe, iar Internetul este pur și simplu plin de articole pe acest subiect.

2. java.lang.OutOfMemoryError: spațiu PermGen
Această eroare apare atunci când nu există suficient spațiu în zona Permanent, a cărei dimensiune este specificată de parametrii -XX:PermSize și -XX:MaxPermSize.

3. java.lang.OutOfMemoryError: limita generală GC a fost depășită
Această eroare poate apărea atât atunci când prima cât și a doua zonă sunt depășite. Se datorează faptului că a rămas puțină memorie și GC-ul funcționează constant, încercând să elibereze spațiu. Această eroare poate fi dezactivat folosind parametrul -XX:-UseGCOverheadLimit, dar, bineînțeles, nu ar trebui să fie dezactivat, ci fie să rezolve problema scurgerii memoriei, fie să aloce mai mult spațiu, fie să schimbe setările GC.

4. java.lang.OutOfMemoryError: nu se poate crea un fir nativ nou

Aruncat atunci când nu mai pot fi create fire.

Mai multe detalii în articolul http://habrahabr.ru/post/117274/

18. Ce știi despre SQLException? Cărui tip bifat sau nebifat aparține și de ce?

SQLException oferă informații despre erorile de acces la baza de date sau alte erori legate de bazele de date.

SQLException aparține excepțiilor verificate, ceea ce înseamnă că este verificată în etapa de compilare.

Dezbaterea despre acest tip de excepție este că dezvoltatorul trebuie să gestioneze în mod constant această excepție în cod, deși majoritatea erorilor apar în timpul execuției programului, adică, potrivit multora, ar fi mai bine să o clasifice ca excepții de rulare neverificate.

încercați ( // faceți niște apeluri SQL ) catch (SQLException e) ( // înregistrați returnarea excepției; // și renunțați)

incearca (

// faceți niște apeluri SQL

) catch ( SQLException e ) (

//Înregistrează excepția

întoarcere; // si renunta

Argumentul lui Joshua Bloch din Effective Java Second Edition este că testarea SQLException este o încercare de a forța dezvoltatorii să gestioneze excepția și să o înglobeze într-un nou nivel de abstractizare.

19. Ce este eroarea? Când se utilizează Error? Dați un exemplu de eroare.

Erorile sunt probleme mai grave pe care specificația Java prevede că nu ar trebui să încercați să le gestionați în propriul program, deoarece sunt probleme la nivel de JVM. De exemplu, excepții de acest fel apar dacă memoria disponibilă pentru mașina virtuală s-a epuizat.

De exemplu, uitați-vă la imaginea ierarhiei excepțiilor de la începutul articolului. Ca exemplu - OutOfMemoryError.

20. Ce construct este folosit în Java pentru a gestiona excepțiile?

Puteți utiliza try-catch-finally și cu Java 7 try-with-resources. Prima cale:

try( //aici este codul care ar putea duce la o eroare) catch(SomeException e)( //în paranteze este indicată clasa erorii specifice așteptate //acțiunile care vizează gestionarea excepțiilor sunt descrise aici) finally( //executat în orice caz (blocarea în sfârșit este opțională))

Încercați cu resurse:

Vechiul mod BufferedReader br = new BufferedReader(new FileReader(cale));

încercați ( return br.readLine(); ) în cele din urmă ( dacă (br != null) ( br.close(); ) ) JDK 7 încercați (BufferedReader br = new BufferedReader(new FileReader(cale))) ( return br.readLine ();

Vechiul mod

incearca (

BufferedReader br = new BufferedReader(new FileReader(cale));

) in sfarsit (

întoarce br . readLine();

dacă (br != nul ) (

br. aproape();

JDK 7

încercați (BufferedReader br =

BufferedReader br = new BufferedReader(new FileReader(cale));

BufferedReader nou (nou FileReader (cale) ) (

Vedeți, de asemenea, răspunsul la „Care sunt modalitățile de a gestiona excepțiile?”

21. Să presupunem că există un bloc try-finally. A apărut o excepție în blocul try și execuția s-a mutat în blocul final. O excepție a apărut și în blocul finally. Care dintre cele două excepții va „arunca” din blocul try-finally? Ce se întâmplă cu a doua excepție?

clasă publică TestExc ( public static void main(String args) ( Excepție ex = twoExceptionsMethod(); System.out.println(ex.getClass()); String s = twoExceptionsMethod2(); System.out.println(s); ) public static Exception twoExceptionsMethod() ( try ( return new IndexOutOfBoundsException (); ) finally ( return new NullPointerException (); ) ) public static String twoExceptionsMethod2() ( try ( throw new NullPointerException(); ) catch (NullPointerException ex) (Sistem. out.println(ex.getMessage()+ " catchBlock");; în final ( Exception ex2 = new Exception(); return ex2.getMessage() + "finallyBlock"; ) ) ) //Ieșire clasa java.lang.NullPointerException null catchBlock null finallyBlock

clasa publica TestExc(

public static void main (Argumente șir) (

Excepție ex = twoExceptionsMethod();

Sistem. afară . println(ex. getClass());

Orice program va funcționa stabil doar dacă cod sursă este depanat și nu conține condiții care ar putea provoca situații neașteptate. Procesul de detectare a eventualelor defecțiuni se realizează în etapa de programare. Pentru a face acest lucru, dezvoltatorul ia în considerare toate rezultatele posibile și încearcă să limiteze efectul erorii, astfel încât să nu perturbe funcționarea programului sau să îl provoace blocarea.

Când poate fi necesară gestionarea excepțiilor

În Java, excepțiile pot fi cauzate de introducerea incorectă a utilizatorului, absența unei resurse necesare pentru rularea programului sau oprire bruscă retelelor. Pentru utilizarea confortabilă a aplicației create de dezvoltator, este necesar să se controleze apariția situațiilor de urgență. Consumatorul nu trebuie să aștepte ca un program blocat să se finalizeze, să piardă date din cauza excepțiilor necontrolate sau pur și simplu să primească mesaje frecvente că ceva a mers prost.

Gestionarea excepțiilor Java

Ce trebuie să iei în considerare? limbajul Java are propria sa funcționalitate încorporată de gestionare a excepțiilor. Desigur procent mare erorile sunt surprinse în etapa de compilare, când sistemul raportează automat că nu mai poate fi folosit. Dar există și un tip de excepție care apare în timp ce programul rulează. Dezvoltatorul trebuie să fie capabil să anticipeze acest lucru și să proiecteze codul în așa fel încât să nu provoace o eroare, ci mai degrabă să îl gestioneze într-un mod special sau să transfere controlul către o altă ramură.

În Java, o astfel de captare a excepțiilor este impusă de compilator, deci probleme tipice sunt cunoscute și au propriile lor schema standard execuţie.

Excepții tipice

Cel mai mult exemplu simplu, în care puteți obține o excepție este diviziunea. În ciuda simplității sale, expresia poate conține zero ca divizor, ceea ce va duce la o eroare. Este bine dacă apariția sa poate fi prezisă mai devreme și prevenită. Dar această opțiune nu este întotdeauna disponibilă, așa că prinderea excepției trebuie organizată imediat când apare o „diviziune la zero”.

În Java, mecanismul de gestionare a erorilor arată astfel:

  • un obiect excepție este creat pe heap, la fel ca oricare altul;
  • cursul natural al programului este întrerupt;
  • mecanismul de excepție încearcă să găsească o modalitate alternativă de a continua codul;
  • După ce a găsit un loc pentru executarea în siguranță a programului în handler, lucrarea fie va fi restabilită, fie excepția va fi implementată într-un mod special.

Cel mai simplu exemplu de creare a unei erori poate arăta astfel:

aruncă o nouă excepție NullPointerException();

Aici variabila a este verificată pentru inițializare, adică. dacă referința la obiect este nulă. Dacă apare o astfel de situație și este nevoie de o gestionare specială, o excepție este aruncată folosind throw new NullPointerException().

Câteva detalii despre cuvintele cheie

Când lucrați cu excepții, deseori trebuie să utilizați cuvinte cheie Java pentru a indica o anumită acțiune. Există cinci dintre ele în acest limbaj de programare:

  • Încerca. a fost deja întâlnit și înseamnă o tranziție la o secțiune de cod care poate genera o excepție. Blocul este delimitat de acolade ().
  • Captură. Captează tipul de excepție dorit și îl gestionează în consecință.
  • In sfarsit. Acest cuvânt cheie este opțional și servește la executarea unei anumite secțiuni de cod care este necesară în orice caz, chiar dacă nu este prinsă nicio excepție. Adăugat direct după blocul de încercare.
  • Throw - Vă permite să aruncați excepții Java oriunde în cod.
  • Throws este un cuvânt cheie care este inclus în semnătura metodei. Înseamnă că codul ulterior poate arunca o excepție Java de tipul specificat. O astfel de etichetă servește ca un semnal pentru dezvoltatori că trebuie să țină cont de faptul că este posibil ca metoda să nu funcționeze conform așteptărilor.

Prinde cu încercare

Aruncarea unei excepții în Java presupune în mod natural că aceasta va fi gestionată într-un mod special. Cel mai convenabil mod de a face acest lucru este dacă o secțiune de cod este îngrădită într-un anumit bloc. Care poate conține o excepție. La executarea unui astfel de cod, mașina virtuală va găsi o situație neașteptată, va înțelege că se află într-un bloc critic și va transfera controlul în secțiunea de procesare.

În Java, codul este împachetat într-un bloc special de încercare, în cadrul căruia poate fi aruncată o excepție. Astfel, în el sunt plasate deodată mai multe situații neprevăzute, care vor fi prinse într-un singur loc, fără a se răspândi în întregul cod.

Codul cel mai tipic cu un bloc de procesare arată astfel:

//Aici va fi definit codul care poate arunca o exceptie

) catch (Exception_type_1 identifier_1) (

) catch (Exception_type_2 identifier_2) (

//Excepția este procesată aici, după tipul și condițiile acesteia;

Cuvântul cheie catch indică faptul că codul care este capturat de testul de excepție trebuie procesat așa cum este descris în continuare, cu condiția să se potrivească cu tipul său. Identificatorul poate fi folosit în cadrul unui bloc de cod de procesare ca argumente.

In sfarsit

După cum a fost clar din capitolul anterior, blocurile catch captează excepțiile și le gestionează. Dar de foarte multe ori apare o situație în care trebuie executat un anumit cod, indiferent dacă au fost surprinse erori. Există în sfârșit un cuvânt cheie pentru asta. Este folosit pentru a incrementa diferite contoare, pentru a închide fișiere sau pentru a închide conexiunile de rețea.

Această secțiune prezintă mai multe blocuri de captură cu metode inventate pentru capturarea excepțiilor. De exemplu, codul conținut în try generează o situație neașteptată precum Cold. Apoi expresiile „Caught cold!” vor fi afișate în consolă. și „Este ceva de încurajat?” Adică blocul final este executat în orice caz.

Există de fapt o modalitate de a evita să alergi în cele din urmă. Este asociat cu oprirea mașinii virtuale. Puteți afla cum să implementați acest lucru pe Internet.

aruncare cuvânt cheie

Throw aruncă o excepție. Sintaxa sa arată astfel:

arunca noua NewException();

Aici este creată o nouă excepție cu tipul NewException(). Clasele care sunt deja incluse în bibliotecile standard Java și cele definite anterior de producția proprie a dezvoltatorului pot fi folosite ca tip.

Această construcție este inclusă în descrierea unei metode, care trebuie apoi apelată în cadrul unui bloc try pentru a o putea intercepta.

aruncă cuvântul cheie

Ce trebuie făcut dacă în timpul procesului de dezvoltare apare o situație în care o metodă poate arunca o excepție, dar nu o poate gestiona corect. Pentru a face acest lucru, semnătura metodei specifică cuvântul aruncă și tipul de excepție posibilă.

Această etichetă este un fel de indicator pentru dezvoltatorii clienți că metoda nu este capabilă să gestioneze propria excepție. În plus, dacă tipul de eroare este testabil, compilatorul vă va forța să indicați acest lucru în mod explicit.

Încercați cu resurse

ÎN versiuni Java 7, dezvoltatorii au inclus o inovație atât de importantă precum procesarea unui bloc de încercare cu resurse.

Multe obiecte create în Java trebuie să fie închise după ce sunt folosite pentru a economisi resurse. Anterior, trebuia să luăm în considerare acest lucru și să oprim manual astfel de instanțe. Acum au interfața AutoClosable. Ajută la închiderea automată a obiectelor deja folosite plasate într-un bloc de încercare. Datorită acestei abordări, scrierea codului a devenit mai convenabilă, iar lizibilitatea sa a crescut semnificativ.

Clasele native de excepție Java

Creatorii limbajului de programare descris au ținut cont de multe aspecte atunci când au proiectat tipuri de situații neprevăzute. Cu toate acestea, nu va fi posibil să preveniți toate rezultatele posibile ale evenimentelor, astfel încât Java implementează capacitatea de a vă defini propriile excepții care sunt potrivite în mod specific pentru nevoile unui anumit cod.

Cel mai simplu mod de a-l crea este de a moșteni de la obiectul care este cel mai potrivit pentru context.

Aceasta moștenește de la Exception, o clasă care este folosită pentru a defini excepții personalizate. MyException are doi constructori - unul implicit, al doilea cu un argument msg de tip String.

Apoi clasa publică FullConstructors implementează o metodă f a cărei semnătură conține MyException. Acest cuvânt cheie înseamnă că f poate arunca o excepție tip Java MyException. Mai departe, în corpul metodei este produsă rezultatul informații text la consolă și generarea actuală a MyException în sine, folosind throw.

A doua metodă este ușor diferită de prima prin faptul că, atunci când este creată o excepție, i se transmite un parametru șir, care se va reflecta în consolă atunci când este prins. În principal, puteți vedea că f() și g() sunt plasate într-un bloc try și cuvântul cheie catch este configurat pentru a captura MyException. Rezultatul procesării va fi rezultatul unui mesaj de eroare către consolă:

Astfel am reușit să adăugăm excepții Java create de noi înșine.

Arhitectură de excepție

Ca toate obiectele din Java, excepțiile sunt, de asemenea, moștenite și au structura ierarhică. Elementul rădăcină al tuturor erorilor aruncate în acest limbaj de programare este clasa java.lang.Throwable. Două tipuri sunt moștenite de la acesta - Eroare și Excepție.

Eroare - notifică despre erori criticeși reprezintă excepțiile neverificate ale Java. Interceptarea și prelucrarea unor astfel de date au loc în majoritatea cazurilor în stadiul de dezvoltare și nu trebuie să fie implementate în codul final al aplicației.

Clasa cel mai frecvent utilizată pentru crearea și analiza excepțiilor este Exception. Care, la rândul său, este împărțit în mai multe ramuri, inclusiv RuntimeException. RuntimeException se referă la excepțiile de rulare, adică cele care apar în timp ce programul rulează. Toate clasele moștenite de la acesta sunt neverificabile.

Excepții comune

În Java, excepțiile, a căror listă este prezentată mai jos, sunt utilizate cel mai des, așa că merită să descrieți fiecare dintre ele mai detaliat:

  • ArithmeticException. Aceasta include erori legate de operațiile aritmetice. Cel mai frapant exemplu este împărțirea la zero.
  • ArrayIndexOutOfBoundsException - acces la numărul unui element de matrice care depășește lungimea sa totală.
  • ArrayStoreException - A fost făcută o încercare de a atribui un element de matrice unui tip incompatibil.
  • ClassCastException - o încercare de a arunca incorect un tip în altul.
  • IllegalArgumentException - Un argument nevalid a fost folosit într-un apel de metodă.
  • NegativeArraySizeException - excepție la crearea unei matrice de dimensiune negativă.
  • NullPointerException - utilizarea incorectă a unei referințe nule.
  • NumberFormatException - Apare atunci când un șir este convertit incorect într-un număr.
  • UnsupportedOperationException - operația nu este acceptată.

Aceste exemple sunt tipuri de excepții Java nebifate. Și așa arată cele bifate:

  • ClassNotFoundException - clasa nu a fost găsită.
  • IllegalAcccessException - restricție de acces la clasă.
  • InterruptedException - întreruperea firului de execuție.
  • NoSuchFieldException - Câmpul obligatoriu nu există.

Interpretarea excepției

Vorbind despre excepțiile frecvent întâlnite, trebuie remarcat faptul că interpretarea lor în timpul dezvoltării poate fi interpretată incorect. Mai jos este o listă scurtă care explică mai detaliat când poate apărea o situație neașteptată.

NullPointerException. Prima dată când se aruncă o excepție este atunci când este accesată o referință de obiect care este nulă. Acest lucru se aplică și metodelor instanței nule a clasei. NullPointerException poate fi, de asemenea, aruncată dacă lungimea matricei este nulă. Verificarea periodică a obiectelor pentru null va ajuta la evitarea unor astfel de situații.

ArrayIndexOutOfBoundsException. Orice program nu poate exista fără a folosi matrice. În consecință, accesul frecvent la acestea poate genera și erori. O excepție apare atunci când dezvoltatorul încearcă să acceseze un element de matrice care nu se află în lista de indexuri. De exemplu, valoarea cerută este mai mare decât lungimea sau mai mică decât zero. Foarte des apare ca urmare a faptului că numărarea în matrice începe de la zero.

Concluzii

Gestionarea excepțiilor Java − instrument puternic mediu, care facilitează foarte mult munca programatorului și îi permite să creeze cod curat și fără erori. Statutul și reputația companiei dezvoltatoare depind de cât de bine și de stabil funcționează aplicația.

Desigur, mai mult sau mai puțin programe simple urmărirea situațiilor de urgență este mult mai ușoară. Dar în complexele automate mari cu câteva sute de mii de linii, acest lucru este posibil doar ca urmare a depanării și testării îndelungate.

Pentru excepțiile Java, care provoacă erori în unele aplicații, unele companii oferă recompense pasionaților care le găsesc. Sunt apreciate în special cele care provoacă o încălcare a politicii de securitate a pachetului software.

După cum știți, excepțiile sunt evenimente care au loc în timpul execuției programului. Aceste evenimente perturbă cursul normal al lucrurilor.

încercați blocați, blocați prindeți

Partea din cod în care poate apărea o excepție este acoperită de un bloc try.

Operatorii de excepție sunt declarați în blocul catch care urmează imediat blocul try.

Pot exista mai multe blocuri catch pentru un singur bloc de încercare.

Blocul catch tratează excepțiile, iar argumentul său specifică tipul de excepție care poate fi gestionată. acest bloc, adică tipul argumentului este tipul excepției. Codul scris în blocul catch este handlerul de excepții.

în sfârșit blocați

După blocul (blocurile de excepție), poate exista un bloc în sfârșit. Un caz acceptabil este atunci când nu există blocuri de captură, dar există un bloc în final. În cele din urmă, codul bloc este întotdeauna executat, nu doar atunci când apare o excepție. Puteți efectua acțiuni finale obligatorii, curățare, cum ar fi închiderea unui flux, în el, mai degrabă decât într-un bloc de încercare. După ce, în sfârșit, execuția programului continuă cu următoarea linie de cod.

Schematic, totul arată astfel:

Public void aFunc() ( încercați ( //code ) catch(TypeException e) ( //codul de gestionare a excepțiilor de tip //TypeException; ) catch(SecondTypeException e) ( //codul de gestionare a excepțiilor de tip //SecondTypeException; ) finally ( // acțiuni finale obligatorii. //Codul blocului finally //este întotdeauna executat, și nu numai //când apare o excepție.

sau poate fără blocuri de prindere, așa:

Public void aFunc() ( try ( //code ) finally ( //acțiuni finale obligatorii. //Codul blocului finally //este întotdeauna executat, și nu numai //când apare o excepție. ) )

sau fără blocul final:

Public void aFunc() ( try ( //code ) catch(TypeException e) ( //type exception handler code //TypeException; ) )

Să aruncăm o privire mai atentă la ce se întâmplă atunci când apare o excepție.

Când apare o situație excepțională, este generat un obiect excepție care conține informații despre această excepție, care este transmisă sistemului. În astfel de cazuri, se spune că partea corespunzătoare a programului face o excepție, de exemplu. generează un obiect excepție și îl transmite sistemului. Apoi, sistemul începe să funcționeze, dar înainte de a-l privi, trebuie să înțelegem ce este o stivă de apeluri.

Medalion

Stack de apeluri

Stack de apeluri este o secvență de apeluri de metodă, pornind de la metoda principală până la metoda de interes pentru noi. Să ne uităm la un exemplu ipotetic. Există o clasă:

Clasa publică AClass ( public AClass() () public void methodC() ( ) public void methodB() ( methodC(); ) public void methodA() ( încercați ( methodB(); ) catch(AnException e) ( System.out .println(e.getMessage()) ) public static void main(String args) ( AClass ac = new Aclass(); ac.methodA(); ) )

Aici stiva de apeluri astfel: principal apelează metodaA(), metodaA() apelează metodaB(), metodaB() apelează metodaC().

Sfârșitul barei laterale

Să continuăm să studiem acțiunile sistemului după ce primește un obiect excepție (presupunând că tipul obiectului excepție este AnException) aruncat printr-o metodă. Fie aceasta metoda metodaС(), vezi bara laterală " Stack de apeluri„mai sus. Sistemul începe să navigheze stiva de apeluri pentru methodС() în ordine inversă, adică pornind de la metoda methodС() în sine, se deplasează în direcția principal. Scopul acestei scanări este de a găsi handler-ul de excepții care a apărut în methodC(). În primul rând, sistemul se uită la methodC(), dacă nu are handlerul de excepții necesar, atunci trece la methodB(), dacă nu are, atunci trece la methodA(). methodA() conține un handler de tip AnException și acestui handler sistemul îi transmite obiectul excepție pentru procesare. Se spune că handler-ul prinde excepția. Dacă sistemul nu a găsit un handler de excepție de tipul necesar, atunci programul se va încheia.

Dacă metoda A() ar avea mai multe blocuri de captură, sistemul ar selecta primul bloc de potrivire, adică. un bloc al cărui tip de argument se potrivește cu tipul excepției.

Trei categorii de excepții

Excepții verificate. De exemplu, erori de introducere. Se recomandă gestionarea unor astfel de excepții;

Eroare. Acestea sunt excepții cauzate de motive externe aplicației și aplicația, de regulă, nu le gestionează. Astfel de excepții sunt definite de clasă Eroare sau subclasele sale;

Excepție de rulare. De exemplu, erori în cod. Astfel de excepții sunt definite de clasă RuntimeException sau subclasele sale. Aceste excepții pot fi gestionate.

Sunt numite excepții ale celui de-al doilea și al treilea tip excepții necontrolate.

Este posibil ca metoda să nu gestioneze excepția, dar, presupunând că aceasta ar putea apărea, împingeți-o în stiva de apeluri pentru procesare. Apoi în declarația de metodă este scris operatorul aruncări iar în el, separate prin virgule, o listă de posibile tipuri de excepții. Exemplu:

Metoda public voidC(int a) aruncă AnException ( //code; )

Metoda în sine poate arunca o excepție. Pentru a face acest lucru, utilizați operatorul aruncași obiectul excepție din acesta. Exemplu:

Metoda public voidC(int a) aruncă o excepție (if(a< 10) { throw new AnException("Error in methodC"); } }

Dacă în acest exemplu a< 10, то будет выброшено исключение AnException, так, как если бы здесь произошла соответствующая ошибка.

Aruncă operator de excepție arunca Este posibil și din corpul altui handler de excepții. Așa apare excepții înlănțuite. Exemplu:

Public void methodA() ( încercați ( methodB(); ) catch(AnException e) ( System.out.println(e.toString()); aruncați nou NextException("metodaA aruncă NextException."); ) )

Toate clasele de excepție revin la clasă Aruncabil. Descendenții săi imediati sunt clasele EroareŞi Excepţie. Din Excepţie se întâmplă RuntimeExceptionși toate clasele de excepții controlate.

Știm deja că excepții ca Eroare procesate de sistem, de obicei nu le atingem.

Tipul excepțiilor RuntimeException vorbim despre erorile din cod. Astfel de excepții pot fi gestionate, dar este mai bine să remediați pur și simplu erorile de cod.

Tipul excepțiilor Excepţie ei spun că există probleme, dar nu sunt grave sistemice. Astfel de erori ar trebui tratate.

Puteți crea propriile clase de excepție ca descendenți direcți sau nu Excepţie. Se obișnuiește să se adauge cuvântul la numele unor astfel de clase Excepţie.

Dacă tipul de argument al operatorului catch este Excepţie, atunci handlerul de excepții corespunzător va putea prinde toate excepțiile verificate și excepțiile de tip RuntimeException. Aceasta este ceea ce poți face dacă nu cerințe speciale la handler sau dacă pot apărea excepții neașteptate. Dar dacă este necesar abordare specială, atunci este mai bine să folosiți moștenitori Excepţie.

Cum să creați singur o clasă de excepție?

Deoarece trebuie să gestionăm excepțiile verificate, vom moșteni clasa noastră de la Excepţie.

Exemplu

În concluzie, vă prezint exemplul complet de cod care a fost discutat în această secțiune. Clasa principala:

Pachetul exceptionTest.test;< 10) { throw new AnException("Error in methodC"); } } public void methodB() throws AnException { methodC(1); } public void methodA() { try { methodB(); } catch(AnException e) { System.out.println(e.toString()); throw new NextException("methodA throws NextException."); } } public static void main(String args) { TestClass tc = new TestClass(); try { tc.methodA(); } catch(NextException ex) { System.out.println(ex.toString()); } finally { System.out.print("Message from finally: The end."); } } }

clasă publică TestClass ( public TestClass() ( ) public void methodC(int a) aruncă AnException ( if(a)

Clasa de excepție AnException:

Clasa publică AnException extinde Excepție ( private static final long serialVersionUID = 1L; private String exceptionMessage; AnException() ( exceptionMessage = null; ) AnException(String exceptionMessage) ( this.exceptionMessage = exceptionMessage; ) public String toString() ( returnează „Mesaj de la AnException: " + exceptionMessage; ) )

Clasa de excepție NextException:

  • Pachetul exceptionTest.test;

    un fel de recenzie „scurtă”... de parcă s-ar grăbi undeva