Megjegyzi józan gyakorlat - technika - a próbát
try / catch / véglegesen és kivételek
Azt hiszem, alig van olyan Java-fejlesztő, amely nem legalább hallott kivételek. Elvileg ezek nem kizárólagos tulajdona Java, ott vannak a Delphi, C ++ tegye. Azonban a Java kivételek alkalmazása elsősorban széles körben. És gyakran vannak társítva egy csomó hibát. A fő célja ennek a cikknek - rendszerezése információkat kivételek, a feldolgozás, stb nevezetesen:
Kizárása, mint jelenség
Mi az általános kivétel? Ez a jel egy nem - kizárólagos - helyzetet. A helyzet nagyon eltérő lehet - várható-e vagy sem, a változó súlyosságú. És kezelni ezeket a helyzeteket, persze, van sok.
Mint minden a Java, kivételek is vannak ábrázolva osztályok. A gyökér a hierarchia java.lang.Throwable osztályban. szó szerint - „dobja”. Ő közvetlen leszármazottai java.lang.Exception és java.lang.Error. akitől örökölte minden egyéb kivételek. És ami azt javasoljuk, hogy örökölje tulajdon.
Szeretném hangsúlyozni, hogy a kizárás nem valami szokatlant. Ez a normális eljárás. Tehát ne próbálja ne használja őket minden áron. És minél többet ne próbálják meg elkerülni kivételek konstruktőrök, amelyek hajlamosak a fejlesztők ismerik a C ++. Tekintettel a szemétgyűjtő memóriavesztés ebben az esetben nem. Ez tényleg megpróbálja. Mármint szándékosan.
Most tekintsük a fajta kivételek közelebb.
besorolás kivétel
Mint már említettem, van két „alapvető” típusú kivételek - java.lang.Exception és java.lang.Error. Azt mondanám, hogy a különböző súlyossági. Nem, persze, mindkét típusú lehet elfogott, a fogás kivételek a szintet java.lang.Throwable. Ez a felosztás meglehetősen logikus. Ha volt valami komoly - nem talált egy módszert, hogy meg kell hívni, az emlékezet verem túlcsordulás, a rövid, valamit, majd vissza a normális működés, nem valószínű, hogy valóban - ez egy tévedés, java.lang.Error. Ha a további munka elméletileg lehetséges - ez egy kivétel, java.lang.Exception.
Emellett a már említett két típus, van is egy osztály, amely elengedhetetlen - java.lang.RuntimeException. Ő örökölte java.lang.Exception, és a gyökere minden kivételt futásidejű - azaz találkozott, amikor egy virtuális gép. A nulla referencia, osztás nullával, érvénytelen argumentum, amely túlmutat tömbök, stb - minden kivétel idejét. Miben különböznek a szokásos, nézzük meg az alábbiakban.
Kivételként - pontosan ugyanolyan osztályok, akkor bekapcsol, és saját változókat, és még néhány fajta logika. Vegyen részt, azonban ez nem szükséges. Az a tény, hogy a kizárás - osztály még mindig kiemelve. Amikor létrehoz egy Eldobható van egy nagy overhead - kitöltésével a hívási verem. Ez egy meglehetősen időigényes eljárás. És így, hogy hozzon létre egy kivételt okból - saját veszedelem. Meg kell létrehozni csak akkor elengedhetetlen, mikor lesz pontosan dobni. Könnyebb csinálni azonnal, együtt az irányelv dobás.
De ne kivétel osztály bizonyos információkat, amelyek lehetővé teszik, hogy eljárást - ez nagyon is lehetséges. Továbbítja ezt az információt egy jobb designer.
Tehát folytassa részletesebb venni. Az első bázis típusa -
java.lang.Exception
Kivételek az ilyen típusú azt oharakteriroval így - a felmerülő helyzetekben, amelyek nem befolyásolhatók minket. Például, deserializuem osztály, és az adatokat a hibás formátumú. És ez semmit sem tehetünk, de, hogy megfelelően reagáljon.
Bármilyen kivétel java.lang.Exception típusú kell feldolgozni. Ez a törvény. Annak végrehajtását a következő fordító. Ha a kivétel kezelése nem a módszer - meg kell állapítani, az ő aláírása ebben az esetben kezelt adatai. Vagy még ennél is magasabb. De ez lesz feldolgozni. Az egyetlen kivétel - ez java.lang.RuntimeException. amely megbeszéljük a további.
Az eljárás nyilatkozni minden kolichestko kivételek. Nem, bárki számára - talán túl erős kifejezés. Ha emlékezetem nem csal, a mentességek számát korlátozott 64K - 65536 db. Számomra ez azt jelenti, hogy már kijelenthetem annyi kivétellel, ahogy tetszik.
java.lang.RuntimeException
Ahogy az várható volt a hiba - buta, java.lang.RuntimeException típusú kivételeket nem nyilvánították. A fordító ezt lehetővé teszi, illetve lehetővé teszi számukra, hogy ne dolgozza fel. Sőt, azt mondanám, hogy a fogási java.lang.RuntimeException - rossz formában, hiszen ahelyett, hogy szüntesse meg az okot, akkor neystralizuem következményeit. És a legrosszabb az egészben az, hogy a fejlesztő hibák kiküszöbölése során szinte lehetetlen, sőt, ezek sokkal közelebb áll a kritikusság java.lang.Error.
Térjünk az utóbbi típus -
java.lang.Error
Mint már említettem, ez kritikus hibákat, amely után normális működés helyreállításához gyakorlatilag lehetetlen. Valójában - nos, mit lehet tenni, ha egy verem túlcsordulás? Vagy, ha a módszert nem talált? Vagy ha az absztrakt metódus? Vagy hiba esetén a bájtkódot osztályban? Abszolút semmi. Legalábbis nem súlyos emberi beavatkozás, amely felválthatja a könyvtár, például. Vagy módosítsa a classpath.
Bizonyos esetekben, a helyzet nem annyira kritikus. Például a memória hiánya, ami java.lang.OutOfMemoryError. Ha ez a hiba időpontjában megjelenése nagy mennyiségű memória - például, ha létrehozunk egy tömböt - lehetséges, hogy elfogják, és megkísérli a memóriát kisebb mennyiségben megváltoztatásával valahogy algoritmus, amely használni fogja ezt a memóriát.
Vagy, mondjuk, abban az esetben, ha a JVM nem támogatja a kódolási rendszer - egy hiba fog dobni, amikor megpróbál létrehozni egy InputStreamReader kódolás nélkül. Azonban mi is kell egy rendszer kódolás és mennyire kritikus távollétében számunkra - ez rajtunk múlik.
Mint abban az esetben a fordító szétválasztja java.lang.RuntimeException nem nyilvánítja, és kezeli a hibákat a hierarchia java.lang.Error. Fogni őket, akár nem - úgy dönt. Ez attól függ, hogy tud-e ajánlani egy elfogadható algoritmus a regenerálódásra.
A besorolás kész, haladunk tovább a következő kérdésre.
megindítását kivételek
És a következő kérdés - mit, mikor dobja.
Képzeld el, hogy hozzon létre rendkívüli helyzet és a munka a kódot nem. Milyen típusú kivétel kezelhető?
Itt az ideje, hogy kihasználják a jellemzői a kivételek a fent felsorolt. Ha kivételes helyzet állt elő, hogy a további munkát lehetetlen elvileg - lehet dobni egy kivételt a hierarchia java.lang.Error. Bár én személy szerint nem volt ilyen helyzetek a gyakorlatban. Ha kivételes helyzet állt elő, mivel a hiba a külső körülmények, vagy a felhasználó az alkalmazás - nem a megadott adatokat, például -, akkor ez egy eset, amikor a hibákat ki kell feldolgozni, ezért a legjobb, ha egy java.lang.Exception. Ha a helyzet alakult ki hibájából a fejlesztő - például az általunk küldött, mint a paraméter null. annak ellenére, hogy az angol akkor javadoc fehér, hogy ez nem lehet megtenni - akkor java.lang.RuntimeException.
Néhány szó a fenti példában - null paraméterként. Elméletileg ebben a helyzetben meg lehet dobni két kivételtől eltekintve - NullPointerException és IllegalArgumentException. Neskotrya látszólagos nyilvánvaló választás, én személy szerint inkább a második lehetőséget. Véleményem kell dobni NullPointerException kizárólag virtuális gép. Ha én tettem ellenőrizze az értéket, és győződjön meg arról, hogy null. de ez nem lehet - sokkal informatívabb használni IllegalArgumentException. ha az érték az az érv, vagy IllegalStateException - amennyiben ez az érték egy osztály tagja.
Nos, hogy dobja el - valahogy meghatározni. De néha van némi irracionális vágy nem csak a dob kivételt, de valahogy az ő teste, amely az oka. Nem, akkor, természetesen, és a kizárás minden hibát létrehozni, de megbolondul sokkal könnyebb és gyorsabb.
Az első változat, ami látható - egy szöveges üzenetet. Szinte minden kivétel osztály van konstruktora, hogy vesz egy paraméter a szövegben. Ez az a szöveg jelenik meg a konzolon, amikor a nyomtatás kivételével üzenetet, akkor lehetséges, hogy a getMessage (). Ez pozlezno ha hibát észlel magunkat. És mi a teendő, ha egy hibát számunkra is „idegen”, azt mondják - fogtunk kivétel dobott mélyebb?
Ebben az esetben a mechanizmus lehet az úgynevezett óvadék kivétel láncolás - kötelező kivételek. Szinte minden kivétel osztály van konstruktora, hogy vesz egy paraméter Eldobható - az oka a kivétel. Ha ez a kivitelező nem - teljesen ugyanaz Eldobható. ahonnan örökölte a kivételeknek initCause (Eldobható) módszer. amely nevezhető pontosan egyszer. És adja neki a kivétel yavivsheesya oka, hogy azt követően indították kivétel.
Miért csinálni. Az a tény, hogy egy jól megtervezett kód - ez olyan, mint egy fekete doboz. Megvan a saját felület, egy bizonyos viselkedés, egy sor kivételt, végre. És mi folyik odabent - nem számít, amit kívül. Ráadásul - néha játszhat az ellenkező hatást. Az okok a hiba lehet egy tucat, és elkapni őket külön-külön, és ugyanabban a folyamatban. Leggyakrabban, egyszerűen nem kell. Könnyebb meghatározni, mert például a kizárás (vagy a meglévő, nem számít), és dobja az szerepel, mint az oka annak, amit fogott. És a farkasok etetik, és a felhasználók a munka kód kevesebb.
Nos, a kezdeményezéstől a kivételek fokozatosan mozog a kezelést.
kivételek kezelése
Úgy tűnik, hogy mi sem egyszerűbb? Írtam fogás (Eldobható th) - és mindent. Azonban ebből szeretnék figyelmeztetni őket.
Először is, ahogy említettük. fogása futásidejű kivételeket - rossz formában. Ezek jelzik a hibát. Catch java.lang.Error vagy származékai érdemes csak ha pontosan tudja, mit csinál. Helyreállítás az ilyen hibák nem mindig lehetséges, és szinte mindig triviális.
Második - hogyan kell kezelni? Írtam róla egy cikket a minősége a kód részben kivételek kezelését. de ismétlem. Minden Poymanov így nem kell dönteni. Csak lenyelni, vagy hogy a konzolra - a legkellemetlenebb dolog, ami jön. És ez a bűn, sajnos, sok. Egy ember olvas az XML fájlból veszi a kivétel lenyeli -, és megpróbálja folytatni a munkát az XML, mintha semmi sem történt volna. Természetesen lesz NullPointerException. az osztály, hogy használ, nem inicializált. Fejlesztő hiba, bár nem annyira nyilvánvaló.
Miért mondom, hogy meg kell kezdeni a saját kivételtípust - így könnyebben ki tudják választani azokat a feldolgozási szakaszban. Képzeljük el, hogy van öt ok, amiért kivételt lehet dobni, és mind az öt esetben dob java.lang.Exception. Alszol kitalálni, hogy pontosan mi okozta ezt a kivételt. És ha ez az öt különböző típusú - nincs könnyű. Minden - az egységnyi fogás.
És a harmadik -, mi köze hierarchia kivételek. Tegyük fel, hogy van egy módszer lehet dobni, mint IOException. és kivétel. Tehát, ez nem mindegy, hogy milyen sorrendben fog állni fogás blokkokat. mert kezelik pontosan ugyanabban a sorrendben, mint bejelentették. És ha az első fogás (Kivétel ex) - a második (catch (IOException ioex)) kezelése csak nem értem. A fordító ezt, persze, figyelmeztetni, sőt - úgy vélik, egy hiba. Mindazonáltal érdemes megjegyezni.
A következő dolog, amit szeretnék érinteni -
Lefoglaló kivételek okozta áramlási befejezése
Ha több szálat, vannak helyzetek, amikor meg kell tudni, hogyan áramlik át. Úgy értem - ha ez volt köszönhető, hogy a kivétel, mert azt. Erre a célra, kezdve a megjelenése Java 5, van egy speciális interfész - Thread.UncaughtExceptionHandler. Ennek végrehajtását állíthatja be a kívánt áramlási keresztül setUncaughtExceptionHandler módszer. Azt is beállíthatja az alapértelmezett kezelő a statikus módszer Thread.setDefaultUncaughtExceptionHandler.
Thread.UncaughtExceptionHandler felület egy egyetlen módszer - uncaughtException (Szál t, Eldobható e) - amely továbbítja a folyamba esetben végződő egy kivétel, és egy másolatot a kivétel. Visszaállítani az áramlás természetesen nem fog sikerülni, de rögzíteni azt a tényt, hogy abnormális befejeződését így lehetséges.
A következő dolog, amit akart beszélni - ő try / catch / végül konstrukció.
A design try / catch / végül - finomság
Blokk próbát. Azt hiszem, a kérdés nem merül fel. A catch blokk - remélem, már nem. Így is marad végül blokkolja. Mi ez, és mit eszik?
A blokk végül a végén a konstrukció try / catch / végül. Az egyik legfontosabb jellemzője az, hogy ő mindig elégedett. függetlenül attól, hogy a rakomány fogás.
Miért csinálni. Nézd itt ezt a kódrészletet:
Úgy tűnik, hogy minden rendben van. És mi történik, ha például, ha hívja rs.first () történik kivétel? Igen, ez feldolgozni. Azonban sem a ResultSet. Nem mondtál. vagy kapcsolat nem lesz lezárva. A következmények nagyon szomorú - kimerültség nyitott kurzorok, csatlakozások a medencében, stb
Akkor, persze, hogy ugyanazt a kódot a catch blokkban. Ugyanakkor a kettős kód - nem a legjobb ötlet. Helyes, hogy a záró kódot végül blokk. Ebben az esetben, akkor lefut, mint abban az esetben, kivétel, és mikor nem.
Tekintsük egy másik példa:
Trükkös kérdés - mi az eredmény? Mi vizsgálatokkal kap:
Ie Mindkét esetben az eredmény ugyanaz lesz. és nem olyan, amit elvár! Miért történik ez? Az első esetben - a try blokk vissza kell értéke 6 - hossza telt húr. Ugyanakkor a végül blokkolja. ahol a függvény 0. Ennek eredményeképpen, a kezdeti érték elvész. A második esetben - egy kísérlet okozhat toString () a továbbított null érték megszüntetné - NullPointerException. Ez a kivétel lesz fogott, mert Ez az utódja a kivétel. A catch blokk, vissza kell adnia értéke -1, de az végül blokkolni, és visszaáll 0 és -1 - elveszett!
Hasonlóképpen, a blokk végül veszteséget okozhat kivételek. Nézd meg itt egy példa:
Ez a teszt nagyon gyakran ad interjút. És helyesen válaszol egységet. Eközben - az eredmény annak végrehajtása kerül kiadásra a konzol b. És csak. Megkezdését követően az első kivétel - új Kivétel ( „a”) - végül blokk kerül végrehajtásra. ahol kivételt új IOException ( „b”) fogják dobni. És ez a kivétel lesz fogott, és kezeli. Kezdeti ugyanezt a kivételt elveszett.
Szeretnék kitérni egy másik pontján. Milyen kombinációk léteznek try blokkot. fogni, és végül. Magától értetődik, hogy próbálja - kötelező. Meg lehet osztani a fogás. vagy egy fogás, és végül ugyanabban az időben. Külön-külön, próbáld nem használható. Vannak más lehetőségek?
Ott. próbálja párosítható végre. fogás nélkül. Ez ugyanúgy működik, - miután kilépett a try blokkban, a végül blokkolja. Ez hasznos lehet például a következő helyzetet. Amikor kilép a módszert, meg kell, hogy bizonyos intézkedéseket. A visszatérés ez a módszer költség több helyen. Írni ugyanazt a kódot, mielőtt minden visszatér kivitelezhetetlen. Sokkal könnyebb és hatékonyabb, hogy alapvető kódot próbát. és a kód, ami kilépéskor - a végül.
És az utolsó a témában -
A hiányzó tranzakciós
Az elején említettem, hogy szervezni memóriavesztés használatakor kivételek konstruktőrök nehéz. Valójában - ez lehetséges. Nézzük egy példát.
Ez a példa mesterséges, de csak egy bizonyos mértékig. Úgy beszél egy nagyon fontos jellemzője a kivételek:
Tulajdonságok tranzakciós kivételek nem rendelkezik - olyan tevékenységek, amelyek előfordulnak a try blokk kivétel, nem törölték pocle előfordulása.
És azt kell figyelembe venni. Hivatkozással az alábbi példát - érdemes minden műveletet, amely kizáráshoz vezet, hogy végezzen a lehető leghamarabb. Például, hogy ellenőrizze az átadott paraméterek azonnal. Bizonyos esetekben, hogy megszünteti már akciók hasznos lehet a végül blokk. És ha valóban szükség van valahol tartani egy hivatkozás a létrehozandó objektum, és meg kell tenni a kivitelező - a legjobb, ha hagyja, hogy a végén, amikor az összes kritikus kód már befejeződött.
Nos, ez minden. Azt hiszem, Bo A legtöbb ilyen anyag volt ismerős. Különben is, remélem. Célom az volt, hogy egyszerűen az információk E kivételek még felületesen ismerik. Köszönöm mindenkinek!