Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Interní datové typy a výjimky

Podobné prezentace


Prezentace na téma: "Interní datové typy a výjimky"— Transkript prezentace:

1 Interní datové typy a výjimky
Rudolf Pecinovský

2 Obsah s odkazy Výjimky Výjimky kontrolované a nekontrolované
Definice vlastních výjimek Interní datové typy Vnořené typy (nested, static inner) Vnitřní třídy (inner classes) Anonymní třídy Pojmenované lokální třídy Rozhraní Comparable a Comparator

3 Výjimky Výjimečné situace v programech
Ošetření nestandardních situací v Javě Zpráva o výjimce Klíčová slova Činnost Vyvolání

4 Výjimečné situace v programech
V každém programu je alespoň jedna chyba – program na ni musí být připraven Starší programy Program vypsal chybové hlášení a ukončil činnost; V některých situacích (válcovací stolice, autopilot, …) nepřijatelné Funkce vrátí hodnotu signalizující chybu Programátor musí neustále testovat, co funkce vrací Knihovna měla pro tyto účely vyhrazenu speciální proměnnou, do níž se v případě chyby zapsal její kód; nahlédnutím do proměnné program zjistil kód poslední chyby Programátor musí neustále testovat, jaká je v proměnné hodnota Některé jazyky (Cobol, PL/1, …) proto přišly s koncepcí ošetření nestandardních situací Copyright © 2006, Rudolf Pecinovský VŠE – 05

5 Ošetření nestandardních situací v Javě
Výjimečná událost = problém, který brání dalšímu vykonávání části kódu Událost je výjimečná v tom, že na rozdíl od běžných problémů nemá program k vyřešení situace dost informaci Program může při výskytu výjimečné události vyvolat výjimku Výjimka (exception) objekt určený k přenosu informací o nastalém problému z místa jeho vzniku do místa, kde bude problém řešen Copyright © 2006, Rudolf Pecinovský VŠE – 05

6 Postup při vyvolání výjimky
Vytvoří se výjimka = objekt typu Throwable (prakticky vždy instance některého z potomků) Vytvořená výjimka se vyhodí = přeruší se běh programu v místě, kde výjimka vznikla, a začne se hledat místo, kde bude daná výjimka ošetřena Ošetření výjimky (handler) by mělo uvést program do stavu, v němž může jeho vykonávání pokračovat Výjimka „probublává“ programem z místa vyhození stále výše a nenarazí-li cestou nikde na své ošetření, zachytí ji virtuální stroj, který na standardní chybový výstup vypíše zprávu o vzniku výjimky Copyright © 2006, Rudolf Pecinovský VŠE – 05

7 Systémová zpráva o vzniku výjimky
Zpráva o vzniku výjimky spolu s názvem vlákna, v němž k výjimce došlo (zde AWT-EventQueue-0) Popis druhu výjimky (aritmetická výjimka dělení nulou) Informace o místě, odkud byla volána metoda, která vyvolala metodu, v níž došlo k vyhození výjimky Název souboru se zdrojovým kódem Informace o místě, odkud byla volána metoda, v níž došlo k vyhození výjimky Číslo řádku zdrojáku, kde došlo k výjimce Úplný název třídy včetně balíčku Název metody Copyright © 2006, Rudolf Pecinovský VŠE – 05

8 Klíčová slova související s výjimkami
try (zkus) Označuje blok kódu, v němž může dojít k výjimce throw (hoď) Příkaz k vyhození výjimky; musí být následován odkazem na existující instanci catch (chyť) Blok ošetřující výjimku, která je zadána jako parametr finally (na konec) Blok s povinnými závěrečnými akcemi nezávisejícími na případném vzniku výjimky throws (hází) Uvození seznamu výjimek vyhazovaných danou metodou Copyright © 2006, Rudolf Pecinovský VŠE – 05

9 Vyvolání a ošetření výjimky v kódu
try { //Kód, který může vyvolat výjimky } catch( Typ1 id1 ) { //Ošetření výjimek typu Typ1 ... catch( TypN idN ) { //ošetření výjimek typu TypN finally { //Kód, který se na závěr VŽDY provede Copyright © 2006, Rudolf Pecinovský VŠE – 05

10 Náznak činnosti try { příkaz1(); příkaz2(); příkaz3(); }
catch ( xxxException e ) { příkazProOšetřeníChyby(); catch (….. finally { ukončovacíPříkazy(); nedojde k vyvolání výjimky = nedojde k chybě Při provádění metody příkaz2 dojde k chybě Byla vyhozena výjimka tohoto typu nebo typu některého z potomků Když je v bloku try vyhozena výjimka, začnou se prohledávat jednotlivé bloky catch a to odshora dolů. Jako blok, jehož příkazy se budou provádět, je vybrán první, jehož parametr je shodného typu jako vyhozená výjimka nebo je předkem tohoto typu. Copyright © 2006, Rudolf Pecinovský VŠE – 05

11 Náznak činnosti try { příkaz1(); příkaz2(); příkaz3(); }
nedojde k vyvolání výjimky = nedojde k chybě try { příkaz1(); příkaz2(); příkaz3(); } catch ( xxxException e ) { příkazProOšetřeníChyby(); catch (….. finally { ukončovacíPříkazy(); dalšíPříkaz(); Při provádění metody příkaz2 dojde k NEošetřené chybě Při provádění metody příkaz2 dojde k ošetřené chybě Byla vyhozena výjimka tohoto typu nebo typu některého z potomků Ostatní bloky catch se přeskočí Ošetření nebylo nalezeno => provede se blok finally a opouští se metoda Když je v bloku try vyhozena výjimka, začnou se prohledávat jednotlivé bloky catch a to odshora dolů. Jako blok, jehož příkazy se budou provádět, je vybrán první, jehož parametr je shodného typu jako vyhozená výjimka nebo je předkem tohoto typu. Copyright © 2006, Rudolf Pecinovský VŠE – 05

12 Náznak činnosti – řádný průběh
try { příkaz1(); příkaz2(); příkaz3(); } catch ( xxxException e ) { příkazProOšetřeníChyby(); catch (….. finally { ukončovacíPříkazy(); dalšíPříkaz(); nedojde k vyvolání výjimky = nedojde k chybě Bloky catch se přeskočí Když je v bloku try vyhozena výjimka, začnou se prohledávat jednotlivé bloky catch a to odshora dolů. Jako blok, jehož příkazy se budou provádět, je vybrán první, jehož parametr je shodného typu jako vyhozená výjimka nebo je předkem tohoto typu. Copyright © 2006, Rudolf Pecinovský VŠE – 05

13 Náznak činnosti – ošetřený výjimka
try { příkaz1(); příkaz2(); příkaz3(); } catch ( xxxException e ) { příkazProOšetřeníChyby(); catch (….. finally { ukončovacíPříkazy(); dalšíPříkaz(); Při provádění metody příkaz2 dojde k ošetřené chybě Byla vyhozena výjimka tohoto typu nebo typu některého z potomků Ostatní bloky catch se přeskočí Když je v bloku try vyhozena výjimka, začnou se prohledávat jednotlivé bloky catch a to odshora dolů. Jako blok, jehož příkazy se budou provádět, je vybrán první, jehož parametr je shodného typu jako vyhozená výjimka nebo je předkem tohoto typu. Copyright © 2006, Rudolf Pecinovský VŠE – 05

14 Náznak činnosti – neošetřená výjimka
try { příkaz1(); příkaz2(); příkaz3(); } catch ( xxxException e ) { příkazProOšetřeníChyby(); catch (….. finally { ukončovacíPříkazy(); dalšíPříkaz(); Při provádění metody příkaz2 dojde k NEošetřené chybě Ošetření nebylo nalezeno => provede se blok finally a opouští se metoda Když je v bloku try vyhozena výjimka, začnou se prohledávat jednotlivé bloky catch a to odshora dolů. Jako blok, jehož příkazy se budou provádět, je vybrán první, jehož parametr je shodného typu jako vyhozená výjimka nebo je předkem tohoto typu. Copyright © 2006, Rudolf Pecinovský VŠE – 05

15 Vyvolání výjimky public class Xyz implements Comparable { public bolean compareTo( Object o ) if( !(o instanceOf Xyz) ) throw new ClassCastException ( "\nPokus o porovnání s neporovnatelnou" + " instancí " + o ); //Zjištění, kdo je větší return vysledek; } Instanci nemusíme vytvářet až v příkazu throw, můžeme ji vytvořit kdykoliv před tím a pak mu ji jen předat Copyright © 2006, Rudolf Pecinovský VŠE – 05

16 Výjimky kontrolované a nekontrolované
Hierarchie výjimek Pořadí výjimek v blocích catch Metody generující výjimky Metody třídy Throwable Zřetězené výjimky Převod kontrolovaných na nekontrolované

17 Charakteristika Výjimky, které jsou potomky třídy RuntimeException nebo Error označujeme jako nekontrolované (unchecked), protože překladač nekontroluje, zda je na ně program připraven Ostatní výjimky označujeme jako kontrolované (checked), protože překladač kontroluje dodržení pravidel: Každá metoda, která může vyhodit kontrolovanou výjimku, se musí k této skutečnosti veřejně přihlásit Každé použití metody, která může vyhodit kontrolovanou výjimku, musí být buď uzavřeno v bloku try…catch, nebo se volající metoda musí přihlásit k tomu, že může také vyhodit danou kontrolovanou výjimku Nekontrolované výjimky ohlašují chyby v programu, kontrolované výjimky očekávatelné situace, na jejichž výskyt má být program připraven a měl by na ně umět reagovat Copyright © 2006, Rudolf Pecinovský VŠE – 05

18 Hierarchie výjimek NEKONTROLOVANÉ UNCHECKED NEKONTROLOVANÉ UNCHECKED
Copyright © 2006, Rudolf Pecinovský VŠE – 05

19 Pořadí výjimek v blocích catch
Třída NumberFormatException je potomkem třídy RuntimeException try { ...... } catch (RuntimeException e) { catch (NumberFormatException e){ Syntaktická chyba, na druhý blok catch nikdy nedojde Obrácené pořadí bloků catch vše vyřeší try { ...... } catch (NumberFormatException e) { catch (RuntimeException e){ Copyright © 2006, Rudolf Pecinovský VŠE – 05

20 Metody generující výjimky
Java vyžaduje, aby programy, které používají metody schopné vyvolat kontrolované výjimky, byly o této schopnosti používaných metod informovány => pak vědí, které výjimku musí umět zachytit a ošetřit Všechny kontrolované výjimky, které může metoda vyhodit, musí deklarovat v hlavičce za klíčovým slovem throws Deklarace vyhazování nekontrolovaných výjimek není povinná public void metoda() throws KontrolovanáVýjimka1, KontrolovanáVýjimka2 { // Tělo metody } Copyright © 2006, Rudolf Pecinovský VŠE – 05

21 Metody třídy Throwable
String getMessage() Vrátí zprávu popisující danou výjimku String toString() Vrátí název třídy výjimky následovaný případnou zprávou void printStackTrace() Vytiskne toString() následovaný sadou informací o volající posloupnosti, která vedla k vzniku výjimky Throwable fillInStackTrace() Připraví nové informace o volací posloupnosti vedoucí k místu zavolání této metody StackTraceElement[] getStackTrace() Vrátí uchované informace o volací posloupnosti dané výjimky Copyright © 2006, Rudolf Pecinovský VŠE – 05

22 Zřetězené výjimky V některých situacích je vhodné v rámci ošetření výjimky vyvolat jinou výjimku, a přitom umožnit zjistit, která výjimka byla prvotním hybatelem celé akce Řada výjimek má mezi svými konstruktory i takové, které akceptují jako poslední parametr odkaz na výjimku, jež byla příčinou vyvolání dané výjimky Chce-li se program zeptat výjimky na výjimku, která ji způsobila, použije metodu public Throwable getCause() Ve zprávě o vyvolání výjimky jsou místa, kde byla jedna výjimka nahrazena jinou, označována textem caused by: Copyright © 2006, Rudolf Pecinovský VŠE – 05

23 Ukázka výpisu při zřetězení výjimek
HighLevelException: MidLevelException: LowLevelException at Junk.a(Junk.java:13) at Junk.main(Junk.java:4) Caused by: MidLevelException: LowLevelException at Junk.c(Junk.java:23) at Junk.b(Junk.java:17) at Junk.a(Junk.java:11) ... 1 more Caused by: LowLevelException at Junk.e(Junk.java:30) at Junk.d(Junk.java:27) at Junk.c(Junk.java:21) ... 3 more Copyright © 2006, Rudolf Pecinovský VŠE – 05

24 Převod kontrolovaných na nekontrolované
Ošetřování kontrolovaných výjimek obtěžuje Víme-li, že k dané výjimce nejspíš nedojde a ošetřujeme-li ji pouze proto, že na tom překladač trvá, můžeme pro případ, že by k výjimce přece jenom došlo zaměnit kontrolovanou výjimku za nekontrolovanou public void prevod( String s ) { try { prověř( s ); } catch( Exception ex ) { throw new RuntimeException( " Neprověřeno! ", ex ); } Copyright © 2006, Rudolf Pecinovský VŠE – 05

25 Definice vlastních výjimek
Hierarchie výjimek Pořadí výjimek v blocích catch Metody generující výjimky Metody třídy Throwable Vlastní výjimky Zásady správného používání výjimek

26 Definice vlastních výjimek
Výjimky jsou zcela běžné třídy; považujeme-li to proto za vhodné, můžeme definovat i vlastní Před definicí nové výjimky bychom si měli ujasnit, bude-li kontrolovaná či nekontrolovaná; podle toho definujeme jejího předka Název výjimek končí dle konvencí slovem Exception před nímž je naznačena podstata dané výjimky IllegalArgumetnException NoSuchMethodException BadStringOperationException Copyright © 2006, Rudolf Pecinovský VŠE – 05

27 Příklad vlastní kontrolované výjimky
public class VelkýPrůšvihException extends Exception { public VelkýPrůšvihException() {}; public VelkýPrůšvihException( String zpráva ) { super( zpráva ); } public VelkýPrůšvihException(String zpráva, Throwable původce ) { super( zpráva, původce ); Copyright © 2006, Rudolf Pecinovský VŠE – 05

28 Test správného vyhození výjimky
Na vytvářených programech je třeba otestovat i to, že v definovaných situacích vyhodí požadovanou výjimku public void testVyhozeníVýjimky() { try { metodaKteráMáVyhoditVýjimku(); } catch ( VelkýPrůšvihException vpe ) { return; } fail( "Nebyla vyhozena výjimka VelkýPrůšvihException" ); Copyright © 2006, Rudolf Pecinovský VŠE – 05

29 Zásady správného používání výjimek 1/2
Neignorujte výjimky Výjimky, o nichž víte, že nemohou nastat, převeďte na nekontrolované pro případ, že by v budoucích verzích programu nastat mohly Při ošetřování výjimek, které nastat mohou, ale nemají vliv na chod programu, vložte do těla ošetření alespoň vysvětlující komentář try { //Nějaký kód } catch(Exception e){} Copyright © 2006, Rudolf Pecinovský VŠE – 05

30 Zásady správného používání výjimek 2/2
Používejte výjimky pouze k ošetření výjimečných stavů Kontrolované výjimky používejte u stavů, z nichž se lze zotavit, jinak použijte výjimky nekontrolované Vyhýbejte se zbytečnému používání kontrolovaných výjimek Programátory ošetřování kontrolovaných výjimek obtěžuje a mají pak tendenci je ošetřovat prázdným blokem catch Dávejte přednost standardním výjimkám, vyvolávejte výjimky odpovídající dané abstrakci Programátoři by měli z názvu výjimky poznat, co se stalo Standardní výjimky mají všeobecně známý význam Snažte se o atomičnost selhání; i po vyhození výjimky by měl být objekt v dobře definovaném stavu Copyright © 2006, Rudolf Pecinovský VŠE – 05

31 Zásady správného používání výjimek 3/2
Doplňujte výjimky zprávami, výjimka by sama měla poskytnout dostatek informací a neměla by programátora nutit k podrobnější analýze programu Dokumentujte vyvolávané výjimky v dokumentačních komentářích pomocí Nedělejte bloky try zbytečně velké, kód uvnitř těchto bloků se neoptimalizuje Umíte-li výjimku v metodě ošetřit, udělejte to Detekuje-li se chyba v jedné metodě a má se ošetřit v jiné (stejné či jiné instance), použijte výjimku. Copyright © 2006, Rudolf Pecinovský VŠE – 05

32 Nejčastěji používané výjimky 1/2
IllegalArgumentException Byla zadána nepovolená hodnota parametru Např. chci nastavit zápornou velikost grafického tvaru IllegalStateException V daném stavu objektu nelze metodu provést Např. otevřu soubor, přečtu pár vět, zavřu soubor a chci znovu přečíst větu NullPointerException Byla vyvolána metoda instance, na níž ukazuje prázdný odkaz, nebo byl předán nepovolený prázdný odkaz v parametru ArrayIndexOutOfBoundException Byly zadány špatné meze pole, buď záporné nebo moc velké Copyright © 2006, Rudolf Pecinovský VŠE – 05

33 Nejčastěji používané výjimky 2/2
ConcurrentModificationException V průběhu iterace byla změněna struktura kontejneru Např. byl do kontejneru přidán prvek NumberFormatException Je požadován špatný převod řetězce na číslo či naopak Chci-li např. převést na číslo řetězec, který není číslem Častá chyba v metodách String.format či PrintStream.printf ClassCastException Požadované přetypování není možné UnsupportedOperationException Požadovaná operace není podporována (např. chci přidat prvek do neměnného kontejneru) Copyright © 2006, Rudolf Pecinovský VŠE – 05

34 Interní datové typy Charakteristika Rozdělení Globální zanořené třídy
Vnořené třídy Vnitřní třídy – omezení, důvody zavedení Anonymní třídy – definice, omezení, použití Pojmenované lokální třídy

35 Charakteristika Typy definované uvnitř jiných typů Typy mají členy:
Datové – atributy Funkční – metody Typové – interní typy Každý typ, tj. i interní, má vlastní soubor *.class Mohou být potomky libovolné viditelné třídy a implementovat libovolné viditelné rozhraní Jsou uvnitř svých vnějších typů, a proto vidí i na jejich soukromé (private) členy Copyright © 2006, Rudolf Pecinovský VŠE – 05

36 Rozdělení interních tříd
Globální – mimo bloky kódu, tj. na úrovni atributů a metod Statické – Vnořené (nested, embedded, static inner) Nestatické – Vnitřní (inner) Lokální – uvnitř metod a bloků kódu Pojmenované (named) Anonymní (anonymous) Copyright © 2006, Rudolf Pecinovský VŠE – 05

37 Globální interní typy Pro jejich dostupnost a její nastavení platí totéž, co pro dostupnost ostatních členů, tj. atributů a metod Mohou mít nastaveny kterýkoliv modifikátor přístupu public protected „package private“ private Zvenku se k nim přistupuje stejně jako k ostatním členům, tj. kvalifikují se svoji třídou či instancí (např. java.awt.geom.Point2D.Double) Copyright © 2006, Rudolf Pecinovský VŠE – 05

38 Lokální třídy Deklarovány uvnitř bloků kódu
Nejen uvnitř metod, ale uvnitř libovolného bloku kódu Jsou soukromou záležitostí svého bloku Obdobně jako lokální proměnné jsou zvenku nedosažitelné Mohou to být pouze třídy, nelze definovat lokální interface Instance lokální třídy je možno vyvážet mimo daný blok; tam se vydávají za instance svého předka či implementovaného rozhraní Hlavní důvod definice lokálních tříd Copyright © 2006, Rudolf Pecinovský VŠE – 05

39 Vnořené typy (nested, static inner)

40 Charakteristika Deklarovány s modifikátorem static (rozhraní static nepotřebují, protože jiná být nemohou) Jsou to zcela obyčejné typy se všemi jejich možnostmi a omezeními, s výjimkou viditelnosti / dosažitelnosti Vnoření typu do jiného ovlivní pouze Viditelnosti daného typu z okolí Dosažitelnost objektů z definic ve vnořené třídě (z rozhraní není kam dosahovat) Vnoření je pouze otázka jmenného prostoru => vnořené typy můžeme definovat i uvnitř rozhraní (např. java.util.Map.Entry) Copyright © 2006, Rudolf Pecinovský VŠE – 05

41 Důvody zavedení: Třída potřebuje definovat vlastní datový typ, nejčastěji přepravku (pak bývají soukromé) Potřebujeme definovat datový typ, jehož instance budou mít přístup k soukromým atributům své vnější třídy Pro rozhraní je občas vhodné definovat typickou implementaci deklarovaných metod (adaptér) Vnější třída je rodičem svých vnitřních, které přímo přistupují k jejím soukromým atributům Copyright © 2006, Rudolf Pecinovský VŠE – 05

42 Příklad 1: třída Směr8 Statický inicializační blok Deklarace hodnot
public enum Směr8 { //== HODNOTY VÝČTOVÉHO TYPU ================================================== VÝCHOD ( 1, 0, "S", "VÝCHOD", "VYCHOD"), SEVEROVÝCHOD( 1, -1, "SV", "SEVEROVÝCHOD", "SEVEROVYCHOD"), SEVER ( 0, -1, "S", "SEVER", "SEVER"), SEVEROZÁPAD ( -1, -1, "SZ", "SEVEROZÁPAD", "SEVEROZAPAD"), ZÁPAD ( -1, 0, "Z", "ZÁPAD", "ZAPAD"), JIHOZÁPAD ( -1, 1, "JZ", "JIHOZÁPAD", "JIHOZAPAD"), JIH ( 0, 1, "J", "JIH", "JIH"), JIHOVÝCHOD ( 1, 1, "JV", "JIHOVÝCHOD", "JIHOVYCHOD"), ; //== KONSTANTNÍ ATRIBUTY TŘÍDY =============================================== public static final int SMĚRŮ = 8; private static final int MASKA = 7; private static final Map<String,Směr8> názvy = new HashMap<String,Směr8>( SMĚRŮ*3 ); private static final int[][] posun = new int[SMĚRŮ][2]; private static final Směr8[] SMĚRY = values(); static { for( Směr8 s : SMĚRY ) { posun[s.ordinal()][0] = s.přepravka.dx; posun[s.ordinal()][1] = s.přepravka.dy; názvy.put( s.přepravka.zkratka, s ); názvy.put( s.přepravka.název, s ); názvy.put( s.přepravka.názevBHC,s ); s.přepravka = null; } //== DOČASNÉ ATRIBUTY INSTANCÍ =============================================== private static class Přepravka { int dx, dy; String zkratka, název, názevBHC; Přepravka přepravka; //== KONSTRUKTORY A TOVÁRNÍ METODY =========================================== private Směr8( int dx, int dy, String zkratka, String název, String názevBHC ) { přepravka = new Přepravka(); přepravka.dx = dx; přepravka.dy = dy; přepravka.zkratka = zkratka; přepravka.název = název; přepravka.názevBHC = názevBHC; Příklad 1: třída Směr8 Statický inicializační blok inicializující pole a mapu Deklarace hodnot (veřejných konstant) daného typu Přepravka pro dočasné uchování hodnot zadaných konstruktoru, než je bude možno uložit do mapy a příslušných polí Konstruktor ukládá všechny parametry do přepravky, aby je bylo možno vyzvednout ve statickém inicializačním bloku Mapa pro odvození instance ze zadaného názvu Instance si svá data nepamatují ve vlastních atributech, ale v polích, které jsou atributy třídy Copyright © 2006, Rudolf Pecinovský VŠE – 05

43 Příklad 2: IPosuvný.Adaptér
public interface IPosuvný extends IKreslený { public Pozice getPozice(); public void setPozice( Pozice pozice ); public void setPozice( int x, int y ); public static class Adaptér implements IPosuvný public Pozice getPozice() { throw new UnsupportedOperationException(); } public void setPozice( Pozice pozice ) { public void setPozice( int x, int y ) { public void nakresli( Kreslítko kreslítko ) { public class Třída extends IPosuvný.Adaptér { // Definice těla třídy } Copyright © 2006, Rudolf Pecinovský VŠE – 05

44 Vnitřní třídy (inner classes)

45 Charakteristika Deklarovány bez modifikátoru static
Instance vnitřní třídy jsou navázány na instanci vnější třídy –> mají deklarován skrytý konstantní atribut obsahující odkaz na příslušnou instancí vnější třídy Tato vazba potřebuje implementaci => jako vnitřní typ není možno definovat rozhraní Atribut je skrytý, tj. neuvádí se, ale můžeme jej používat –> získání odkazu na instanci vnější třídy: Vnější.this Copyright © 2006, Rudolf Pecinovský VŠE – 05

46 Konstrukce instance vnitřní třídy
V metodě instance Odkaz na příslušnou instanci vnější třídy předá konstruktoru překladač (vezme this a předá je) V metodě třídy Odkaz na příslušnou instanci vnější třídu musí konstruktoru vnitřní třídy předat programátor – učiní tak kvalifikací operátoru new instancí vnější třídy, na níž bude vytvářená instance vnitřní třídy napojena – např.: Vně vně = new Vně(); Vně.Vni vni = vně.new Vně.Vni(); Copyright © 2006, Rudolf Pecinovský VŠE – 05

47 Omezení Nesmějí mít statické atributy a metody – nevědělo by se, jak moc jsou statické Pouze v rámci napojené instance V rámci celé vnější třídy Místo zavádění statických atributů a metod je třeba definovat potřebné atributy a metody v příslušné vnější třídě Při dědění od vnitřní třídy je třeba dceřinému konstruktoru předat v parametru odkaz na její instanci – složité, nepoužívat Copyright © 2006, Rudolf Pecinovský VŠE – 05

48 Důvody zavedení Je třeba exportovat objekt zadaného typu, který by měl přístup k soukromým složkám instance (např. iterátor) Je potřeba pomocný (=soukromý) typ, jehož instance budou mít přímou vazbu na instance své vnější třídy Alternativa pro některé anonymní třídy (někdo nemá anonymní třídy rád, protože znepřehledňují kód) Copyright © 2006, Rudolf Pecinovský VŠE – 05

49 Příklad: Iterátor public class ItPole<Položka> implements Iterable<Položka> { private final Položka [] pole; //Pole položek typu Položka public ItPole(Položka[] pole) { this.pole = pole.clone() } public Iterator<Položka> iterator() { return new Iter(); } private class Iter implements Iterator<Položka> { int index = 0; public boolean hasNext() { return (index < pole.length ); } public Položka next() { return pole[ index++ ]; } public void remove() { throw new UnsupportedOperationException(); } private static void test() { ItPole<Integer> ip = new ItPole<Integer>( new Integer[] { 1, 3, 5, 7, 11, 13, 17, 19 } ); for( Integer i : ip ) { System.out.println( i + "^2 = " + i*i ); Copyright © 2006, Rudolf Pecinovský VŠE – 05

50 Anonymní třídy

51 Charakteristika Jejich definice je součástí příkazu k vytvoření instance; je to na poslední chvíli uvedená definice třídy vytvářené instance Definice anonymní třídy jsou součástí příkazu vytvoření instance, a proto vystupují ve zdrojovém textu jako výraz (píše se za nimi středník či čárka) Nemohou mít vlastní konstruktor; je-li potřeba, používá se místo něj nestatický inicializační blok Mohou používat pouze konečné lokální proměnné (konstanty) některého z bloků, v nichž je anonymní třída definována Důvod: doba života bloku × instance Copyright © 2006, Rudolf Pecinovský VŠE – 05

52 Zápis Tváříme se, že voláme konstruktor rodiče, ale protože ve skutečnosti chceme zkonstruovat potomka, jehož třída navíc ještě neexistuje, tak si ji narychlo vytvoříme Podle zadaných parametrů se pozná, který z rodičovských konstruktorů vytvoří příslušný podobjekt Definice tříd implementujících rozhraní se „tváří“, že rozhraní má implicitní konstruktor; ve skutečnosti se volá konstruktor třídy Object new Rodič(parametry) { //Definice potřebných metod } Copyright © 2006, Rudolf Pecinovský VŠE – 05

53 Omezení 1/2 Mohou používat pouze konečné proměnné (konstanty) bloků, v nichž jsou definovány Důvod: doba života bloku × instance Je-li použitou proměnnou parametr, i on musí být definován jako konečný Nemohou mít vlastní konstruktor; je-li potřeba, používá se místo něj inicializační blok IPojmenovaný vytvoř( final String název ) { return new IPojmenovaný() { String jméno; { jméno = název; } public String getNázev() { return jméno; } }; IPojmenovaný vytvoř( final String název ) { return new IPojmenovaný() { public String getNázev() { return název; } }; Lepší řešení Copyright © 2006, Rudolf Pecinovský VŠE – 05

54 Omezení 2/2 Nemohou definovat statické metody
Teoreticky je místo nich třeba definovat potřebné metody ve vnější třídě, ale tak složité anonymní třídy se nepoužívají Nemohou definovat statické atributy Místo proměnných statických atributů je třeba definovat atributy ve vnější třídě Místo konstantních atributů lze použít konstanty některého z bloků v nichž je definice anonymní třídy zanořena Copyright © 2006, Rudolf Pecinovský VŠE – 05

55 Použití 1: Posluchači událostí 1/3
Nejčastěji se s jejich pomocí na poslední chvíli vyrábí instance požadovaného typu Posluchači událostí Vlákna Instance anonymní tříd je použita jako parametr JButton tlačítko = new JButton( OK ); tlačítko.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent ae ) potvrzeno(); } ); Copyright © 2006, Rudolf Pecinovský VŠE – 05

56 Použití 2: Vytvoření ihned použitého objektu
Objekt vlákna (instance třídy Thread) monu nejprve vytvořit a v dalším příkazu použít Stejně dobře ale mohu čerstvě vytvořený objekt ihned, tj. v témže příkazu použít Thread t = new Thread( "Ukázka" ) { public void run() { metoda(); } }; t.start(); new Thread( "Ukázka" ) { public void run() { metoda(); } }.start(); Copyright © 2006, Rudolf Pecinovský VŠE – 05

57 Použití 3: Funkční výčtové typy 2/3
Instance funkčního výčtového typy jsou instancemi potomka tohoto typu Z venku není dovnitř potomků vidět, takže nevím, jaké metody deklarují => Metody instancí funkčních výčtových typů musí být v rodiči deklarovány jako abstraktní – tím se zviditelní public enum Operace { PLUS { public int proveď( int a, int b) { return a + b; } }, MINUS { return a - b; }; public abstract proveď( int a, int b ); //... Operace op = PLUS; int výsledek = op.proveď( x, y ); Copyright © 2006, Rudolf Pecinovský VŠE – 05

58 Použití 4: Vektory metod 3/3
public interface IOperace { public int proveď( int a, int b ); } IOperace[] op = { new IOperace() { public int proveď( int a, int b ) { return a * b; } }, public int proveď( int a, int b ) { return a / b; } }; Random rnd = new Random(); //... int výsledek = op[ rnd.nextInt(op.length) ].proveď(x,y); Copyright © 2006, Rudolf Pecinovský VŠE – 05

59 Pojmenované lokální třídy

60 Charakteristika Jsou velmi podobné anonymním třídám Odchylky:
Mohou mít vlastní konstruktor Mají jména, takže jejich instance mohu vytvářet na více místech programu Společná omezení Nemohou mít statické členy Z lokálních proměnných bloků, v nichž jsou definovány, mohou používat pouze konstanty Copyright © 2006, Rudolf Pecinovský VŠE – 05

61 Příklad: Filtr souborů
private static <T> void najdiVeSlozce( File koren, Class predek, String balicek, Collection<Class<T>>tridy ) { // Filtr souboru k dalsi analyze - pousti jen class-soubory class Prelozene implements java.io.FileFilter { public boolean accept( File soubor ) { boolean slozka, trida, zajimavy; zajimavy = (slozka = soubor.isDirectory()) || (trida = soubor.getName().endsWith( ".class" ) ); return zajimavy; } for( File f : koren.listFiles( new Prelozene() ) ) { zpracujSoubor( f ); Copyright © 2006, Rudolf Pecinovský VŠE – 05

62 Rozhraní Comparable a Comparator
Typy s definovaným pořadím Rozhraní Comparable Nativní třídění polí a seznamů Problémy související s tříděním Požadavky rozhraní Comparator Třídění s pomocí komparátoru Další metody využívající porovnání Návrhový vzor Příkaz 89–93

63 Typy s definovaným pořadím
Řada hodnotových objektových typů má definované porovnávání hodnot Porovnatelnost hodnot instancí deklaruje třída implementací rozhraní java.lang.Comparable<T> Rozhraní vyžaduje implementaci jediné metody int compareTo( T t ) Vracená hodnota: < 0 je-li this < t = 0 je-li this == t > 0 je-li this > t Copyright © 2006, Rudolf Pecinovský VŠE – 05

64 Požadavky na metodu compareTo(T)
Antisymetričnost: sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) Vztahuje se i na výjimky, tj. když jedno porovnání vyhodí výjimku, mělo by ji vyhodit i to sdružené Transitivnost: (x.compareTo(y)>0 && y.compareTo(z)>0) => x.compareTo(z)>0 Odvoditelnost: x.compareTo(y)==0 => sgn(x.compareTo(z)) == sgn(y.compareTo(z)) Vřelé doporučení: konsistence s equals(Object): (x.compareTo(y)==0) == (x.equals(y)) Copyright © 2006, Rudolf Pecinovský VŠE – 05

65 Nativní třídění polí a seznamů
K třídění polí slouží metody java.util.Arrays.sort(T[] ta) java.util.Arrays.sort(T[] ta, int from, int to) kde typ T může být libovolný primitivní či objektový typ K třídění seznamů slouží metoda java.util.Coolections.sort(List<T> lt) kde typ T může být libovolný objektový typ implementující Comparable<? super T> U objektových typů se předpokládá, že Všechny porovnávané instance implementují rozhraní Comparable Instance jsou vzájemně porovnatelné V opačném případě metoda vyvolá ClassCastException Copyright © 2006, Rudolf Pecinovský VŠE – 05

66 Problémy související s tříděním
V různých fázích práce programu potřebuji třídit podle různých kritérií Např. jednou s rozlišováním velikosti písmen a podruhé bez něj Potřebuji porovnávat instance tříd, které nativně vzájemné porovnání nepodporují Např. hrušky s jablky podle jejich váhy Potřebuji třídit podle jiného kritéria, než je nativní kritérium implementované metodou compareTo(Object) Zákazníci jsou nativně tříděni dle abecedy, ale já je potřebuji setřídit podle jejich dosažitelnosti, solventnosti apod. Třída žádné porovnávací kritérium nedefinuje, ale pro danou situaci mám nějaké vymyšlené Třídím experimenty podle odhadované doby trvání Copyright © 2006, Rudolf Pecinovský VŠE – 05

67 Rozhraní java.util.Comparator<T>
Předchozí problémy lze řešit definicí třídy implementující rozhraní java.util.Comparator<T> Rozhraní Comparator<T> vyžaduje definici metody int compare(T t1, T t2) Vracená hodnota i požadavky na metodu jsou stejné jako u metody compareTo(Object) zaměníme-li u ní this za t1 Třída implementující rozhraní Comparator<T> bývá často definována jako interní (většinou vnořená) Copyright © 2006, Rudolf Pecinovský VŠE – 05

68 Třídění polí a seznamů pomocí komparátoru
K třídění polí slouží metody Arrays.sort(T[] ta, Comparator<? super T> c) Arrays.sort(T[] ta, int from, int to, Comparator<? super T> c) K třídění seznamů slouží metoda Coolections.sort(List<T> lt, Comparator<? super T> c) Instance komparátoru předaná jako parametr musí umět vzájemně porovnat všechny prvky v tříděném poli či seznamu; v opačném případě metoda vyvolá ClassCastException Copyright © 2006, Rudolf Pecinovský VŠE – 05

69 Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable<Modulo2> { private final int hodnota; private final int modul; public Modulo2( int h ) { hodnota = h; modul = h % 10; }//============================================================= public String toString() { return String.format( "%2s", hodnota); private static void tiskni( String s, Modulo2[] mm) { System.out.println( s + Arrays.asList( mm ) ); public static final void test() { Random rnd = new Random(); Modulo2[] mm = new Modulo2[20]; for( int i=0; i < mm.length; mm[i++] = new Modulo2(rnd.nextInt(100)) ); tiskni( "Výchozí: ", mm ); Arrays.sort( mm ); tiskni( "Setříděné: ", mm ); Arrays.sort( mm, new Comp() ); tiskni( "Comparator:", mm ); public int compareTo(Modulo2 m) { return (hodnota - m.hodnota); private static class Comp implements Comparator<Modulo2> public int compare( Modulo2 a, Modulo2 b) { if( a.modul != b.modul ) return (a.modul - b.modul); else return a.hodnota - b.hodnota; } Copyright © 2006, Rudolf Pecinovský VŠE – 05

70 Příklad: Třídění nativní a modulo
Výchozí: [99, 79, 18, 81, 47, 88, 88, 42, 56, 85, 61, 23, 41, 44, 3, 46, 74, 52, 17, 23] Setříděné: [ 3, 17, 18, 23, 23, 41, 42, 44, 46, 47, 52, 56, 61, 74, 79, 81, 85, 88, 88, 99] Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74, 85, 46, 56, 17, 47, 18, 88, 88, 79, 99] public class Modulo2 implements Comparable<Modulo2> { private final int hodnota; private final int modul; public Modulo2( int h ) { hodnota = h; modul = h % 10; }//============================================================= public String toString() { return String.format( "%2s", hodnota); private static void tiskni( String s, Modulo2[] mm) { System.out.println( s + Arrays.asList( mm ) ); public static final void test() { Random rnd = new Random(); Modulo2[] mm = new Modulo2[20]; for( int i=0; i < mm.length; mm[i++] = new Modulo2(rnd.nextInt(100)) ); tiskni( "Výchozí: ", mm ); Arrays.sort( mm ); tiskni( "Setříděné: ", mm ); Arrays.sort( mm, new Comp() ); tiskni( "Comparator:", mm ); public int compareTo(Modulo2 m) { return (hodnota - m.hodnota); private static class Comp implements Comparator<Modulo2> { public int compare( Modulo2 a, Modulo2 b) { if( a.modul != b.modul ) return (a.modul - b.modul); else return a.hodnota - b.hodnota; } Copyright © 2006, Rudolf Pecinovský VŠE – 05

71 Další metody využívající porovnání 1/2
K vyhledání prvku v setříděném polí slouží metody Arrays.binarySearch(T[] ta, T klíč) Arrays.binarySearch(T[] ta, T klíč, Comparator<? super T> c) kde typ T může být libovolný primitivní či objektový typ K vyhledání prvku v setříděném seznamu slouží metody Collections.binarySearch(List<T> lt, T klíč) Collections.binarySearch(List<T> ta, T klíč, Comparator<? super T> c) K získání komparátoru, který třídí v obráceném pořadí, slouží Collections.reverseOrder() Collections.reverseOrder(Comparator<T> cmp) Copyright © 2006, Rudolf Pecinovský VŠE – 05

72 Další metody využívající porovnání 2/2
K vyhledání největšího prvku v kolekci slouží metody Collections.max(Collection<T> coll) Collections.max(Collection<T> coll, Comparator<? super T> c) K vyhledání nejmenšího prvku v kolekci slouží metody Collections.max(Collection<T> coll) Collections.max(Collection<T> coll, Comparator<? super T> c) Copyright © 2006, Rudolf Pecinovský VŠE – 05

73 Zdrojový kód metody max(Collection<T>)
//Deklarace typových parametrů jsou zjednodušené public static <T extends Comparable<T>> T max(Collection<T> coll) { Iterator<T> i = coll.iterator(); T candidate = i.next(); while(i.hasNext()) { T next = i.next(); if (next.compareTo(candidate) > 0) candidate = next; } return candidate; Kolekcí budeme procházet pomocí iterátoru Připravíme si kandidáta na maximum Procházíme zbytkem kolekce, a je-li někdo větší než kandidát, prohlásíme jej za lepšího kandidáta Copyright © 2006, Rudolf Pecinovský VŠE – 05

74 Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené public static <T> T max(Collection<T> coll, Comparator<T> comp) { if (comp==null) return (T)max((Collection<SelfComparable>) (Collection) coll); Iterator<T> i = coll.iterator(); T candidate = i.next(); while(i.hasNext()) { T next = i.next(); if (comp.compare(next, candidate) > 0) candidate = next; } return candidate; private interface SelfComparable extends Comparable<SelfComparable> {} Je-li dodán komparátor, připraví si iterátor a kandidáta na maximum Je-li zadán prázdný odkaz na komparátor, zkusíme verzi bez komparátoru Pak pokračuje stejně jako minule, jenom s jinou metodou porovnání hodnot Verze bez komparátoru vyžaduje nativně porovnatelné objekty – definuje si soukromé vnořené rozhraní, na něž se pokusí instance přetypovat Copyright © 2006, Rudolf Pecinovský VŠE – 05

75 Děkuji za pozornost Rudolf Pecinovský mail: ICQ:

76 Copyright © 2006, Rudolf Pecinovský
VŠE – 05

77 Příklad: Fronta – atributy a metody
public class Fronta<E> implements Iterable<E> { private final List<E> prvky = new LinkedList<E>(); public void zařaď( E e ) { prvky.add( e ); } public E další() { if( prvky.size() == 0 ) return null; E ret = prvky.get(0); prvky.remove(0); return ret; public Iterator<E> iterator() { return new MůjIterator( this ); Copyright © 2006, Rudolf Pecinovský VŠE – 05

78 Příklad: Fronta – vnořená třída
private class MůjIterator implements Iterator<E> { int pořadí = 0; Fronta<E> f; MůjIterator( Fronta<E> fronta ) { f = fronta; } public boolean hasNext() { return (pořadí < f.prvky.size()); public E next() { return f.prvky.get( pořadí++ ); public void remove() { CHYBA(); Protože je definována uvnitř třídy, má přístup k soukromým složkám jejích instancí Neplnohodnotná implementace – volání metody způsobí chybu Copyright © 2006, Rudolf Pecinovský VŠE – 05

79 Příklad: Fronta – Test public static void test() {
Random rnd = new Random(); Fronta<Integer> fronta = new Fronta<Integer>(); System.out.println("===== Začátek testu ====="); System.out.println("Přidáváme:"); for( int i=0; i < 5; i++ ) { Integer číslo = new Integer(rnd.nextInt(100)); fronta.zařaď( číslo ); System.out.print("Přidáno: " + číslo); System.out.print (" Stav:"); //Použití cyklu for(:) na instance třídy Fronta for( Integer fi : fronta ) System.out.print( " " + fi ); System.out.println(""); } System.out.println("\nOdstraňujeme:"); for(;;) { Integer další = fronta.další(); if( další == null ) break; // > System.out.print("Obslouženo: " + další); System.out.println("===== Fronta obsloužena ====="); Copyright © 2006, Rudolf Pecinovský VŠE – 05

80 Pgm Používaná písma a objekty
Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Demi) Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Medium) Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Cond) Příliš žluťoučký kůň úpěl ďábelské ódy (Heavy) Příliš žluťoučký kůň úpěl ďábelské ódy (Franklin Gothic Book) Příliš žluťoučký kůň úpěl ďábelské ódy (Comic Sans MS) Příliš žluťoučký kůň úpěl ďábelské ódy (Consolas) Příliš žluťoučký kůň úpěl ďábelské ódy Příliš žluťoučký kůň úpěl ďábelské ódy Opakování Program Keyword Příliš žluťoučký kůň úpěl ďábelské ódy Copyright © 2006, Rudolf Pecinovský VŠE – 05

81 Konvence syntaktických definic
Syntaktická definice = pravidla zápisu konstrukce jazyka Název – Název definované součásti součást – Název součásti definované jinde program – Text, který se přímo použije (opíše) [ ] – Obsah hranatých závorek je volitelný { | } – Výběr z několika možností oddělených | – Druhou možností je psaní možností pod sebe … – Předchozí položka se může opakovat ¶ – Definice pokračuje na dalším řádku kde bude navíc odsazená Příklad: Identifikátor: písmeno [ { písmeno | číslice } ] … Číslice: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 Originál: P02_Prvni_kod.ppt#23. Konvence syntaktických definic Copyright © 2006, Rudolf Pecinovský VŠE – 05


Stáhnout ppt "Interní datové typy a výjimky"

Podobné prezentace


Reklamy Google