Excepții Java. Situații excepționale în Java - excepție și eroare

31.07.2019 Photoshop

Acest articol discută mecanismul de gestionare a excepțiilor utilizat în Java. O excepție în Java este un obiect care descrie o condiție excepțională care a apărut într-o parte a codului programului. Când apare o excepție, este creat un obiect al clasei Excepţie. Acest obiect este transmis metodei care procesează acest tip situatie exceptionala. Pot fi ridicate și excepții pentru a raporta anumite situații anormale.

Excepție cuvintele cheie încercați, prindeți, aruncați, aruncați, în sfârșit

Mecanismul de excepție în Java este susținut de cinci cuvinte cheie:

  • captură,
  • arunca
  • aruncări
  • in sfarsit.

Mai jos este forma generală a unui bloc de gestionare a excepțiilor.

Încercați ( // bloc de cod ) catch ( e) ( // handler de excepții de tip ExceptionType1 ) catch ( e) ( // handler de excepții de tip ExceptionType2 ) în cele din urmă ( // ... )

Tipuri de excepții

În partea de sus a ierarhiei excepțiilor se află clasa Aruncabil, care este moștenit de la Obiect. Fiecare dintre tipurile de excepții este o subclasă de Throwable. Doi descendenți imediati ai clasei Throwable împart ierarhia subclaselor de excepție în două ramuri distincte. Ierarhia claselor este prezentată în figură.

Clasă Excepţie folosit pentru a descrie situații de excepție care trebuie surprinse de codul utilizatorului. Clasă Eroare este destinat să descrie situații excepționale care în condiții normale nu ar trebui să fie prinse într-un program de utilizator.

Excepții neprinse

Obiectele de excepție sunt create automat de runtime Java atunci când apar anumite excepții. Un exemplu de program în care creăm o excepție la împărțirea la zero.

mostre de ambalaj; clasa TestException ( public static void main(String args) ( int d = 0; int a = 42 / d; System.out.println ("a = " + a); ) )

Următorul mesaj va fi imprimat pe consolă.

Excepție în firul „principal” java.lang.ArithmeticException: / prin zero la samples.TestException.main(TestException.java:8)

Rețineți că tipul de excepție aruncat nu a fost Excepţie si nu Aruncabil. Aceasta este o subclasă a clasei Excepţie, si anume: ArithmeticException, explicând ce eroare a apărut în timpul executării programului.

Să schimbăm clasa adăugând o metodă statică subrutină, în care vom crea aceeași situație excepțională.

mostre de ambalaj; clasă publică TestException ( static void subroutine() ( int d = 0; int a = 10 / d; System.out.println ("a = " + a); ) public static void main(String args) ( TestException.subroutine( ) )

Mesajul de execuție a programului arată cum se execută gestionarea excepțiilor sisteme Java imprimă conținutul întregii stive de apeluri.

Excepție în firul „principal” java.lang.ArithmeticException: / cu zero la samples.TestException.subroutine(TestException.java:8) la samples.TestException.main(TestException.java:14)

Prinderea excepțiilor de încercare/prindere

Pentru a proteja codul programului de excepții, trebuie să utilizați blocuri asociate cu cuvinte cheie incearca sa prinzi ; catch este plasat imediat după blocul de încercare. Blocul catch specifică tipul de excepție care trebuie tratată.

Clasa TestException ( public static void main(String args) ( try ( int d = 0; int a = 42 / d; ) catch (ArithmeticException e) ( System.out.println("diviziune cu zero"); ) ) )

Scopul celor mai bine concepute captură-secțiunile ar trebui să proceseze excepția apărută și să aducă variabilele programului într-o stare rezonabilă - astfel încât programul să poată fi continuat ca și cum nu ar fi apărut nicio eroare (în exemplul nostru, este afișat un avertisment - împărțire la zero).

Secțiuni de captură multiple

ÎN în unele cazuri un bloc de cod poate arunca excepții diverse tipuri. Pentru a localiza procesarea unor astfel de situații, puteți folosi mai multe captură-partitii pentru unul încercați să blocați. Blocurile celor mai specializate clase de excepție trebuie să fie pe primul loc, deoarece nu se va ajunge la nicio subclasă dacă sunt plasate după superclasă.

Următorul exemplu prinde două tipuri diferite de excepții, cu acești doi handlere specializate urmate de o secțiune captură scop general, interceptând toate subclasele clasei Aruncabil.

Clasa MultiCatch ( static int c = ( 1 ); public static void main(String args) ( try ( int a = args.length; System.out.println("a = " + String.valueOf(a))); int b = 23 / a; c = 33; ) catch (ArithmeticException e) ( System.out.println("ArithmeticException: " + e.getMessage()); ) catch(ArrayIndexOutOfBoundsException e) ( System.out.println("ArrayIndexOutOfBound " + e.getMessage()); ) ) )

Acest exemplu, atunci când rulează fără parametri, ridică o excepție de împărțire la zero. Dacă în linie de comandă vor fi definiți unul sau mai mulți parametri, setând astfel „a” la o valoare mai mare decât zero, apoi va fi ridicată o excepție de index în afara limitelor ArrayIndexOutOfBounds. Mai jos sunt rezultatele acestui program care rulează în ambele moduri.

A = 0 div cu 0: java.lang.ArithmeticException: / cu zero a = 1 index matrice oob: java.lang.ArrayIndexOutOfBoundsException:33

Instrucțiuni de încercare imbricate

Operatori încerca pot fi imbricate unul în celălalt. Dacă operatorul încerca nivel scăzut nicio sectiune captură corespunzătoare excepției aruncate, stiva va fi extinsă cu un pas mai sus și secțiunile catch ale instrucțiunii exterioare try vor fi verificate pentru a găsi un handler potrivit. Exemplu de imbricare a două declarații incearca sa prinzi unul în celălalt prin apelarea unei metode.

Clasa MultiNest ( static int c = ( 1 ); static void checkArray() ( încercați ( c = 33; ) catch(ArrayIndexOutOfBoundsException e) ( System.out.println "ArrayIndexOutOfBoundsException: " + e.getMessage()); ) ) public static void main(String args) ( try ( int a = args.length(); System.out.println("a = " + a); int b = 23 / a; checkArray(); ) catch (ArithmeticException e) ( System.out.println("ArithmeticException: " + e.getMessage()); ) ) )

Aruncând excepții

Un program poate arunca în mod explicit o excepție folosind instrucțiunea arunca. După executarea instrucțiunii arunca procesul de execuție a programului este suspendat și instrucțiunile ulterioare nu sunt executate. JVM se uită la blocurile din apropiere încearcă...prind, corespunzătoare tipului de excepție, pentru „transfer control”. Dacă nu este găsit un bloc adecvat, handlerul de excepții va opri programul și va „tipări” starea stivei de apeluri.

Exemplu de excepție în care obiectul excepție este mai întâi aruncat, apoi instrucțiunea arunca ridică o excepție, după care se ridică din nou aceeași excepție - de data aceasta prin codul secțiunii care a prins-o prima dată captură.

Clasa TestThrow ( static void method() ( încercați ( throw new NullPointerException ("Excepție în metodă"); ) catch (NullPointerException e) ( System.out.println(e.getMessage()); throw e; ) ) public static void main(String args) ( try ( method(); ) catch(NullPointerException e) ( System.out.println("Catch inside main: " + e.getMessage()); ) ) )

Rezultatul rulării programului este prezentat mai jos.

Excepție în metodă Catch inside main: Excepție în metodă

Declararea unei excepții de aruncare

Dacă o metodă poate arunca excepții pe care nu le gestionează ea însăși, trebuie să declare acest lucru, astfel încât alte metode care o apelează să se poată proteja de aceste excepții. Pentru a specifica o listă de excepții care pot fi ridicate printr-o metodă, utilizați cuvânt cheie aruncări.

Dacă metoda este explicită (adică folosind operatorul arunca) ridică o excepție, tipul clasei de excepție trebuie specificat în instrucțiune aruncăriîn declaraţia acestei metode. Luând în considerare acest lucru, sintaxa definiției unei metode ar trebui descrisă după cum urmează:

Clasa publică TestThrow ( static void method() aruncă IllegalAccessException ( try ( System.out.println ("în interiorul metodei")); aruncă o nouă IllegalAccessException ("Excepție în metodă"); ) catch (NullPointerException e) ( System.out.println( e.getMessage()); ) public static void main(String args) ( try ( method(); ) catch(IllegalAccessException e) ( System.out.println("Catch inside main: " + e.getMessage()) ;)))

Rezultatul exemplului:

Metoda interior Catch inside main: Excepție în metodă

în sfârșit cuvânt cheie

În cazul în care este necesar să se garanteze executarea unei anumite secțiuni de cod, trebuie să utilizați cuvântul cheie in sfarsit. Utilizarea Comunicarii incearca... in sfarsit vă permite să vă asigurați că codul este executat indiferent de excepțiile aruncate și prinse, chiar și în cazurile în care metoda nu are o secțiune catch corespunzătoare excepției aruncate.

Fiecare secțiune încerca trebuie să fie conform cel puţin sau o secțiune captură sau bloc in sfarsit. Un bloc final este foarte util pentru închiderea fișierelor și eliberarea oricăror alte resurse care au fost păstrate pentru utilizare temporară la începutul execuției unei metode.

Mai jos este un exemplu de clasă cu două metode care se completează prin diverse motive, dar în ambele codul de secțiune este executat înainte de a ieși in sfarsit.

Clasa publică TestFinally ( static void methodA() ( încercați ( System.out.println ("în interiorul metodei A")); aruncați o nouă excepție RuntimeException ("Excepție în metoda A"); ) în cele din urmă ( System.out.println ("în final în interiorul metodeiA") ; ) ) static void methodB() ( try ( System.out.println("inside methodB"); return; ) finally ( System.out.println("finally inside methodB"); ) ) public static void main(String args ) ( încercați ( methodA(); ) catch (Excepția e) ( System.out.println(„Prinți excepția în interiorul principal”); ) methodB(); ) )

În exemplul de testare, este ridicată o excepție în metoda A. Dar înainte de a părăsi blocul prematur încerca, secțiunea rulează in sfarsit. Cea de-a doua metodă metodaB completează munca în încerca-blocare de către operator reveni, dar chiar înainte de a ieși din metodă, codul de program al blocului este executat in sfarsit. Rezultatul exemplului de testare:

În interiorul metodeiA, în cele din urmă, în interiorul metodeiA Prindeți excepția în interiorul principal în interiorul metodeiB, în final, în interiorul metodeiB

Gestionarea excepțiilor în Java oferă un mecanism extrem de puternic de gestionare programe complexe. Cuvinte cheie încercați, aruncați, prindeți vă permit să gestionați erorile și diversele situații anormale din program.

Excepție moștenire

captură- design polimorf, i.e. catch by type parent captează excepțiile de orice tip care sunt Parent.

Clasa publică TestException ( public static void main(String args) ( try ( System.err.print ("nivel 0")); aruncă un nou RuntimeException (); System.err.print ("nivel 1"); ) catch (Excepție e ) ( // prind Exception CATCHING RuntimeException System.err.print("nivelul 2"); ) System.err.println("nivelul 3" ) )

Ca rezultat, vom vedea în consolă

Nivelul 0 Nivelul 2 Nivelul 3

Eroare și Excepţie din ramuri paralele de moştenire din Aruncabil, așa că prindeți un frate nu puteți prinde un alt frate.

Clasa publică TestError ( public static void main(String args) ( încercați ( System.err.println ("nivel 0")); dacă (adevărat) ( ​​aruncă o nouă eroare (); ) System.err.println ("nivel 1") ") ; ) catch (Excepția e) ( System.err.println("nivelul 2"); ) System.err.println("nivelul 3" ) )

Rezultatul executării programului

Excepție de nivel 0 în firul „principal” java.lang.Error at TestError.main(TestFinally.java:8)

Excluderi multiple

Pot exista mai multe declarații de excepții într-o metodă. Exemplu:

Import java.io.EOFException; import java.io.FileNotFoundException; clasă publică MultiException ( // declară excepții public static void main(String args) throws EOFException, FileNotFoundException ( if (System.currentTimeMillis() % 2 == 0) ( throw new EOFException(); ) else ( throw new FileNotFoundException(); ) ) )

Orice program va funcționa stabil doar dacă codul său 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 o întrerupere bruscă a rețelei. 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. Bineînțeles, un procent mare de erori sunt surprinse în etapa de compilare, când sistemul raportează automat că este imposibil să-l mai folosești. 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 să o gestioneze într-un mod special sau a transferat controlul către o altă sucursală.

În Java, o astfel de captare a excepțiilor este impusă de compilator, deci probleme tipice sunt cunoscute și au propria lor schemă standard de 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ă cale alternativă continuarea codului;
  • 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 necesară o manipulare 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. ÎN limba dată Există cinci opțiuni 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. Blocarea este limitată bretele crete {}.
  • Captură. Interceptări tipul dorit excepție și o 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ă metoda poate 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 este să faceți acest lucru 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 diverse contoare, a închide fișiere sau 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.

aruncă cuvântul cheie

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

arunca noua NewException();

Aici este creată o nouă excepție cu tipul NewException(). Tipul poate fi folosit deja inclus în biblioteci standard Clasele Java și cele definite anterior de producția proprie a dezvoltatorului.

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 posibilei excepții.

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 versiunea 7 Java, 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. Apoi, în corpul metodei, informațiile text sunt trimise în consolă și MyException în sine este generată 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 unui tablou 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, în programe mai mult sau mai puțin simple este mult mai ușor de urmărit situațiile de urgență. 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.

Excepțiile sau situațiile excepționale (stările) sunt erori care apar într-un program în timpul funcționării acestuia.

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.

Ierarhia claselor de excepție:

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 reprezintă mai mult decât probleme serioase, care, conform specificației Java, nu ar trebui încercat să fie procesat în program propriu, deoarece sunt legate de probleme la nivel JVM. De exemplu, excepții de acest fel apar dacă memoria este disponibilă pentru mașină virtuală. Programul încă nu va putea oferi memorie suplimentară pentru JVM.

În Java, toate excepțiile sunt împărțite în trei tipuri: excepții verificate (verificate) și excepții nebifate (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;

Gestionarea excepțiilor poate fi făcută folosind instrucțiunile try...catch sau transferată în partea externă a programului. De exemplu, o metodă poate trece excepții care apar în ea mai sus în ierarhia apelurilor fără a o gestiona singură.

Excepțiile nebifate nu necesită tratare, dar puteți gestiona RuntimeExceptions dacă doriți.

Să compilam și să rulăm următorul program:

Clasa Main ( public static void main(String args) ( int a = 4; System.out.println(a/0); ) )

La lansare, pe consolă va fi afișat următorul mesaj:

Excepție în firul „principal” java.lang.ArithmeticException: / prin zero la Main.main(Main.java:4)

Mesajul arată clasa excepției care a apărut - ArithmeticException. Această excepție poate fi gestionată:

Clasa Main ( public static void main(String args) ( int a = 4; try ( System.out.println(a/0); ) catch (ArithmeticException e) ( System.out.println ("A avut loc un eveniment nevalid operație aritmetică"); } } }

Acum, în loc de un mesaj de eroare standard, va fi executat un bloc catch, al cărui parametru este obiectul e clasa corespunzătoare excepției (obiectului în sine i se poate da orice nume; va fi necesar dacă vrem să aruncăm din nou această excepție cu forța, de exemplu, astfel încât să poată fi verificată de un alt handler).

Blocul try conține fragmentul programului în care ar putea apărea o excepție.

O singură încercare poate corespunde mai multor blocuri de captură cu diferite clase de excepții.

Import java.util.Scanner; clasa Main ( public static void main(String args) ( int m = (-1,0,1); Scanner sc = new Scanner (System.in); try ( int a = sc.nextInt(); m[a] = 4/a; System.out.println(m[a]); catch (ArithmeticException e) ( System.out.println("A avut loc o operație aritmetică ilegală"); („Acces prin index de matrice nevalid”);

Dacă, după lansarea programului prezentat, utilizatorul intră de la tastatura 1 sau 2, programul va rula fără a crea excepții.

Dacă utilizatorul introduce 0, o ArithmeticException va fi lansată și gestionată de primul bloc catch.

Dacă utilizatorul introduce 3, va apărea o excepție a clasei ArrayIndexOutOfBoundsException (matrice în afara limitelor) și va fi procesată de al doilea bloc catch.

Dacă utilizatorul introduce un număr care nu este întreg, de exemplu, 3.14, atunci va apărea o excepție a clasei InputMismatchException (nepotrivire tip valoare de intrare) și va fi aruncată în format de eroare standard, deoarece nu am gestionat-o în niciun fel .

Cu toate acestea, puteți adăuga un handler pentru clasa Exception, deoarece această clasă este clasa părinte pentru toate celelalte excepții controlate, va intercepta oricare dintre ele (inclusiv InputMismatchException).

Import java.util.Scanner; clasa Main ( public static void main(String args) ( int m = (-1,0,1); int a = 1; Scanner sc = new Scanner(System.in); try ( a = sc.nextInt();); m = 4/a; System.out.println(m[a]); catch (ArithmeticException e) ( System.out.println("A avut loc o operație aritmetică ilegală"); ) catch (ArrayIndexOutOfBoundsException e) ( System.out. println(„Manevrarea unui index de matrice nevalid”); catch (Excepție e) ( System.out.println(„A apărut o altă excepție”);

Deoarece excepțiile sunt construite pe o ierarhie de clase și subclase, mai întâi ar trebui să încercați să gestionați excepții mai specifice și abia apoi pe cele mai generale. Adică, dacă am plasat primul (și nu al treilea) bloc cu gestionarea excepțiilor din clasa Excepție, nu am vedea niciodată niciun mesaj de eroare în afară de „S-au produs o altă excepție” (toate excepțiile ar fi capturate imediat de acest bloc și nu ar ajunge la rest) .

O adăugare opțională pentru a încerca...catch blocks poate fi un bloc final. Comenzile plasate în acesta vor fi executate în orice caz, indiferent dacă apare sau nu o excepție. În ciuda faptului că atunci când apare o excepție netratată, partea de program rămasă după generarea acestei excepții nu este executată. De exemplu, dacă a apărut o excepție în timpul unor calcule de lungă durată, blocul final poate fi folosit pentru a afișa sau stoca rezultate intermediare.

2010, Alexey Nikolaevich Kostin. Departamentul TIDM, Facultatea de Matematică, Universitatea Pedagogică de Stat din Moscova.

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 îi spune apelantului ce evenimente de excepție trebuie să gestioneze. Acest lucru vă permite, de asemenea, să actualizați clauza throw atunci când metoda dvs. aruncă 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 componenta software pe care o implementați și de unde întâlniți 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 caz contrar, IDE-urile dvs. vor afișa o eroare sau un avertisment 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. Acest lucru va adăuga un mesaj de eroare fals la fișierul 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 informatiile necesare despre un eveniment excepțional. Mesajul descrie acest lucru și conține următorul stivă informatii detaliate despre clasa, metoda și linia în 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.

Nu sunt la fel de eficiente ca structuri generale Comenzi 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 descrie 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, ei prind excepția în stratul de persistență și o propagă la 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ă aceste clase de excepții suplimentare 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ă la astăzi Nu am văzut niciodată o aplicație care să adopte 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 clasă aduce excepții 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); )

Ultima actualizare: 30.10.2015

Erorile pot apărea adesea în timpul execuției programului și nu neapărat din vina dezvoltatorului. Unele dintre ele sunt greu de prevăzut sau anticipat, iar uneori chiar imposibile. De exemplu, se poate rupe brusc conexiune la rețea la transferul unui fișier. Astfel de situații se numesc excepții.

Limbajul Java oferă instrumente speciale pentru a gestiona astfel de situații. Un astfel de mijloc este încercarea... prinderea... construcția în sfârșit. Când apare o excepție într-un bloc try, controlul trece la blocul catch, care poate gestiona excepția. Dacă nu se găsește un astfel de bloc, utilizatorului îi este afișat un mesaj de excepție netratată și execuția ulterioară a programului este oprită. Și pentru a preveni o astfel de oprire, trebuie să utilizați un bloc try..catch. De exemplu:

Int numere = new int; numere=45; System.out.println(numerele);

Deoarece matricea noastră numere poate conține doar 3 elemente, la executarea instrucțiunii numere=45, consola va afișa o excepție și programul se va termina. Acum să încercăm să gestionăm această excepție:

Try( int numere = new int; numere=45; System.out.println(numere); ) catch(Exception ex)(ex.printStackTrace(); ) System.out.println("Program terminat");

Când se utilizează un bloc try...catch, toate instrucțiunile dintre instrucțiunile try și catch sunt executate mai întâi. Dacă o excepție apare brusc într-un bloc try, ordinul normal de execuție se oprește și trece la instrucțiunea catch. Prin urmare, când execuția programului ajunge la numerele de linie=45; , programul se va opri și va merge la blocul catch

Expresia catch are următoarea sintaxă: catch (type_excepție nume_variabilă) . ÎN în acest caz, este declarată o variabilă ex, care este de tip Excepție. Dar dacă excepția care apare nu este o excepție de tipul specificat în instrucțiunea catch, atunci nu este procesată, iar programul pur și simplu îngheață sau aruncă un mesaj de eroare.

Dar, deoarece tipul Exception este clasa de bază pentru toate excepțiile, expresia catch (Exception ex) va gestiona aproape toate excepțiile. Gestionarea excepției în acest caz se reduce la tipărirea urmei stivei de erori pe consolă folosind metoda printStackTrace() definită în clasa Exception.

După ce blocul catch termină execuția, programul își continuă munca, executând toate celelalte instrucțiuni după blocul catch.

Construcția try..catch poate avea și un bloc final. Cu toate acestea, acest bloc este opțional și poate fi omis atunci când se gestionează excepții. Blocul final este executat indiferent dacă apare sau nu o excepție în blocul try:

Încercați( int numere = int nou; numere = 45; System.out.println(numere); ) catch(Exception ex)(ex.printStackTrace(); ) finally( System.out.println("În cele din urmă blocați"); ) System.out.println("Program finalizat");

Gestionarea mai multor excepții

Există multe tipuri diferite de excepții în Java și le putem diferenția gestionarea prin includerea blocurilor de captură suplimentare:

Int numere = new int; try( numere=45; numere=Integer.parseInt("gfd"); ) catch(ArrayIndexOutOfBoundsException ex)( System.out.println("Matrice în afara limitelor"); ) catch(NumberFormatException ex)( System.out.println ("Eroare la conversia din șir în număr");

Dacă primim o excepție anumit tip, apoi merge la blocul de captură corespunzător.

declarație aruncă

Puteți utiliza instrucțiunea throw pentru a indica că au apărut excepții într-un program. Adică, folosind acest operator, noi înșine putem crea o excepție și o ridicăm în timpul execuției. De exemplu, în programul nostru introducem un număr și vrem să aruncăm o excepție dacă numărul este mai mare de 30:

Pachetul firstapp; import java.util.Scanner; clasă publică FirstApp ( public static void main(String args) ( try( Scanner in = new Scanner(System.in); int x = in.nextInt(); if(x>=30)( throw new Exception ("Numărul x trebuie să fie mai mic de 30"); ) ) catch(Excepție ex)( System.out.println(ex.getMessage()); ) System.out.println("Program terminat"); ) )

Aici, pentru a crea un obiect excepție, se folosește constructorul clasei Exception, căruia îi este transmis mesajul de excepție. Și dacă numărul x este mai mare decât 29, atunci va fi aruncată o excepție și controlul va trece la blocul catch.

În blocul catch, putem obține mesajul de excepție folosind metoda getMessage().