Vaše jistota na trhu IT Interní datové typy a výjimky Rudolf Pecinovský [email protected] Vaše jistota na trhu IT Obsah s odkazy ►Výjimky ►Výjimky kontrolované a nekontrolované ►Definice vlastních výjimek ►Interní.

Download Report

Transcript Vaše jistota na trhu IT Interní datové typy a výjimky Rudolf Pecinovský [email protected] Vaše jistota na trhu IT Obsah s odkazy ►Výjimky ►Výjimky kontrolované a nekontrolované ►Definice vlastních výjimek ►Interní.

Slide 1

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 2

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 3

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 4

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 5

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 6

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 7

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 8

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 9

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 10

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 11

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 12

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 13

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 14

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 15

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 16

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 17

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 18

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 19

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 20

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 21

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 22

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 23

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 24

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 25

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 26

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 27

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 28

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 29

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 30

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 31

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 32

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 33

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 34

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 35

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 36

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 37

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 38

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 39

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 40

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 41

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 42

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 43

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 44

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 45

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 46

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 47

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 48

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 49

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 50

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 51

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 52

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 53

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 54

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 55

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 56

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 57

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 58

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 59

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 60

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 61

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 62

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 63

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 64

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 65

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 66

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 67

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 68

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 69

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 70

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 71

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 72

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 73

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 74

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 75

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{


Slide 76

Vaše jistota na trhu IT

Interní datové
typy a výjimky
Rudolf Pecinovský
[email protected]

Vaše jistota na trhu IT

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

Vaše jistota na trhu IT

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í

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

4

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

5

Postup při vyvolání výjimky
1. Vytvoří se výjimka = objekt typu Throwable
(prakticky vždy instance některého z potomků)
2. 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
3. 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

6

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
Informace o místě, odkud byla volána metoda,
v níž došlo k vyhození výjimky
Úplný název třídy včetně balíčku
Copyright © 2006, Rudolf Pecinovský

Název metody
VŠE – 05

Název souboru se
zdrojovým kódem
Číslo řádku zdrojáku,
kde došlo k výjimce
7

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

8

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

9

Náznak činnosti – řádný průběh
nedojde k vyvolání výjimky
= nedojde k chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

12

Náznak činnosti – ošetřený výjimka
try {
příkaz1(); Při provádění metody příkaz2
dojde k ošetřené chybě
příkaz2();
příkaz3();
Byla vyhozena výjimka
tohoto typu nebo typu
}
některého z potomků
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ostatní bloky catch
catch (…..
se přeskočí
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

13

Náznak činnosti – neošetřená výjimka
Při provádění metody příkaz2
dojde k NEošetřené chybě

try {
příkaz1();
příkaz2();
příkaz3();
}
catch ( xxxException e ) {
příkazProOšetřeníChyby();
}
Ošetření nebylo nalezeno =>
catch (…..
provede se blok finally
a opouští se metoda
finally {
ukončovacíPříkazy();
}
dalšíPříkaz();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

14

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

15

Vaše jistota na trhu IT

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é

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

17

Hierarchie výjimek

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

18

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

VŠE – 05

19

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

20

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

21

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

22

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

23

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

24

Vaše jistota na trhu IT

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

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

26

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

27

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

28

Zásady správného používání výjimek

1/2

Neignorujte
výjimky

try {
//Nějaký kód
}
catch(Exception e){}

► 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ář
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

29

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

30

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í značky @throws
► 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

31

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

32

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

33

Vaše jistota na trhu IT

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

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

35

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

36

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

37

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

38

Vaše jistota na trhu IT

Vnořené typy (nested, static inner)

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

40

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

41

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"), ;

Příklad 1: třída Směr8

TŘÍDY ===============================================
Statický
inicializační
blok
Deklarace
hodnot
Přepravka
pro
dočasné
uchování
int SMĚRŮ = 8;
inicializující
pole
a mapu
(veřejných
konstant)
hodnot zadaných
konstruktoru,
int MASKA = 7;
všechny
daného
typu
Map názvyKonstruktor
= je bude ukládá
než
možno
uložit
do přepravky,
new HashMap(
);
doparametry
mapySMĚRŮ*3
a příslušných
polí
private static final int[][] posun = new int[SMĚRŮ][2];
aby je bylo možno vyzvednout
private static final Směr8[] SMĚRY = values();
ve statickém inicializačním bloku

//== KONSTANTNÍ ATRIBUTY
public static final
private static final
private static final

Mapa pro odvození instance
static {
ze zadaného názvu
Instance si svá data nepamatují ve
for( Směr8 s : SMĚRY ) {
vlastních atributech, ale v polích,
posun[s.ordinal()][0] = s.přepravka.dx;
posun[s.ordinal()][1] = s.přepravka.dy; které jsou atributy tří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;

}
}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

42

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 ) {
throw new UnsupportedOperationException();
}
public void setPozice( int x, int y ) {
throw new UnsupportedOperationException();
}
public void nakresli( Kreslítko kreslítko ) {
throw new UnsupportedOperationException();
}
public class Třída extends IPosuvný.Adaptér
}
{
}
// Definice těla třídy
}
VŠE – 05
43
Copyright © 2006, Rudolf Pecinovský

Vaše jistota na trhu IT

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

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

45

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

46

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

47

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

48

Příklad: Iterátor
public class ItPole implements Iterable
{
private final Položka [] pole; //Pole položek typu Položka
public ItPole(Položka[] pole) { this.pole = pole.clone() }
public Iterator iterator() { return new Iter(); }

private class Iter implements Iterator {
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 ip = new ItPole(
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

49

Vaše jistota na trhu IT

Anonymní třídy

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

51

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

52

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 IPojmenovaný vytvoř(
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

final String název ) {
return new IPojmenovaný() {
String jméno;
{ jméno = název; }
public String getNázev() {
return jméno;
}
};
}
Lepší řešení
IPojmenovaný vytvoř( final String název ) {
return new IPojmenovaný() {
public String getNázev() {
return název;
}
};
}

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

53

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

54

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

55

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
Thread t = new Thread( "Ukázka" ) {
public void run() { metoda(); }
};
t.start();
► Stejně dobře ale mohu čerstvě vytvořený objekt ihned,
tj. v témže příkazu použít
new Thread( "Ukázka" ) {
public void run() { metoda(); }
}.start();

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

56

Použití 3: Funkční výčtové typy

2/3

► Instance funkčního
výčtového typy jsou
instancemi potomka
tohoto typu

public enum Operace {
PLUS {
public int proveď( int a, int b) {
return a + b;
}
► Z venku není dovnitř
},
potomků vidět, takže
MINUS {
nevím, jaké metody
public int proveď( int a, int b) {
deklarují =>
return a - b;
}
► Metody instancí
};
funkčních výčtových
typů musí být
public abstract proveď( int a, int b );
v rodiči deklarovány }
jako abstraktní – tím
se zviditelní

//...
Operace op = PLUS;
int výsledek = op.proveď( x, y );
//...
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

57

Použití 4: Vektory metod

3/3

public interface IOperace {
public int proveď( int a, int b );
}
IOperace[] op = {
new IOperace()
public int
},
new IOperace()
public int
}
};

{
proveď( int a, int b ) {

return a * b; }

{
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

58

Vaše jistota na trhu IT

Pojmenované lokální třídy

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

60

Příklad: Filtr souborů
private static
void najdiVeSlozce( File koren, Class predek, String balicek,
Collection>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

61

Vaše jistota na trhu IT

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

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
► 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

63

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

64

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 lt)
kde typ T může být libovolný objektový typ implementující
Comparable

► 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

65

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

66

Rozhraní java.util.Comparator
► Předchozí problémy lze řešit definicí třídy
implementující rozhraní java.util.Comparator
► Rozhraní Comparator 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
bývá často definována jako interní (většinou vnořená)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

67

Třídění polí a seznamů pomocí komparátoru
► K třídění polí slouží metody
Arrays.sort(T[] ta, Comparator c)
Arrays.sort(T[] ta, int from, int to,
Comparator c)
► K třídění seznamů slouží metoda
Coolections.sort(List lt,
Comparator 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

68

Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable
{
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

69

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]
public class Modulo2 implements Comparable
Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74,
{
private final int hodnota;
85, 46, 56, 17, 47, 18, 88, 88, 79, 99]
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);
VŠE – 05
Copyright © 2006, Rudolf Pecinovský

70

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 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 lt, T klíč)
Collections.binarySearch(List ta, T klíč,
Comparator c)
► K získání komparátoru, který třídí v obráceném pořadí, slouží
Collections.reverseOrder()
Collections.reverseOrder(Comparator cmp)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

71

Další metody využívající porovnání

2/2

► K vyhledání největšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)
► K vyhledání nejmenšího prvku v kolekci slouží metody
Collections.max(Collection coll)
Collections.max(Collection coll,
Comparator c)

Copyright © 2006, Rudolf Pecinovský

VŠE – 05

72

Zdrojový kód metody max(Collection)
//Deklarace typových parametrů jsou zjednodušené
public static >
Kolekcí budeme
T max(Collection coll)
procházet pomocí
{
iterátoru
Iterator i = coll.iterator();
T candidate = i.next();

Připravíme si
kandidáta na maximum

while(i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;

}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

Procházíme zbytkem kolekce,
a je-li někdo větší než kandidát,
prohlásíme jej za lepšího kandidáta

73

Zdrojový kód verze s komparátorem
//Deklarace typových parametrů jsou zjednodušené
public static T max(Collection coll,
Comparator comp)
{
if (comp==null)
return (T)max((Collection)
(Collection) coll);
Iterator i = coll.iterator();
T candidate = i.next();

Je-li dodán komparátor,
připraví
si pokračuje
iterátor
Je-li
zadán
Pak
prázdný
a odkaz
kandidáta
najako
maximum
stejně
na komparátor,
minule,
zkusímejenom
verzi bez
s jinou
komparátoru
metodou

while(i.hasNext()) {
porovnání hodnot
T next = i.next();
if (comp.compare(next, candidate) > 0)
Verze bez komparátoru vyžaduje
candidate = next;
nativně porovnatelné objekty –
}
definuje si soukromé vnořené rozhraní,
return candidate;

na něž se pokusí instance přetypovat
}
private interface SelfComparable
extends Comparable {}
Copyright © 2006, Rudolf Pecinovský

VŠE – 05

74

Vaše jistota na trhu IT

Děkuji za pozornost

►Rudolf Pecinovský
http://vyuka.pecinovsky.cz/vse
mail: [email protected]
ICQ: 158 156 600

Příklad: Fronta – atributy a metody
public class Fronta implements Iterable
{
private final List prvky = new LinkedList();
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 iterator() {
VŠE – 05
Copyright © 2006, Rudolf Pecinovský
return new MůjIterator(
this );

77

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

VŠE – 05

78

Příklad: Fronta – Test
public static void test() {
Random rnd = new Random();
Fronta fronta = new Fronta();
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:");
VŠE – 05
79
Copyrightfor(;;)
© 2006, Rudolf Pecinovský
{