Programavimas

„Java“ išimtys, 1 dalis. Išimčių tvarkymo pagrindai

„Java“ išimtys yra bibliotekos tipai ir kalbos ypatybės, naudojamos programos gedimams atspindėti ir spręsti. Jei norėjote suprasti, kaip nesėkmės vaizduojamos šaltinio kode, patekote į reikiamą vietą. Be „Java“ išimčių apžvalgos, aš pradėsiu nuo „Java“ kalbos funkcijų, skirtų mesti objektus, bandyti kodą, kuris gali nepavykti, gaudyti užmestus objektus ir išvalyti „Java“ kodą po to, kai bus išimtis.

Pirmoje šios pamokos pusėje sužinosite apie pagrindines kalbos ypatybes ir bibliotekos tipus, buvusius nuo „Java 1.0“. Antroje pusėje rasite pažangias galimybes, įdiegtas naujesnėse „Java“ versijose.

Atminkite, kad šios mokymo programos kodų pavyzdžiai yra suderinami su JDK 12.

atsisiųsti Gauti kodą Atsisiųskite šaltinį, pvz., programas, šioje pamokoje. Sukūrė Jeffas Friesenas, skirtas „JavaWorld“.

Kokios yra „Java“ išimtys?

Gedimas įvyksta, kai įprastą „Java“ programos veikimą nutraukia netikėtas elgesys. Šis išsiskyrimas yra žinomas kaip išimtis. Pavyzdžiui, programa bando atidaryti failą, kad perskaitytų jo turinį, tačiau failo nėra. „Java“ klasifikuoja išimtis į keletą tipų, todėl apsvarstykime kiekvieną iš jų.

Patikrintos išimtys

„Java“ klasifikuoja išimtis, atsirandančias dėl išorinių veiksnių (pvz., Trūkstamo failo), kaip patikrintos išimtys. „Java“ kompiliatorius patikrina, ar tokios išimtys yra tvarkomi (pataisyti) ten, kur jie įvyksta, arba dokumentais tvarkomi kitur.

Išimčių tvarkytojai

An išimčių tvarkytojas yra kodo seka, tvarkanti išimtį. Jis klausia konteksto - tai reiškia, kad jis skaito reikšmes, išsaugotas iš kintamųjų, kurie buvo taikymo srities metu, kai įvyko išimtis, tada panaudoja tai, ko išmoko, kad atkurtų „Java“ programą įprastu elgesiu. Pavyzdžiui, išimčių tvarkytojas gali perskaityti išsaugotą failo pavadinimą ir paraginti vartotoją pakeisti trūkstamą failą.

Vykdymo (netikrintos) išimtys

Tarkime, kad programa bando sveiką skaičių padalyti iš sveiko skaičiaus 0. Šis neįmanomumas iliustruoja kitos rūšies išimtį, būtent a vykdymo laiko išimtis. Skirtingai nuo pažymėtų išimčių, vykdymo laiko išimtys paprastai kyla iš prastai parašyto šaltinio kodo, todėl jas turėtų ištaisyti programuotojas. Kadangi kompiliatorius netikrina, ar vykdymo laiko išimtys yra tvarkomos ar dokumentuojamos, kad būtų tvarkomos kitur, galite laikyti vykdymo laiko išimtį kaip nepatikrinta išimtis.

Apie vykdymo laiko išimtis

Galite modifikuoti programą, kad būtų vykdoma vykdymo laiko išimtis, tačiau geriau pataisyti šaltinio kodą. Vykdymo laiko išimtys dažnai kyla dėl neteisingų argumentų perdavimo bibliotekos metodams; turėtų būti pataisytas bagio skambinimo kodas.

Klaidos

Kai kurios išimtys yra labai rimtos, nes pakenkia programos galimybei tęsti vykdymą. Pavyzdžiui, programa bando paskirstyti atmintį iš JVM, tačiau nepakanka laisvos atminties, kad patenkintumėte užklausą. Kita rimta situacija įvyksta, kai programa bando įkelti klasės failą per „Class.forName“ () metodo iškvietimas, bet klasės failas yra sugadintas. Tokia išimtis yra žinoma kaip klaida. Niekada neturėtumėte pabandyti pašalinti klaidų patys, nes JVM gali nepavykti atsigauti.

Išimtys šaltinio kode

Išimtis šaltinio kode gali būti pateikiama kaip Klaidos kodas arba kaip objektas. Pristatysiu abu ir parodysiu, kodėl objektai yra pranašesni.

Klaidų kodai, palyginti su objektais

Programavimo kalbos, pvz., C, naudoja sveikąjį skaičių klaidų kodai pateikti nesėkmę ir nesėkmės priežastis - t. y. išimtis. Štai keli pavyzdžiai:

if (chdir ("C: \ temp")) printf ("Nepavyko pakeisti į temp katalogą:% d \ n", errno); FILE * fp = fopen ("C: \ temp \ foo"); if (fp == NULL) printf ("Nepavyko atidaryti foo:% d \ n", klaida);

C chdir () (pakeisti katalogą) funkcija grąžina sveiką skaičių: 0 sėkmės atveju arba -1, jei nesėkmė. Panašiai ir C fopen () (failas atidarytas) funkcija grąžina nullull rodyklė (sveikasis adresas) į a NUOTRAUKOS sėkmės struktūra arba nulinis (0) žymeklis (pavaizduotas konstanta NULL) dėl nesėkmės. Bet kuriuo atveju, norėdami nustatyti išimtį, kuri sukėlė gedimą, turite perskaityti visuotinę errno kintamojo sveikojo skaičiaus klaidos kodas.

Klaidų kodai kelia keletą problemų:

  • Sveikieji skaičiai yra beprasmiški; jie neapibūdina jų atstovaujamų išimčių. Pavyzdžiui, ką reiškia 6?
  • Susieti kontekstą su klaidos kodu yra nepatogu. Pvz., Galbūt norėsite išvesti failo, kurio nepavyko atidaryti, pavadinimą, bet kur saugosite failo pavadinimą?
  • Sveikieji skaičiai yra savavališki, o tai gali sukelti painiavą skaitant šaltinio kodą. Pavyzdžiui, nurodant jei (! chdir ("C: \ temp")) (! reiškia NE) vietoj jei (chdir ("C: \ temp")) išbandyti nesėkmę yra aiškiau. Tačiau sėkmei nurodyti buvo pasirinktas 0 ir t jei (chdir ("C: \ temp")) turi būti nurodyta išbandyti gedimą.
  • Klaidų kodus per lengva ignoruoti, o tai gali sukelti klaidų kodą. Pavyzdžiui, programuotojas galėtų nurodyti chdir ("C: \ temp"); ir nepaisyti jei (fp == NULL) patikrinti. Be to, programuotojui nereikia nagrinėti errno. Netikrindama gedimo, programa elgiasi netaisyklingai, kai kuri nors funkcija pateikia gedimo rodiklį.

Siekdama išspręsti šias problemas, „Java“ pritaikė naują požiūrį į išimčių tvarkymą. „Java“ sistemoje objektus, apibūdinančius išimtis, deriname su mechanizmu, paremtu šių objektų mėtymu ir gaudymu. Keletas objektų, palyginti su klaidos kodu, naudojimo privalumai žymint išimtis:

  • Objektą galima sukurti iš klasės su prasmingu pavadinimu. Pavyzdžiui, FileNotFoundException (viduje konors java.io pakuotė) yra prasmingesnė nei 6.
  • Objektai gali išsaugoti kontekstą įvairiuose laukuose. Pvz., Objekto laukuose galite išsaugoti pranešimą, failo, kurio nepavyko atidaryti, pavadinimą, naujausią poziciją, kur nepavyko išanalizuoti, ir (arba) kitus elementus.
  • Jūs nenaudojate jei teiginiai, kad patikrintumėte nesėkmę. Vietoj to, išimties objektai metami tvarkytojui, kuris yra atskiras nuo programos kodo. Todėl šaltinio kodas yra lengviau skaitomas ir rečiau yra klaidingas.

Metamas ir jo poklasiai

„Java“ pateikia klasių, kurios atspindi įvairias išimtis, hierarchiją. Šios klasės yra įsišaknijusios java.lang pakuotės Metamas klasė, kartu su ja Išimtis, RuntimeExceptionir Klaida poklasiai.

Metamas yra pagrindinis superklasė, kai kalbama apie išimtis. Tik objektai, sukurti iš Metamas o jo poklasius galima mesti (ir vėliau gaudyti). Tokie objektai yra žinomi kaip mesti.

A Metamas objektas siejamas su a išsamus pranešimas kad apibūdina išimtį. Pateikti keli konstruktoriai, įskaitant porą, aprašytą žemiau, sukuria a Metamas objektas su išsamiu pranešimu arba be jo:

  • Mesti () sukuria a Metamas be jokio išsamaus pranešimo. Šis konstruktorius tinka situacijoms, kai nėra konteksto. Pavyzdžiui, jūs norite žinoti tik tai, kad kaminas yra tuščias arba pilnas.
  • Metamas (eilutės pranešimas) sukuria a Metamas su pranešimą kaip išsamią žinutę. Šis pranešimas gali būti išvestas vartotojui ir (arba) užregistruotas.

Metamas teikia Eilutė „getMessage“ () būdas grąžinti išsamų pranešimą. Taip pat pateikiami papildomi naudingi metodai, kuriuos pristatysiu vėliau.

Išimties klasė

Metamas turi du tiesioginius poklasius. Vienas iš šių poklasių yra Išimtis, kuriame aprašoma išimtis, atsirandanti dėl išorinio veiksnio (pvz., bandymo skaityti iš neegzistuojančio failo). Išimtis deklaruoja tuos pačius konstruktorius (su vienodais parametrų sąrašais) kaip Metamas, ir kiekvienas konstruktorius iškviečia savo Metamas atitikmuo. Išimtis paveldi Metamasmetodai; ji nedeklaruoja jokių naujų metodų.

„Java“ teikia daug išimčių klasių, kurios tiesiogiai perkelia poklasį Išimtis. Štai trys pavyzdžiai:

  • CloneNotSupportedException signalizuoja apie bandymą klonuoti objektą, kurio klasė neįgyvendina Klonuojamas sąsaja. Abi rūšys yra java.lang pakuotė.
  • IOException signalizuoja, kad įvyko kažkoks įvesties / išvesties gedimas. Šis tipas yra java.io pakuotė.
  • ParseException signalizuoja, kad analizuojant tekstą įvyko klaida. Šio tipo galite rasti java.text pakuotė.

Atkreipkite dėmesį, kad kiekvienas Išimtis poklasio pavadinimas baigiasi žodžiu Išimtis. Ši sutartis leidžia lengvai nustatyti klasės tikslą.

Paprastai priskirtumėte poklasį Išimtis (arba vieną iš jo poklasių) su savo išimčių klasėmis (kurių pavadinimai turėtų baigtis Išimtis). Čia yra pora pritaikytų poklasių pavyzdžių:

viešoji klasė „StackFullException“ išplečia išimtį {} public class „EmptyDirectoryException“ išplečia išimtį {private String directoryName; public EmptyDirectoryException (eilutės pranešimas, eilutės katalogo pavadinimas) {super (pranešimas); this.directoryName = katalogo pavadinimas; } public String getDirectoryName () {return directoryName; }}

Pirmajame pavyzdyje aprašoma išimčių klasė, kuriai nereikia išsamaus pranešimo. Tai numatytasis „noargument“ konstruktoriaus iškvietimas Išimtis (), kuris kviečia Mesti ().

Antrasis pavyzdys apibūdina išimčių klasę, kurios konstruktorius reikalauja išsamaus pranešimo ir tuščio katalogo pavadinimo. Konstruktorius kreipiasi Išimtis (eilutės pranešimas), kuris kviečia Metamas (eilutės pranešimas).

Objektai iš karto Išimtis arba vienas iš jo poklasių (išskyrus RuntimeException arba vienas iš jo poklasių) yra tikrinamos išimtys.

„RuntimeException“ klasė

Išimtis yra tiesiogiai klasifikuojamas RuntimeException, kuri apibūdina išimtį, kuri greičiausiai kyla dėl blogai parašyto kodo. RuntimeException deklaruoja tuos pačius konstruktorius (su vienodais parametrų sąrašais) kaip Išimtis, ir kiekvienas konstruktorius iškviečia savo Išimtis atitikmuo. RuntimeException paveldi Metamasmetodus. Ji nedeklaruoja jokių naujų metodų.

„Java“ teikia daug išimčių klasių, kurios tiesiogiai perkelia poklasį RuntimeException. Šie pavyzdžiai yra visi java.lang paketas:

  • Aritmetinė išimtis signalizuoja apie neteisėtą aritmetinę operaciją, pvz., bandymą padalyti sveiką skaičių iš 0.
  • Neteisėtas argumentas. Išimtis signalizuoja, kad metodui buvo perduotas neteisėtas ar netinkamas argumentas.
  • „NullPointerException“ signalizuoja bandymą iškviesti metodą arba pasiekti egzemplioriaus lauką per nulinę nuorodą.

Objektai iš karto RuntimeException arba vienas iš jo poklasių yra nepatikrintos išimtys.

Klaidų klasė

Metamaskitas tiesioginis poklasis yra Klaida, kuri apibūdina rimtą (net nenormalią) problemą, kurios nereikėtų bandyti išspręsti pagrįstai taikomai programai, pvz., atminties trūkumas, JVM kamino perpildymas ar bandymas įkelti klasę, kurios negalima rasti. Kaip Išimtis, Klaida deklaruoja identiškus konstruktorius Metamas, paveldi Metamasmetodus ir nedeklaruoja jokių savo metodų.

Galite nustatyti Klaida poklasiai iš konvencijos, kuria baigiasi jų klasių pavadinimai Klaida. Pavyzdžiai: „OutOfMemoryError“, „LinkageError“ir „StackOverflowError“. Visi trys tipai priklauso java.lang pakuotė.

Mėtymo išimtys

C bibliotekos funkcija praneša apie išimties skambinimo kodą nustatydama visuotinę errno kintamasis į klaidos kodą ir grąžina gedimo kodą. Priešingai, „Java“ metodas meta objektą. Žinojimas, kaip ir kada daryti išimtis, yra esminis efektyvaus „Java“ programavimo aspektas. Išmetimo išmetimas apima du pagrindinius veiksmus:

  1. Naudoti mesti pareiškimas mesti išimties objektą.
  2. Naudoti metimai sąlyga informuoti kompiliatorių.

Vėlesniuose skyriuose daugiausia dėmesio bus skiriama išimčių gaudymui ir valymui po jų, bet pirmiausia sužinokime daugiau apie mėtomus daiktus.

Metimo pareiškimas

„Java“ teikia mesti pareiškimas mesti objektą, apibūdinantį išimtį. Štai sintaksė mesti pareiškimas:

mesti mesti;

Objektas, kurį identifikuoja mesti yra pavyzdys Metamas ar bet kuris jo poklasis. Tačiau jūs dažniausiai mėtote daiktus tik iš pakategorių Išimtis arba RuntimeException. Štai keli pavyzdžiai:

mesti naują FileNotFoundException ("nepavyksta rasti failo" + failo vardas); mesti naują „IllegalArgumentException“ („argumentas, perduotas skaičiuoti, yra mažesnis nei nulis“);

Išmetamas metamas iš dabartinio metodo į JVM, kuris patikrina, ar šis metodas yra tinkamas prižiūrėtojas. Jei nerandama, JVM išvynioja metodo skambučio kaminą, ieškodamas artimiausio skambinimo metodo, kuris galėtų apdoroti išmetimą, aprašytą išmetamuoju. Jei jis randa šį metodą, jis perduoda metimą metodo tvarkytojui, kurio kodas vykdomas, kad būtų tvarkoma išimtis. Jei nerandama metodo, kaip elgtis su išimtimi, JVM nutraukiamas tinkamu pranešimu.

Metimų sąlyga

Jūs turite informuoti kompiliatorių, kai metote pažymėtą išimtį. Atlikite tai pridėdami a metimai metodo antraštės sąlyga. Ši sąlyga turi šią sintaksę:

metimai checkExceptionClassName (, checkExceptionClassName)*

A metimai sąlyga susideda iš raktinio žodžio metimai po to kableliais atskirtas klasių pavadinimų sąrašas patikrintų išimčių, išmestų iš metodo. Štai pavyzdys:

public static void main (String [] args) meta ClassNotFoundException {if (args.length! = 1) {System.err.println ("naudojimas: java ... classfile"); grįžti; } Class.forName (argumentai [0]); }

Šiame pavyzdyje bandoma įkelti klasės failą, identifikuojamą komandinės eilutės argumentu. Jei „Class.forName“ () negali rasti klasės failo, jis meta a java.lang.ClassNotFoundException objektas, kuris yra pažymėta išimtis.

Patikrinta išimčių diskusija

metimai sąlyga ir patikrintos išimtys yra prieštaringos. Daugelis kūrėjų nekenčia priversti nurodyti metimai arba tvarkykite patikrintą (-as) išimtį (-is). Sužinokite daugiau apie tai skiltyje Ar patikrintos išimtys yra geros ar blogos? tinklaraščio straipsnis.