- Funkce velmi často potřebné při běžných výpočtech
- Poskytovány třídou ```java.lang.Math``` (tj. třída Math je umístěna v balíku java.lang a není ji tedy třeba importovat)
- statické metody, musí se tedy **volat s názvem třídy**
- např. ```Math.jménoMetody();```
- Většina metod má parametry typu ```double``` a vrací typ ```double```
- Pro většinu běžných matematických výpočtů se normálně používají reálná čísla
- Někdy mají i celočíselnou variantu, takže podle toho, zda jsou parametry ```int``` nebo ```double```, vrátí ```int``` nebo ```double```
- Kromě metod obsahuje konstanty
- ```Math.PI``` – hodnota π
- ```Math.E``` – hodnota e
- příklad metod
- Absolutní hodnota
- ```Math.abs(i);```
- Větší a menší číslo
- ```Math.max(i, j);```
- ```Math.min(d, e);```
- Zaokrouhlování
- ```Math.round(e);```
### Generování (pseudo)náhodných čísel v Javě
- Třída ```Math```
- Obsahuje metodu ```random()```, která vrací reálné náhodné číslo (typu ```double```) z intervalu <0.0;1.0)
- Např. ```double nahodne = Math.random();```
- - Třída ```Random```
- Třída věnovaná náhodným číslům
- Je umístěná v balíku ```java.util```, před jejím použitím je tedy nutno použít import ```import java.util.Random;```
- Obsahuje různé metody pro generování náhodných čísel s různými pravděpodobnostními rozděleními
- Metody třídy ```Random``` nejsou statické, proto se nevolají nad názvem třídy (jako metody třídy ```Math```)
- Je nutná inicializace podobně jako u třídy ```Scanne```
- ```Random r = new Random();```
- Inicializuje třídu ```Random``` pro generování náhodných čísel s výchozí hodnotou získanou ze systémového času
- Při každém spuštění programu se vygeneruje jiná posloupnost náhodných čísel
- ```Random r = new Random(výchozíHodnota)```
- Inicializuje třídu ```Random``` pro generování náhodných čísel se zadanou výchozí hodnotou (celé číslo typu ```long```)
- Při každém spuštění programu se vygeneruje stejná posloupnost náhodných čísel
- Je jedno, jakou výchozí hodnotu zadáme (vhodné může být např. ```1```), podstatné je, že je konstantní (při každém spuštění stejná)
- Metody se potom volají nad proměnnou ```r```
- Dvě velmi často používané metody
- ```int nextInt(int max)```
- Vrací celé číslo z intervalu <0;max–1>
- ```double nextDouble()```
- Vrací reálné číslo z intervalu <0;1)
- Funguje stejně jako metoda ```Math.random();```
## Problémy při provádění aritmetických operací
- Při provádění aritmetických operací může nastat několik problémů, se kterými je potřeba počítat
### Výsledky celočíselných aritmetických operací implicitně typu int
- Výsledky celočíselných aritmetických operací (tj. hodnota výrazu) jsou v jazyce Java implicitně typu ```int```
- Výjimkou je datový typ ```long``` – pokud je alespoň jeden operand typu ```long```, výsledek aritmetické operace je typu ```long```
- Pokud používáme pouze typ ```int```, s problémem se nesetkáme
- Pokud používáme datové typy s menším rozsahem (```byte, short```), je potřeba výslednou hodnotu výrazu před přiřazením přetypovat
### Celočíselné vs. reálné dělení
- V jazyce Java existuje pouze jeden operátor pro dělení – lomítko „/“, který se používá pro celočíselné dělení (tj. dělení se zbytkem) i reálné dělení
- Typ provedeného dělení záleží na obou operandech
- Pokud jsou oba operandy celá čísla (např. typu ```int```), výsledek je celé číslo – podíl získaný celočíselným dělením
- Pokud je alespoň jeden operand nebo oba operandy reálná čísla (např. typu double), výsledek je reálné číslo – podíl získaný reálným dělením (obecně desetinné číslo)
### Přetečení a podtečení
- Přetečení
- Nastane, pokud do proměnné daného typu uložíme větší hodnotu, než je kapacita daného datového typu
- Např. do proměnné typu ```byte``` uložíme hodnotu 130 (maximální kladná hodnota uložitelná do ```byte``` je 127
- To nelze udělat přímo – dojde k chybě při překladu, ale snadno se to stane při ukládání výsledku aritmetické operace nebo při nevhodném přetypování
- Výsledek přetečení je uložení jiné hodnoty (často s opačným znaménkem, ale není to pravidlo)
- POZOR! – Přetečení není detekováno jako chyba, program se normálně přeloží a spustí => Zda k přetečení dojde, závisí na hodnotách operandů
- Podtečení
- Může nastat pouze u reálných čísel (u čísla nebo jeho exponentu)
- Hodnota, kterou se pokoušíme uložit, je menší než nejmenší zobrazitelná hodnota daným datovým typem (```float``` nebo ```double```)
- Reálná čísla nemají nekonečnou přesnost, mají omezený počet desetinných míst, pokud uložíme velmi malé nenulové číslo (např. 1E-300), může se stát, že bude uloženo jako 0.0
### Porovnávání reálných čísel
- Reálná čísla nemají nekonečnou přesnost, mají omezený počet desetinných míst – dochází k zaokrouhlování
- Proto není vhodné zjišťování, zda jsou dvě reálná čísla shodná, provádět pomocí relačního operátoru ```„==“```
- Např. ```d1 == d2```
- Převést na porovnání, zda je absolutní hodnota rozdílu dvou reálných čísel menší než absolutní chyba porovnání (ε – vhodně zvolená malá reálná konstanta)
- ```Např. Math.abs(d1 - d2) <EPSILON```
## Řídicí struktury
- Řídicí struktury
- Programové konstrukce, které se skládají z dílčích příkazů
- Určují způsob provedení těchto příkazů
- ovlivňují směr provádění programu => bez nich by program běžel postupně od prvního do posledního příkazu
- Tři základní řídící struktury
- Posloupnost
- Příkazy jsou v posloupnosti a vždy se provedou v pořadí, v jakém jsou zapsány („řádku po řádce“)
- Složený příkaz (blok)
- Několik příkazů uzavřených do složených závorek „{“ a „}“
- Např. tělo metody ```main()``` (a jakékoliv jiné metody) je blok
- Často se využívá s větvením a cykly
- Příkazy v bloku důsledně odsazujeme alespoň dvěma mezerami nebo tabulátorem
- V Javě téměř ve všech případech využití bloku otevírací závorce „{“předchází předchozí konstrukce (např. hlavička metody, větvení, cyklus) napsaná na STEJNÉ řádce jako tato závorka
- Větvení
- V závislosti na splnění podmínky se provede jen určitá část programu
- Příkaz ```if``` pro jednoduché větvení (neúplný podmíněný příkaz) a příkaz ```if - else``` pro dvojité větvení (úplný podmíněný příkaz)
- Cyklus
- V závislosti na splnění podmínky se část programu opakuje
- Příkaz ```for```
- pro cyklus s předem známými mezemi (s předem známým počtem opakování)
- Příkaz ```while```
- pro cyklus a předem neznámými mezemi
- Příkaz ```do - while``` pro cyklus s předem neznámými mezemi
### Větvení
- Základem je příkaz ```if - else```, ostatní příkazy pro větvení urychlují nebo zpřehledňují zápis
- Bez větvení nelze vytvářet ani jednoduché užitečné programy s výjimkou jednorázových výpočtů
#### Podmíněný příkaz (příkaz if – else)
- V závislosti na splnění podmínky se provede buď jedna, nebo druhá část programu
- Tyto části se často nazývají „větve“
- Podmínka
- Logický výraz, jehož výsledkem je (booleovská hodnota) buď ```true``` (podmínka je pravdivá, je splněná) nebo ```false``` (podmínka není pravdivá, není splněná)
- Uvádí se bezprostředně za klíčové slovo ```if```
- Je vždy uzavřena do kulatých závorek „(“ a „)“
- Může obsahovat relační operátory (operátory pro porovnání)
- ```„<“, „>“, „<=“, „>=“, „!=“, „==“```
- Může se skládat z více logických výrazů, které jsou spojeny logickými operátory ```„&&“``` („a zároveň“, konjunkce) nebo ```„||“``` („nebo“, disjunkce)
- Bez ohledu na komplikovanost a délku podmínky, jejím výsledkem je VŽDY hodnota ```true``` nebo ```false```
- Úplný podmíněný příkaz (```if - else```)
- Pokud je podmínka splněna (její hodnota je ```true```), provede se první část kódu (uvedená bezprostředně za podmínkou) – „větev ```if```“
- Pokud podmínka není splněna (její hodnota je false), provede se druhá část kódu – „větev ```else```“
- Neúplný podmíněný příkaz (```if```)
- Pokud je podmínka splněna (její hodnota je ```true```), provede se část kódu uvedená bezprostředně za podmínkou
- Pokud podmínka není splněna (její hodnota je ```false```), neprovede se nic
- Vnořený příkaz ```if```
- Příkaz ```if``` může v sobě obsahovat další příkaz ```if```, ten zase další atd.
- Úroveň zanoření není omezena
- Příkaz ```else if```
- Kromě vnořování je možné využít příkaz ```else if```, kdy po klíčovém slově else bezprostředně následuje další příkaz ```if```
- Běžně se využívá
- Možnost reagovat na více podmínek
- Možnost závěrečné ```else``` větve, která se provede, pokud žádná podmínka nebyla splněna
- Vždy se provede maximálně jedna větev (nebo žádná, pokud chybí závěrečné ```else``` a žádná podmínka není splněná)
#### Přepínač (příkaz switch)
- Umožňuje několikanásobné větvení programu na základě hodnoty jedné proměnné
- Proměnná může být typ celočíselný datový typ (```int, byte, short, long```) nebo ```char, String``` a výčtový datový typ
- Lze plně nahradit příkazy ```if – else```
- Není nutné ho používat příliš často, je možné nepoužívat ho vůbec
- Je ale minimálně dobré vědět, jak funguje, když ho použije někdo jiný
- Každá větev (začínající klíčovým slovem ```case```) může být ukončena příkazem ```break;```
```java
switch (proměnná) {
case konstanta1:
příkaz11;
příkaz12;
…
break;
case konstanta2:
příkaz21;
příkaz22;
…
break;
default:
příkazN1;
příkazN2;
…
break;
}
```
- Sémantika příkazu ```switch```
- Nalezne se konstanta odpovídající hodnotě proměnné (nebo vypočtené hodnotě výrazu, pokud je místo proměnné výraz)
- Provedou se všechny příkazy v této větvi
- Pokud je větev ukončena příkazem ```break;```, skočí se na konec přepínače, pokračuje se dalším příkazem za přepínačem
- Pokud větev příkazem ```break;``` ukončena není, pokračuje se s příkazy další větve
- Zdroj častých chyb vedoucí k neočekávanému chování programu
- Umožňuje provést stejnou akci pro více hodnot
- Pokud není nalezena konstanta odpovídající hodnotě proměnné, provedou se příkazy větve ```default```
- Příkaz ```break;``` za větví ```default``` je zbytečný, protože po dokončení posledního příkazu této větve příkaz ```switch``` končí v každém případě, ale většinou se uvádí
- POZOR! – Nikdy nekombinujte použití příkazu ```if - else``` a příkazu ```switch```, značně to znepřehledňuje kód
- Podmínka je libovolný logický výraz s výsledkem ```true``` nebo ```false``` (stejně jako v příkazu if)
- Výrazy jsou libovolné výrazy, jejichž výsledek je stejného datového typu
- Pro přehlednost dávat mezery okolo „?“ a „:“
- Sémantika
- Pokud je podmínka splněná (```true```), vrátí ```výrazTrue```
- Pokud podmínka není splněná (```false```), vrátí ```výrazFalse```
- Ternární operátor vždy vrací hodnotu a nelze použít jako příkaz
- Hodnota musí být přiřazena do proměnné nebo jinak použita, např. může být součástí složitějšího výrazu
## Cykly
- opakování části kódu
- základní pojmy:
- **řídící proměnná cyklu**
- Proměnná, na které závisí ukončení cyklu
- Nejčastěji bývá pouze jedna
- **podmínka ukončující cyklus**
- Logický výraz – cyklus končí, pokud je jeho výsledek false
- **hlavička cyklu**
- Klíčové slovo určující typ cyklu (for, while nebo do) a výrazy v následujících kulatých závorkách
- **tělo cyklu**
- příkazy ve složených závorkách (tj. tvořící blok), které se mají opakovaně provést
- Přestavuje výkonný kód
### Cyklus s podmínkou na začátku (cyklus while)
- Vhodný v případě, že ukončovací podmínka závisí na nějakém výrazu uvnitř cyklu
- Není dopředu jasné, kolikrát cyklus proběhne
- Např. načtení nějakých hodnot až do jejich vyčerpání (např. ze souboru)
- Podmínka, zda má být cyklus proveden se testuje PŘED vykonáním těla cyklu
- syntaxe:
```java
while (výraz) {
příkaz1;
příkaz2;
…
}
```
### Cyklus s podmínkou na konci (cyklus do – while)
- Velmi podobný cyklu while
- Používá se ale mnohem méně (v Javě)
- Podmínka, zda má být cyklus ukončen, se testuje **PO** vykonání těla cyklu
- Tělo cyklu se provede, pak se otestuje podmínka, a pokud je splněna, tělo cyklu se provede znovu
- Cyklus tedy proběhne minimálně jednou
- syntaxe:
```java
do {
příkaz1;
příkaz2;
…
} while (výraz);
```
### Cyklus se známým počtem opakování (cyklus for)
- Vhodný v případě, že jsou předem známá omezující kritéria
- Počáteční a koncová hodnota řídící proměnné a její způsob ovlivnění v každé obrátce cyklu
- V mnoha případech to znamená, že je známý počet opakování
- Podmínka, zda má být cyklus proveden, se testuje PŘED vykonáním těla cyklu
- Cyklus tedy nemusí proběhnout ani jednou
- Inicializace je nastavení počáteční hodnoty řídící proměnné cyklu a často i její deklarace, typicky ``` int i = 0 ```
- Ukončovací podmínka je logický výraz, který by měl obsahovat řídící proměnnou,
typicky ``` i <hodnota```
- Změna řídící proměnné je příkaz, který mění hodnotu řídící proměnné, typicky se jedná o inkrementaci ``` (i++) ```, ale může to být i jiný výraz (např. ``` i += 2 ```)
- syntaxe:
```java
for (inicializace; ukončovací podmínka; změna řídící proměnné) {
příkaz1;
příkaz2;
…
}
```
- Zkrácený zápis pro procházení polí a kolekcí
```java
int[] pole = {6, 7, 8, 9}; //Deklarace pole s inicializaci, bude vysvetleno
for (int prvek: pole) {
System.out.println("Prvek pole: " + prvek);
}
```
### Příkazy break; a continue;
- Příkazy, které ovlivňují chování cyklu nezávisle na řídící proměnné
- Mohou být použity u všech tří cyklů
- Pokud jsou cykly vnořeny do sebe, ovlivňují tyto příkazy cyklus, ve kterém jsou bezprostředně uvedeny
- ``` break ```;
- Okamžitě ukončí cyklus
- Používá se pro předčasné ukončení cyklu (např. při výskytu chyby) či pro řádné ukončení nekonečného cyklu
- ``` continue ```;
- Skočí na konec těla cyklu, čímž si vynutí další obrátku (iteraci) cyklu
- Cyklus neskončí
- Používá se méně než break;
## Metody
- Naprostá většina programů je netriviální a rozsáhlá
- Často potřebujeme jeden výpočet provést vícekrát
- Pokud všechen výkonný kód napíšeme jen do metody ```main```(), budou se části kódu opakovat
- Potřeba dekompozice
- Rozdělení problému na menší podproblémy
- Tyto podproblémy lze rozdělit ještě na menší podproblémy
- Tak postupujeme dále, až dostaneme elementární podproblémy, které jsou snadno řešitelné => postupujeme hierarchicky odshora dolů
- Snadno řešitelné elementární podproblémy mohou být reprezentovány metodami
- Použití metod
- Program se snáze navrhuje
- Je rozdělen na elementární části reprezentované metodami
- Je možné vytvářet program po krocích
- Zdrojový kód je přehlednější
- V daném místě se lze soustředit jen na jednu konkrétní část algoritmu
### Popis metod a terminologie
- metody jsou úseky kódu (podprogramy), které provádějí nějaký výpočet
- Metody by neměly být příliš dlouhé (cca na jednu obrazovku) a měly by dělat jednu jasně definovatelnou činnost popsanou jejich názvem
- Je třeba rozlišovat deklaraci/definici metody a volání/použití metody
### Deklarace metody
- Deklarace metody znamená, že vytvoříme (napíšeme) metodu
- včetně jejího názvu a výkonného kódu
- POZOR! – Tento kód se však provede až při volání metody
- Každá metoda se skládá z hlavičky a těla
- Hlavička metody
- Obsahuje „popis vlastností“ metody včetně jejího jména
- ``` právo static návratováHodnota název(parametry) ```
- Např. ``` public static double naDruhou(double x) ```
- ```public ``` je přístupové právo
- ```static ``` značí, že se jedná o statickou metody třídy
- Existují i metody bez ```static```, tzv. metody instance, kterých je ve skutečnosti většina
- Název metody začíná malým počátečním písmenem, každé další slovo víceslovného názvu začíná velkým písmenem
- Podobně jako u názvu proměnných
- U dokumentačního komentáře metody se uvádí alespoň jedna řádka popisující účel metody, případné parametry metody a návratová hodnota jsou popsány na dalších řádkách
- např.:
```java
/**
* Ukazka deklarace metod - vypocet vzdalenosti dvou bodu v rovine
*@author Tomas Potuzak
*@version 1.0 (2018-08-13)
*/
```
- Tělo metody
- Obsahuje výkonné příkazy uzavřené do složených závorek
- V Javě se otevírací závorka píše na řádku hlavičky metody
- Metoda je jednoznačně určena třídou, ve které je deklarována, svým názvem, počtem, typem a pořadím svých parametrů a návratovou hodnotou
- Přesto se ve vysvětlujícím textu (nikoliv ve zdrojovém kódu) běžně používá pouze název metody se závorkami (např. ``` naDruhou ```()), pokud nehrozí záměna za jinou metodu
- Každá metoda musí být deklarována přímo uvnitř třídy
- Není možné deklarovat metodu mimo třídu
- Není možné deklarovat metodu uvnitř jiné metody
- Metody se typicky deklarují po deklaraci proměnných (např. deklarace ```Scanner```u) kvůli přehlednosti
- Mohou být ale deklarovány kdekoliv uvnitř třídy
- Pořadí deklarace metod **je** (v Javě) **irelevantní**, každá metoda je platná (je viditelná) v celé třídě => metoda může být deklarována až za místem, kde již byla volána
### Volání (použití) metody
- Volání metody znamená, že se provede kód umístěný v těle metody na místě programu, kde metodu voláme (použijeme)
- Pokud chceme metodu použít (tj. chceme, aby provedla svou činnost (výpočet) na určitém místě), použijeme její jméno a do závorek napíšeme hodnoty skutečných parametrů, které nahradí formální parametry v hlavičce metody
- Pokud použijeme metodu ve stejné třídě, jako ve které je deklarována (tj. voláme ji z jiné metody téže třídy), voláme ji pouze jejím jménem a hodnotami parametrů
- ``` metoda(parametry); ```
- Pokud použijeme metodu vně třídy, ve které je deklarována, musíme před název metody přidat název třídy, ve které je deklarována (tečková notace)
- ``` Třída.metoda(parametry); ```
- Toto platí pouze pro metody označené klíčovým slovem ```static```
### Lokální proměnné
- Jsou definovány **UVNITŘ** metod
#### Viditelnost lokálních proměnných
- Jsou viditelné (tj. mohu je používat pro čtení a zápis) **pouze uvnitř metody**
- Jsou viditelné od místa (řádky), kde byly deklarovány
- Jsou viditelné do konce bloku, ve kterém byly deklarovány
- Rozdíl oproti proměnným definovaným UVNITŘ třídy, ale VNĚ metod (proměnné třídy), které jsou viditelné v rámci třídy i před místem deklarace (podobně jako metody)
- Pokud jsou deklarovány přímo v těle metody (tj. ne uvnitř vnořeného bloku), jejich viditelnost končí s tělem metody
- Pokud jsou definovány uvnitř vnořeného bloku (např. v příkazu if nebo v cyklu), jejich platnost končí koncem bloku
- Zastíní proměnnou třídy (a instance) pokud se jmenuje stejně
- Je možné deklarovat lokální proměnnou, která se jmenuje stejně jako proměnná třídy
- Společný název (identifikátor) pak odkazuje na **LOKÁLNÍ** proměnnou, ne na proměnnou třídy
- Potenciální zdroj problémů => je potřeba dát pozor, o jakou proměnnou se jedná (lokální/třídy/instance)
- IDE nástroje většinou druh proměnné odlišují barvou či řezem písma pro větší přehlednost
- Lokální proměnné ve vnořených blocích
- Všechny lokální proměnné deklarované před vnořeným blokem jsou platné (viditelné) i v tomto bloku => nelze definovat novou lokální proměnnou se stejným názvem
#### Inicializace lokálních proměnných
- Lokální proměnné nejsou implicitně inicializovány na ```0, 0.0, false``` nebo ```null```
- Na rozdíl od proměnných třídy (a proměnných instance)
- Je vhodné je inicializovat ručně (explicitně)
- Např. ``` int i = 0; ```
### Návratová hodnota metody a příkaz return
- Existují **dva typy metod**:
- Metody **s návratovou hodnotnou** (**funkce**)
- Metody **bez návratové hodnoty** (**procedury**)
#### Metody s návratovou hodnotou (funkce)
- Metoda může vracet návratovou hodnotu, která může být libovolného typu (základní datový typ, třída, pole, ...)
- Pokud metoda vrací návratovou hodnotu, jedná se o funkci
- Typ je specifikován těsně před názvem metody
- Pro určení návratové hodnoty uvnitř těla metody se používá příkaz (klíčové slovo) ```return```, za který se uvede výraz s odpovídajícím typem výsledné hodnoty
- ```return výraz;```
- Výraz může být libovolně komplikovaný nebo se může jednat o samotnou proměnnou (nebo výjimečně i pojmenovanou/nepojmenovanou konstantu)
- Volání metody s návratovou hodnotou
- Výsledkem volání metody je její návratová hodnota, ale může mít i další efekty
- Např. může ovlivnit hodnoty proměnných třídy (nebo mnohem častěji proměnných instance)
- Pokud je primárním výsledkem volání metody (funkce) její návratová hodnota, je většinou volána jako součást výrazu
- Pokud primárním výsledkem volání metody (funkce) je jiná činnost, kterou provádí, a návratová hodnota je (někdy) vedlejší, lze jí volat jako příkaz (tj. ne jako součást výrazu)
- Vrácená hodnota se zahodí (nikam se nepřiřadí a nepoužije se)
#### Metody bez návratové hodnoty (procedura)
- Metoda nevrací žádnou návratovou hodnotu, pouze provede nějakou činnost => pak se jedná o proceduru
- Při deklaraci metody se místo návratového typu uvede klíčové slovo void
- Např. ```public void vypisNahodnaCisla()```
- Volání metody bez návratové hodnoty
- Metoda se volá pouze jako příkaz, nemůže být součástí výrazu jako metoda s návratovou hodnotou
#### Použití příkazu return
- Příkaz return okamžitě ukončí metodu, bez ohledu na to, kde se v metodě nachází
- Příkazů return může být v jedné metodě více (např. v každé větvi příkazu ```if```)
- Pokud metoda vrací návratovou hodnotu (jedná se o funkci), nesmí existovat větev, ve které by příkaz return nebyl (došlo by k chybě překladu)
- Za ním už se nesmí nacházet žádný příkaz, protože se nikdy nemůže provést (dojde k chybě překladu)
- Např. pokud je použit v příkazu ```switch```, nemůžou být jednotlivé větve ukončeny příkazem ```break;```, protože tento příkaz je nedosažitelný
- Příkaz ```return``` se může použít k předčasnému ukončení metody (např. proto, že parametr nemá platnou hodnotu)
- Příkaz return se může použít i k předčasnému ukončení metody bez návratové hodnoty (procedury)
- Pak se použije samotný ```return;```
### Parametry metody
- Metoda může mít „neomezené“ množství parametrů
- Prakticky jich bývá pouze několik (žádný až cca 3 až 5)
- Více parametrů typicky svědčí o špatné dekompozici problému
- Parametry jsou popsány v závorce za názvem metody stejně jako deklarace proměnné typem a názvem
- Parametry mohou být libovolného typu
- Pokud má metoda více parametrů, jsou odděleny čárkou
- U každé proměnné musí být explicitně uveden datový typ, i když je více parametrů stejného datového typu za sebou
- Např. ```double static secti(double a, double b)```
#### Formální a skutečné parametry metody
- Parametry definované v hlavičce metody (při deklaraci metody) se nazývají **formální parametry**
- Při volání metody jsou v závorce uvedeny **skutečné parametry metody**
- Musejí odpovídat počtem a datovým typem (ve správném pořadí)
- Může se jednat o proměnné, pojmenované/nepojmenované konstanty a výrazy (datový typ výsledku výrazu musí odpovídat datovému typu formálního parametru)
- Ve formálních parametrech (proměnných) jsou do metody předány hodnoty skutečných parametrů metody
- Tyto hodnoty typicky ovlivňují chování metody
- Formální parametry mají v těle metody všechny vlastnosti lokálních proměnných, typicky se ale jejich hodnoty jen čtou
- Je možné do nich přiřadit hodnotu, tím se ale ztratí hodnota předaná do metody => do formálních parametrů nové hodnoty v těle metody nepřiřazovat
#### Mechanizmus předání parametrů do metody
- Parametry jsou předávány vždy **hodnotou**
- Platí pro základní datové typy i reference
- Hodnoty skutečných parametrů jsou překopírovány a vloženy do odpovídajících formálních parametrů, přes které jsou hodnoty dostupné v těle metody
- Změnit hodnotu formálních parametrů v těle metody je možné, ale změna se nijak neprojeví vně metody
- Kromě toho se přepíše hodnota předaná do metody
### Předávání řízení při volání metod
- Pokud je program rozdělen na metody, neběží lineárně od první řádky po poslední
- Při každém volání metody se „skočí“ na začátek těla metody a začne se provádět její kód
- Tzv. „předávání řízení“
- Při dosažení konce těla metody se skočí zpátky na místo, odkud byla metoda volána, a pokračuje se dalším příkazem
- Volání metody jako parametru jiné metody
- Pokud metoda vrací návratovou hodnotu a tato hodnota je použita jako parametr volání další metody, je možné si ji uložit do pomocné proměnné a tu pak použít jako parametr další metody
- Tento zápis je přehlednější
- Je však také možné volat metodu přímo ve volání další metody
- Tento zápis je úspornější, ale méně přehledný
- Oba zápisy se běžně používají
### Přetěžování metod (overloading)
- V jedné třídě může být deklarováno více metod se stejným jménem
- Metody se pak nazývají přetížené (overloaded)
#### Důvody k přetěžování metod
- Přetížené metody obvykle dělají podobnou činnost, ale mírně se liší
- Protože je možné metody přetížit, není nutné vymýšlet podobné názvy podobných metod, můžeme rovnou použít stejný název
- Dělají stejnou činnost pro různý datový typ
- Např. metoda ```Math.abs()``` je přetížena 4x pro typ
```int, long, float a double```
- Dělají stejnou činnost, ale s upřesněním
- Typicky přibudou další parametry
#### Požadavky na přetížené metody
- Přetížené metody MUSÍ mít různé hlavičky
- Musí se lišit počtem a/nebo typem a/nebo pořadím typů parametrů
- Nestačí, aby se lišily jen návratovou hodnotou
- Nestačí, aby se lišily jen názvem formálních parametrů
- Názvy formálních parametrů nejsou podstatné – používají se v těle metody, ale při jejím volání je důležitý pouze jejich typ
- Při volání překladač vybere podle skutečných parametrů metodu, která přesně odpovídá počtem, typem a pořadím parametrů
## Konstanty a magická čísla
- Doposud jsme běžně používaly číselné nebo znakové (textové) konstanty přímo ve zdrojovém kódu
- Tzv. literály
- Ve většině případů se taková použití označují jako „magická čísla“ a jsou nevhodná
### Magická čísla
- Magická se nezývají proto, že není jasné, odkud se vzaly
- „Najednou je v programu číslo 2.58. Proč?“
- Nemusí se jednat o čísla, může se jednat i o znakové a textové, případně jiné nepojmenované konstanty
- Velmi znesnadňují úpravu kódu
- I u relativně jednoduchých programů
- Pokud budu program chtít upravit, budu muset magické číslo přepsat na víceromístech
### Pojmenované konstanty místo magických čísel
- Snahou by mělo být důsledně se zbavit magických čísel pomocí pojmenovaných (též symbolických) konstant
- Konstanty mohou být lokální (deklarované uvnitř metody), ale naprostá většina je deklarována jako konstanta třídy (tj. uvnitř třídy, ale mimo metody)
- Konstanta je odlišena od proměnné klíčovým slovem ```final```
- **Názvy konstant** jsou psány **velkými písmeny**, **oddělovač** slov ve víceslovných názvech je **podtržítko**
### Povolené nepojmenované konstanty
- Stejně jako u každého pravidla i u magických čísel existují výjimky, v tomto případě číselné
- Je odůvodnitelné použít malá celá čísla (např. -1, 0, 1, 2), pokud však nemají speciální význam
- Program je dekomponován na objekty (abstrakce objektů z reálného světa), které udržují data a metody, které s daty pracují, pohromadě
### Třída, instance, reference
- Strukturovaný datový typ
- Na rozdíl od základních datových typů, které obsahují pouze jednu hodnotu a nejde je dále členit, třída může obsahovat data ve formě proměnných (atributů) obecně různého typu
- Kromě dat obsahuje metody, které obecně provádějí operace nad těmito daty
- Třída je šablonou pro tvorbu instancí (objektů)
- Název třídy začíná velkým počátečním písmenem, každé další slovo víceslovného názvu začíná velkým písmenem
- U dokumentačního komentáře třídy se uvádí alespoň jedna řádka popisující účel třídy, dále autor třídy a případně verze (s datem poslední úpravy)
### Instance (objekt)
- Je vytvořena podle konkrétní třídy a nese v sobě konkrétní hodnoty atributů (proměnných)
- Od jedné třídy může být vytvořeno více instancí, přičemž každá může mít (a typicky má) jinak nastavené atributy
- Aby bylo možné s atributy a metodami definovanými ve třídě pracovat, je NUTNÉ vytvořit její instanci (neplatí při použití klíčového slova ```static```)
- Tím se vytvoří místo v paměti pro tuto instanci, do kterého se mimo jiné uloží hodnoty jednotlivých atributů
- Rozdíl oproti základním datovým typům, kdy se místo v paměti vytvořilo v okamžiku deklarace proměnné (tj. v okamžiku provedení řádky ```int i;``` se vytvořilo místo v paměti o velikosti 4 byty pro uložení celého čísla)
- Reference
- Abychom mohli pracovat s instancí a jejími atributy a metodami, potřebujeme na ní referenci
- Reference (referenční proměnná) ukazuje na místo v paměti, kde je uložena konkrétní instance
#### Deklarace referenční proměnné a vytvoření instance
- Referenční proměnná se deklaruje stejně jako proměnná základního datového typu, tj. názevTypu názevProměnné;
- ```názevTypu``` je název třídy,
- ```názevProměnné``` je název referenční proměnné
- Pouhou deklarací referenční proměnné ale instance třídy nevznikne
- Po deklaraci (bez inicializace) je referenční proměnná „prázdná“ – není vytvořeno místo v paměti pro instanci a sama referenční proměnná tedy na nic neukazuje
- POZOR! – Pokud se jedná o lokální proměnnou (tj., proměnnou deklarovanou uvnitř metody), je vhodné inicializovat referenční proměnnou hodnotou null
- Hodnota ```null``` (klíčové slovo) explicitně říká, že reference neodkazuje (zatím) na žádnou instanci
- Pokud tuto inicializaci neprovedete, hodnota lokální referenční proměnné není definována a při pokusu o její čtení dojde k chybě (už při překladu programu)
- Vytvoření instance
- Instance se vytvoří pomocí operátoru new (klíčové slovo) a přiřadí se do připravené referenční proměnné
- ```referenčníProměnná = new Třída();```
- Referenční proměnná musí být stejného typu jako vytvářená instance (tj. ```Třída```)
- Nebo typu předka třídy nebo rozhraní implementovaného třídou (viz předměty KIV/PPA2 a KIV/OOP)
#### Přístup k atributům a metodám instance
- K jednotlivým atributům (proměnným) a metodám instance přistupujeme přes referenční proměnnou, která na instanci ukazuje
- Do proměnných (pokud jsou viditelné) lze zapisovat hodnoty a lze je i číst
- ```referenčníProměnná.metodaInstance()```
- Metody lze volat (pokud jsou viditelné)
#### Práce s referenčními proměnnými a instancemi
- Do referenčních proměnných lze přiřazovat nové instance i jiné referenční proměnné
- Na jednu instanci může ukazovat více referenčních proměnných
- Pokud už nějakou instanci nebudeme používat, můžeme do referenční proměnné explicitně přiřadit hodnotu ```null```
- Např. ```pocatek = null;```
- Tím ztratíme referenci na instanci a Garbage Collector ji časem smaže a uvolní tím paměť, kterou instance zabírá
- V Javě neexistuje příkaz pro explicitní smazání instance (a tím pádem „ruční“ uvolnění paměti)
- POZOR! – Pokud má referenční proměnná hodnotu ```null``` (tj. neukazuje na žádnou instanci) nelze přes tuto proměnnou přistupovat k atributům a metodám instance (protože tam žádná instance není)
- Pokus o přístup vede k chybě ```NullPointerException``` za běhu programu (nikoliv při překladu)
- Pokud se může stát (v závislosti na předchozím kódu), že referenční proměnná může být ```null```, nebo může ukazovat na instanci, je vhodné před přístupem k proměnným a metodám instance otestovat, zda je referenční proměnná různá od ```null``` – např. ```if (pocatek != null)```
### Atributy (proměnné) instance
- Protože třídy jsou abstrakce objektů z reálného světa, atributy typicky odpovídají vlastnostem těchto objektů
- Jako atributy jsou reprezentovány pouze ty vlastnosti, které jsou důležité z hlediska výpočtu (funkce programu)
- Každá instance může mít (a typicky má) v atributech uloženy jiné hodnoty
- Atributy (proměnné) instance jsou deklarované uvnitř třídy ale MIMO metody
- V deklaraci NEMAJÍ uvedeno klíčové slovo ```static```
- Naprostá většina proměnných v dosavadních programech byla definována uvnitř metod (hlavně ```main()```) a jednalo se tedy o lokální proměnné
- Pokud byly dosud proměnné deklarované vně metod, jednalo se o statické proměnné třídy (s klíčovým slovem ```static``` – např. používané deklarace ```Scanner```u pro čtení z klávesnice)
- Dokumentační komentáře jsou typicky jednořádkové a stručně popisují účel proměnné
- Atributy se typicky deklarují na začátku třídy (před všemi metodami)
- Kvůli přehlednosti
- Atribut má viditelnost (je použitelný) přes celou třídu (i před místem deklarace), podobně jako metody
- Atributy (proměnné) instance mohou být libovolného datového typu (primitivní datový typ, třídy nebo pole) - Není žádné omezení
- U lokálních proměnných (deklarovaných uvnitř metod) bylo doporučeno provést inicializaci hned při deklaraci (např. ```int i = 0;```), aby se nestalo, že se pokusíme číst z proměnné její hodnotu, která ale nebyla nastavená
- U atributů (proměnných) instance to není nutné, protože jsou automaticky (implicitně) inicializovány na ```0, 0.0, false``` nebo ```null```, v závislosti na datovém typu
- Doplnit explicitní inicializaci je možné, ale není to nutné ani vhodné
#### Konstanty instance
- Ve třídě je možné definovat i konstanty instance
- Stejně jako pro lokální konstanty a statické konstanty třídy je nutné přidat klíčové slovo ```final```
- Hodnota konstanty instance nemusí být, stejně jako lokální konstanty, nastavena při deklaraci, ale může být **nastavena později**– u **konstanty instance** to však lze provést **pouze v konstruktoru**
- Vždy však lze **hodnota konstanty nastavit pouze jednou**
- Mnohem častěji se využívají statické konstanty třídy
### Metody instance
- Metody instance představují **operace nad atributy instance**
- Platí pro ně téměř stejná pravidla, jako pro statické metody třídy
#### Deklarace metody instance
- Deklarace se liší od dosud probraných statických metod třídy pouze chybějícím klíčovým slovem ```static``` v hlavičce metody
- Např. ```public double urciVzdalenost(Bod2D b)```
#### Volání metod instance
- Pokud voláme metodu instance ve stejné třídě, v jaké je deklarována (tj. voláme ji z jiné metody téže třídy), voláme ji pouze jejím jménem a hodnotami parametrů
- ``metoda(parametry)``
- Stejné jako u statických metod třídy
- Např. ```int mocnina = naDruhou(x);```
- Pokud použijeme metodu vně třídy, ve které je deklarována, musíme před název metody přidat název referenční proměnné ukazující na instanci, nad níž chceme metodu zavolat
- ```referenčníProměnná.metoda(parametry);```
- Na rozdíl od statické metody třídy, kdy se používá název třídy
### Metody a atributy instance a třídy
- Z předchozích kapitol vyplývá, že existují dva druhy metod a dva druhy atributů
- Metody a atributy (proměnné) instance
- (Statické) metody a atributy (proměnné) třídy
#### Porovnání vlastností metod a atributů instance a třídy
- Metody a atributy (proměnné) **instance** (bez ```static```)
- Každá instance má vlastní hodnoty atributů (proměnných)
- K proměnným instance se přistupuje přes konkrétní referenční proměnnou ukazující na konkrétní instanci
- Metody instance se vně své třídy (kde jsou deklarovány) volají nad konkrétní referenční proměnnou ukazující na konkrétní instanci
- Metody instance mohou uvnitř své třídy volat jiné metody instance i metody třídy a přistupovat k proměnným instance i třídy
- Při správném objektovém návrhu je to naprostá většina atributů a metod
- Metody a atributy (proměnné) **třídy** (se ```static```)
- Každá proměnná třídy má jen jedno paměťové místo a může tak mít jen jednu hodnotu, bez ohledu na to, kolik instancí třídy existuje
- Paměťové místo pro proměnnou třídy existuje, i když žádná instance ještě neexistuje
- K proměnným třídy se vně jejich třídy přistupuje přes název třídy
- Metody třídy se vně své třídy volají nad názvem třídy
- Metody třídy mohou uvnitř své třídy volat pouze metody třídy a přistupovat pouze k proměnným třídy (metody a proměnné instance deklarované v téže třídě, tj. bez ```static```, jsou pro ně nepřístupné)
- Při správném objektovém návrhu jich není mnoho
- Výjimkou jsou konstanty třídy, které jsou podstatně častější než konstanty instance
#### Použití metod a atributů (proměnných) instance
- Atributy instance obsahují data konkrétní instance třídy
- Metody instance provádějí operace nad těmito konkrétními daty
- Díky tomu, že metody instance mají přístup k atributům instance přímo, tato data se nemusí předávat (a nepředávají) jako parametry metod
- Metody instance jsou poměrně často bez parametrů, protože většinou pracují s proměnnými instance, ke kterým mají přímý přístup (aniž by musely být předávány jako parametry metody)
- Pokud v programu od třídy vytvářím instanci či instance, většina atributů a metod bude instance, nikoliv třídy
- Výjimku tvoří konstanty instance, které se v programech používají minimálně
#### Použití metod a proměnných třídy
- Použití konstant třídy
- Konstanty v dané třídě jsou ve většině případů stejné pro všechny instance => **není vhodné používat konstanty instance**
- **Konstanta třídy** zabírá **pouze jedno paměťové místo** (na rozdíl od konstanty instance, kde je zabráno tolik paměťových míst, kolik je instancí)
- Pro získání hodnoty konstanty třídy se nevytváří instance, přistupuje se k ní přes název třídy (např. ```Math.PI```)
- Uvnitř třídy není název třídy nutný
- Konstanty mají obvykle přístupové právo ```public```
- Konstantě třídy lze přiřadit hodnota pouze přímo v deklaraci, není možné ji inicializovat později
- Použití statické konstanty třídy je vidět např. na Obr. 13.2
- Použití proměnných třídy
- Málo časté
- Hodí se, pokud potřebujeme, aby byla proměnná jen jedna pro všechny instance
- Např. doporučené použití třídy ```Scanner``` pro čtení ze standardního vstupu
- ```public static Scanner sc;```
- Aby ```Scanner``` fungoval správně na standardní vstup, je potřeba mít jen jeden v celém programu. Tento požadavek splňuje právě statická proměnná ```sc```, přes kterou pak lze provádět čtení kdekoliv v programu
- Do proměnné ```sc``` se přiřadí instance hned na začátku metody ```main()``` a tato instance se pak používá pro veškeré čtení
- Použití metod třídy
- Vstupní bod programu – metoda ```main()``` – je metoda třídy (statická)
- To vychází z toho, že na začátku programu není k dispozici instance žádné třídy, a tedy nemůže být spuštěná metoda instance
- Pokud potřebuji pomocnou metodu, kterou volám v metodě ```main()```, musí to být rovněž metoda třídy (statická)
- Zde stojí za zvážení, jestli není lepší v metodě ```main()``` vytvořit instanci a nad ní pak volat libovolné metody instance
- Metody, u kterých se nevyplatí vytvářet instanci
- Je mnoho metod, které realizují nějaký výpočet, ke kterému nepotřebují instanční proměnné ani jiné vlastnosti instance (např. matematické výpočty – metody třídy ```Math```)
- U takových metod je vhodné, aby byly metody třídy (statické), protože se nemusí vytvářet instance a volají se přímo nad názvem třídy
- Více takových metod může být deklarováno v tzv. utility třídě
- Volání je pak možné z jakékoliv metody (třídy či instance)
#### Mechanizmus předání referenčních parametrů metod
- Metody instance i statické metody třídy mají stejný mechanizmus předávání hodnot parametrů metod
- Hodnoty parametrů se předávají hodnotou
- Platí jak pro parametry primitivních datových typů, tak i referencí (typu třídy, ukazujících na instance)
- Stejný mechanizmus má ale různé důsledky
- Pro primitivní datové typy se změna hodnoty formálního parametru uvnitř metody neprojeví vně metody (protože hodnota parametru je pouze kopií)
- Obsah referenční proměnné je však pouze odkaz ukazující na instanci (na rozdíl od proměnné primitivního datového typu, která obsahuje hodnotu přímo, např. celé číslo)
- Pokud překopírujeme odkaz, bude pořád ukazovat na stejnou instanci => změny provedené v této instanci SE PROJEVÍ i vně metody
### Konstruktor
- Při vytváření instance třídy operátorem ```new``` je vhodné nastavit počáteční hodnoty atributů této instance (objektu) – pro to slouží tzv. konstruktor
- Konstruktor
- Speciální metoda (instance) pro inicializaci objektu
- Musí se jmenovat stejně jako třída (včetně velikosti písmen)
- Nemá žádnou návratovou hodnotu (ani ```void```)
- Podle toho se pozná od ostatních metod (a podle názvu jako třída
- Při vytváření instance za ```new``` ve skutečnosti voláme konstruktor
- Protože se jmenuje stejně jako třída, vypadá to, že uvádíme třídu
- Konstruktor může být bez parametru, nebo může mít „libovolné“ množství a typ parametrů (jako běžná metoda)
- Konstruktor nemusí být ve třídě explicitně uveden, ale pokud je, typicky obsahuje inicializaci atributů instance
- Často s předáním hodnot atributů pomocí formálních parametrů konstruktoru
- Inicializace atributů nemusí být jen hodnotami formálních parametrů, mohou se např. pouze připravovat složitější datové struktury pro další výpočty
- Konstruktor může být (a často bývá) přetížen
- Umožňuje různou inicializaci atributů instance
#### Proměnná ```this```
- V konstruktoru (ale i setrech a dalších metodách) se typicky využívá speciální referenční proměnná ```this```
- Referenční proměnná ```this```
- Je dostupná v každé instanci a ukazuje na „tuto“ instanci (tj. na sebe sama)
- Všechny metody instance volané uvnitř své třídy (tj. z jiných metod instance, bez uvedení referenční proměnné, nad kterou jsou volány) jsou implicitně volány nad proměnnou ```this```, to samé platí pro atributy instance
- Díky tomu je možné používat metody a atributy instance uvnitř jejich třídy bez uvedení instance (implicitně se použije ```this```)
- Explicitní použití ```this``` umožňuje přístup k atributům instance, pokud jsou zastíněny lokální proměnnou nebo parametrem metody/konstruktoru se stejným názvem
- Parametry konstruktoru sloužící pro předání počátečních hodnot atributů instance se typicky jmenují stejně
- Díky ```this``` není nutné vymýšlet jiné názvy formálních parametrů metod/konstruktorů
- Explicitní uvedení ```this``` je možné u metod a atributů instance vždy (i když nedochází k zastínění), ale není to nutné ani příliš vhodné
- přetížení konstruktoru
- Při přetěžování konstruktoru je možné volat jiný konstruktor téže třídy
- Volání jiného konstruktoru musí být první příkaz v konstruktoru
- Volá se pomocí ```this(parametry);```, nikoliv jménem konstruktoru
- Není třeba opakovat kód konstruktoru => používá se běžně
#### Implicitní konstruktor
- Pokud ve třídě není žádný konstruktor uveden volá se při vytváření nové instance implicitní konstruktor bez parametrů
- Tento konstruktor bez parametrů zajistí vytvoření instance v paměti
- Atributy instance jsou implicitně inicializovány na ``0, 0.0, false`` nebo ```null``` podle datového typu
- POZOR! – Pokud do třídy přidáme libovolný explicitní konstruktor, implicitní konstruktor nebude vytvořen!
- Pokud potřebujeme i konstruktor bez parametrů jako doplněk k dalším konstruktorům, musíme ho rovněž explicitně napsat
- Pak je možné použít konstruktor bez parametrů (ale nejedná se o implicitní konstruktor, protože je ve třídě přímo napsaný)
### Zapouzdření a přístupová práva
- Atributy mohou být přístupné z vnějšku třídy
- Tento postup není vhodný, protože umožňuje změnu atributů bez jakékoliv kontroly, což umožňuje mj. zadat neplatné hodnoty
- **Zapouzdření** (encapsulation)
- Atributy objektu jsou **skryté před vnějšími vlivy** pomocí **přístupových práv**
- Pokud je potřeba změnit nastavení atributů, provádí se to prostřednictvím metod, které mohou obsahovat kontroly – tzv. ```setry```
- Tyto metody by měly existovat pouze pro atributy, u kterých chceme jejich změnu z vnějšku třídy umožnit
- Pokud je potřeba získat hodnoty atributů, jsou zpřístupněny metodami nazvanými ```getry```
- Tyto metody by měly existovat pouze pro atributy, jejichž hodnota má být přístupná z vnějšku třídy
- I metody mohou mít nastavená přístupová práva tak, aby je nebylo možné volat z vnějšku třídy
- Typicky pomocné metody
#### Přístupová práva
- Přístupová práva určují, odkud lze k dané metodě nebo atributu přistoupit
- Klíčová slova určující přístupová práva se píší na začátek deklarace
- U atributů před datový typ
- Např. ```private int pocetClenu;```
- U metod před návratovou hodnotu nebo ```void```
- Např. ```public int naDruhou(int x)```
- Přístupová práva (od nejméně po nejvíce restriktivní)
- ```public```
- Metoda/atribut je přístupný odkudkoliv (ze stejné třídy, z jiné třídy stejného balíku, z jiné třídy jiného balíku)
- Typicky se používá pro metody
- ```protected```
- Metoda/atribut je přístupný ze stejné třídy, z jiné třídy stejného balíku a z potomka třídy (viz předmět KIV/OOP)
- Neuvedeno (přístupové právo není explicitně uvedeno)
- Metoda/atribut je přístupný ze stejné třídy a z jiné třídy stejného balíku
- ```private```
- Metoda/atribut je přístupný pouze ze stejné třídy
- Typicky se používá pro atributy
- Přístupová práva u třídy (a také rozhraní – viz předměty KIV/OOP a KIV/PPA2)
- ```public```
- Třída musí být v souboru odpovídající názvu třídy
- Neuvedeno
- Třída může být v jiném souboru, který neodpovídá názvu třídy
- Více tříd pak může být v jednom souboru, ale maximálně jedna může být ```public``` (a její název pak odpovídá názvu souboru)
- Pak ale není viditelná z jiného balíku => nepoužívat
- Jiná přístupová práva pro třídy možná nejsou
#### Getry a setry
- Metody pro přístup k atributům
- Getry začínají slovem ```get``` (anglicky „získat“), v případě atributu typu boolean slovem ```is``` (anglicky „je“)
- Setry začínají slovem ```set``` (anglicky „nastavit“)
- Slova ```get``` a ```set``` se používají, i když píšeme zdrojový kód česky
- Je to konvence pojmenování, která se dodržuje
- Jinak jsou to běžné metody
- Getry
- Hlavička přesně daná pro daný atribut
- ```public datovýTypAtributu getAtribut()```
- ```public boolean isAtribut()```
- Např. ```public int getX()```
- Např. ```public boolean isPrazdny()```
- Vrací hodnotu atributu, typicky obsahují jedinou řádku s příkazem ```return```
- Obsahuje přiřazení hodnoty do atributu předané přes formální parametr setru
- Typicky se používá referenční proměnná ```this``` jako v konstruktoru
- Typicky by měl obsahovat **kontrolu**, **zda je hodnota formálního parametru platná** (přípustná)
- POZOR! – Nastavit hodnotu pouze, pokud je platná, a jinak neudělat nic není nejšťastnější řešení –**reálně se řeší pomocí výjimek**
- Pokud tuto **kontrolu neobsahuje**, pak se vlastně o **zapouzdření nejedná**, protože si můžeme z vnějšku třídy dělat s atributem, co chceme (byť prostřednictvím getru a setru)
- Pokud tuto kontrolu dělá, **měl by být setr použit i v konstruktoru** místo přímého přiřazení
- Přiřazení je bez kontroly, což umožňuje zadat neplatnou hodnotu přes formální parametry konstruktoru
- Běžné metody instance (ne getry a setry) mohou měnit více atributů najednou, čímž vyjádří jednu změnu stavu instance
- Pokud jsou na sobě atributy závislé a neměly by se měnit každý zvlášť, pak by pro ně neměly existovat setry a místo toho by měla existovat metoda měnící konzistentně všechny závislé atributy najednou
### Textová reprezentace objektu
- Objekty (instance), mohou být velmi komplikované (obsahovat mnoho různých atributů), často je ale **potřeba získat textovou reprezentaci** objektu (ve formě řetězce – ```String```)
- **Pro výpis objektu** do příkazové řádky – velmi často během ladění programu
- **Pro zobrazení objektu** např. v seznamu v grafickém uživatelském prostředí (GUI)
- Jsou i další použití
- Vypisování hodnot jednotlivých atributů ručně je zdlouhavé, pokud je atributů více, a kód pro výpis je navíc v jiné třídě => využívá se metoda ```toString()```
#### Metoda toString()
- Metoda vracející textovou reprezentaci objektu (instance)
- Hlavička metody ```public String toString()```
- Tato metoda je implicitně v každé instanci (je zděděna od třídy ```Object``` – viz předmět KIV/OOP)
- Vrací řetězec popisující danou instanci
- Metoda pouze VRACÍ řetězec, sama ho NEVYPISUJE
Tato metoda se volá, pokud chceme objekt (instanci) vypsat pomocí metody ```System.out.println()```
- **Implicitní implementace**
- Vrací řetězec obsahující název třídy, zavináč a číslo určující konkrétní instanci
- Např. ```Bod2D3@15db9742```
- Neobsahuje informace o stavu třídy (např. hodnoty atributů)
- **Vlastní implementace**
- Implicitní metodu lze překrýt **vlastní implementací**
- Stačí ve třídě vytvořit **metodu se stejnou hlavičkou**
- Před metodu je vhodné napsat ```@Override``` indikující, že **metoda je překryta** (overridden)
- Není to nutné, ale např. Eclipse tuto entitu doplní automaticky, pokud necháme metodu ```toString()``` vygenerovat
- Bližší informace viz předmět KIV/OOP
- Metoda musí vracet řetězec, ale ten může obsahovat cokoliv
- Typicky obsahuje hodnoty atributů (při ladění programu), ale záleží na tom, na co chceme textovou reprezentaci třídy použít
- Příklad typické metody ```toString()```
### Porovnání objektů
- Objekty (instance) obecně nejsou uspořádané jako základní datové typy, operátory ```„>“, „>=“, „<“, „<=“``` tedy nelze použít
- Lze však použít porovnání na rovnost (operátor ```„==“```) a také různost (operátor ```„!=“```)
- POZOR! – Má jiný než očekávaný význam
- Výsledkem porovnání je **true**, **pokud se jedná o stejnou instanci** (tj. porovnávané referenční proměnné odkazují na stejnou instanci). **Pokud se nejedná o stejnou instanci**, je výsledkem porovnání **false**
- I když mají **dvě instance stejné třídy stejné hodnoty** všech atributů, výsledek je **false**
- Často je ale potřeba zjistit, zda jsou objekty shodné podle hodnot atributů (některých nebo všech)
- Lze dělat ručně porovnáváním jednotlivých atributů, ale pro více atributů zdlouhavé a kód pro porovnání je v jiné třídě => využívá se metoda ```equals()```
#### Metoda equals()
- Metoda slouží **k porovnání objektu** (instance) **s objektem stejné třídy**
- Hlavička metody ```public boolean equals(Object o)```
- Tato metoda je implicitně v každé instanci (je zděděna od třídy ```Object``` – viz předmět KIV/OOP)
- Stejně jako metoda ```toString()```
- Metoda vrací ```true```, pokud jsou instance shodné a ```false```, pokud jsou instance rozdílné
- **Co je shodné a rozdílné, určuje kód metody**
- Typicky **se porovnávají hodnoty atributů**
- **Implicitní implementace**
- Chová se stejně jako operátor „```==```“
- Vrací **true** pouze v případě, že je **stejná instance**
- **Explicitní implementace**
- Implicitní metodu lze překrýt **vlastní implementací**
- Stačí ve třídě vytvořit metodu se stejnou hlavičkou
- Před metodu je vhodné napsat ```@Override``` indikující, že metoda je překryta (overridden)
- Existují doporučení, jak má kód metody ```equals()``` vypadat (viz předmět KIV/OOP)
- Porovnávaná instance je v parametru, který je typu (třídy) ```Object```
- Aby bylo možné číst atributy porovnávané instance, je potřeba proměnnou explicitně přetypovat na typ třídy naší instance
- Přetypování se zapisuje stejně jako u základních datových typů (název třídy v kulaté závorce)
- Při pokusu o přetypování na nesprávný typ dojde k chybě za běhu programu
- Pak je možné porovnávat jednotlivé atributy
- Příklad implementace metody ```equals()```
### Výčtový typ
- Výčtový typ v Javě je sofistikovanější řešení pojmenovaných konstant
#### Základní použití výčtového typu
- Základní použití výčtového typu se hodí v případě, kdy
- Máme více konstant, které spolu souvisí
- Jejich hodnota je irelevantní
- Deklarace výčtového typu
- Deklaruje se podobně jako třída, místo klíčového slova ```class``` se použije klíčové slovo ```enum```
- Pravidla pojmenování jsou stejná jako pro třídu – počáteční písmeno velké, počáteční písmena všech dalších slov víceslovného názvu velká
- Pokud je označen přístupovým právem ```public```, musí být v samostatném souboru, jehož název odpovídá názvu výčtového typu
- Na začátku obsahuje konstanty, což jsou jednotlivé hodnoty výčtového typu
- Pravidla pojmenování stejná jako pro konstanty – všechna písmena velká, oddělovač slov ve víceslovném názvu je podtržítko
- Konstanty jsou odděleny čárkami
- Použití výčtového typu
- Výčtový typ můžeme využít pro deklarování libovolné proměnné (lokální, instance, třídy), jako návratovou hodnotu metody, atd. – stejně jako jakýkoliv jiný datový typ (základní, třída, pole)
- Do proměnné výčtového typu lze přiřadit pouze jednu z konstant definovaných v deklaraci výčtového typu nebo hodnotu ```null```
- Při použití konstanty je třeba použít název výčtového typu
- ```VýčtovýTyp.KONSTANTA```
- Podobně jako u konstant třídy
- Hodnoty výčtového typu lze porovnávat operátorem „```==```“ s očekávaným výsledkem (na rozdíl od instancí třídy)
- Hodnoty výčtového typu lze přímo vypsat
- Vypíše se přímo název konkrétní konstanty
#### Pokročilé použití výčtového typu
- Výčtový typ má větší možnosti než bylo popsáno
- Může obsahovat proměnné a metody, které se pak vážou k jednotlivým hodnotám výčtového typu
- Např. u typu ```HodnotaKaret``` by bylo možné u každé hodnoty uvést bodovou hodnotu karet
- Podrobnosti viz předmět KIV/OOP
## Uspořádání paměti
- **Paměť je** při vykonávání programu **rozdělena na zásobník a haldu**
- Obě části jsou fyzicky **ve stejné paměti (RAM)**, jen **na jiném místě**
### Zásobník a halda
- **Při vykonávání programu se používají obě části**, některé věci jsou uloženy v zásobníku, jiné na haldě
- **POZOR**!
- **Neplést s datovými strukturami zásobník a halda** (viz předmět KIV/PPA2), jde o něco zcela jiného
- Bohužel v češtině i angličtině je pro obojí stejný název
- Část paměti halda není ani podobná datové struktuře halda
- Část paměti zásobník je principiálně podobný datové struktuře zásobník
#### Zásobník (stack)
- Slouží pro ukládání volání jednotlivých metod
- Při volání metody se vytvoří nový zásobníkový rámec (stack frame), ve kterém se alokuje (tj. vytvoří) místo pro
- Pomocné hodnoty, které Java používá pro řízení běhu programu
- Formální parametry
- Všechny lokální proměnné
- Proměnné základních datových typů jsou zde uloženy přímo
- Lokální referenční proměnné jsou zde uloženy přímo, ale objekty (instance), na které ukazují, jsou uloženy na haldě
- Při dokončení metody se zásobníkový rámec uvolní
- Je podstatně menší než halda (řádově 1 MB)
- Může se stát, že dojde volné místo na zásobníku
- Typicky při vnořeném volání příliš mnoha metod (typicky při použití rekurze – viz předmět KIV/PPA2)
- Program se ukončí a objeví se chyba přetečení zásobníku (```stack overflow```)
#### Halda (heap)
- Slouží **pro ukládání objektů (instancí) a polí**
- Při volání konstruktoru se alokuje místo na haldě potřebné pro uložení objektu, mj. jeho proměnných instance
- Paměť uvolní automaticky garbage collector, když na instanci neukazuje žádná referenční proměnná (ani ze zásobníku, ani z instančních referenčních proměnných uložených v instancích na haldě)
- Paměť nelze uvolnit ručně, ale lze JVM požádat, aby zvýšil úsilí automatického uvolňování paměti na haldě voláním metody ```System.gc();```
- Po dokončení metody JVM udělal vše pro uvolnění paměti odstraněním instancí, na něž již neukazují referenční proměnné
- Je **podstatně větší než zásobník** (většina dostupné paměti – řádově GB)
- Přesto se může stát, že dojde volné místo na haldě
- Typicky při vytváření příliš mnoha a/nebo příliš velkých objektů (nebo polí)
- Program se ukončí a objeví se chyba nedostatku paměti (```out of memory```)
- Při postupném zaplňování paměti se před chybou program typicky zpomalí, což je důsledek zvýšené snahy garbage collectoru o uvolnění paměti
- Oblast metod (method area)
- Část haldy, ve které jsou uloženy přeložené výkonné kódy metod (třídy i instance) a také proměnné třídy
## Pole
- **Strukturovaný datový typ pro uložení více prvků stejného typu**
- Pro uložení více hodnot stejného typu se hodí pole
### Základní práce s (jednorozměrným) polem
- Pole
- Strukturovaný datový typ
- Skládá se z **pevně daného počtu prvků**
- **Je homogenní** – všechny prvky v něm uložené jsou stejného typu
- **Počet prvků se stanoví při inicializaci** (vytvoření) pole a pak již **nelze změnit**
- **Počet prvků je délka pole**, která je v **poli kromě prvků rovněž uložená**
- Indexy
- Jednotlivé prvky pole jsou **přístupné pomocí indexů**
- V Javě má index vždy hodnoty 0 až délka pole - 1
#### Deklarace a vytvoření pole
- Pole je podobné třídám a objektům
- V podstatě se jedná o speciální třídu a při inicializaci pole vytváříme její „instanci“ uloženou na haldě
- Je potřeba deklarovat referenční proměnou a vytvořit novou „instanci pole“ operátorem ```new```
- Stejně jako u objektů je možné udělat obojí najednou, nebo nejprve deklarovat referenční proměnou a později vytvořit nové pole
- ```datovýTyp[] proměnná = new datovýTyp[početPrvků];```
- Při vytváření nového pole se udává počet prvků (v hranatých závorkách „[“ a „]“), které bude pole obsahovat
- Typ prvků pole může být libovolný
- Libovolný základní datový typ
- Libovolná třída
- Protože proměnná typu pole je referenční, může být ```null```
- Pokud se jedná o lokální proměnnou a nevytváříme pole hned při deklaraci jeho referenční proměnné, je rozumné inicializovat referenční proměnnou na ```null```
- Pokud se jedná o proměnnou instance nebo třídy, je inicializována na ```null``` implicitně
- Při vytvoření pole jsou jeho jednotlivé prvky implicitně inicializovány na ```0, 0.0, false``` nebo ```null``` podle datového typu pole
- I v případě, že referenční proměnná ukazující na pole je lokální
- Vytvoření pole výčtem hodnot
- Pole je kromě operátoru ```new``` možné vytvořit i výčtem jeho hodnot uvedeným ve složených závorkách ```„{“``` a ```„}“```
- Pole má stejné vlastnosti jako pole vytvořené operátorem ```new``` – délku pole určí překladač podle počtu prvků
- Často používáno jako vzorová data pro usnadnění ladění, nebo uložení pole konstantních hodnot
- POZOR! – Takto definované pole nemá konstantní prvky, **jeho prvky lze libovolně měnit**, např. ```fibonacci[3] = -6;```
- POZOR!
- Samotným výčtem hodnot lze pole vytvořit POUZE PŘI DEKLARACI
- Pokud chceme přiřadit do existující referenční proměnné nové pole výčtem hodnot, musí samotnému výčtu předcházet vytvoření pole operátorem ```new``` bez udání počtu prvků
- Použití klíčového slova ```final``` nezajistí, aby prvky pole po prvním přiřazení nešly změnit
- ```final``` pouze zajistí konstantnost referenční proměnné – nelze do ní již přiřadit jinou hodnotu (tj. jiné pole)
- Prvky pole, na které ukazuje ```final``` referenční proměnná lze ale měnit bez problémů
- To samé platí pro referenční proměnné a instance tříd – hodnoty atributů (proměnných) instance lze měnit, i když je referenční proměnná ukazující na instanci označena jako ```final```
#### Přístup k prvkům pole a jeho délka
- K jednotlivým prvkům pole se přistupuje pomocí indexu
- Index se zapisuje za referenční proměnou do hranatých závorek
- ```proměnná[index]```
- Prvek pole se chová stejně jako proměnná odpovídajícího datového typu
- Lze do něj zapisovat hodnotu
- Lze z něj číst hodnotu
- Např. ```teploty[0] = 17.5;```
- Např. ```double teplota = teploty[0];```
- Délka pole
- Každé pole má v sobě informaci o délce uloženou v proměnné ```length```
- Volá se přes tečkovou notaci stejně jako proměnná instance nad referenční proměnnou pole
- Např. ```int pocetTeplot = teploty.length;```
- První prvek pole má index 0
- ```Např. double prvniTeplota = teploty[0];```
- Poslední prvek pole má index ```pole.length – 1```
- Např. ```double posledniTeplota = teploty[teploty.length - 1];```
- Index mimo rozsah pole
- POZOR! – Při pokusu o přístup k prvkům se záporným indexem nebo indexem větším nebo rovným délce pole, dojde k chybě za běhu programu (nikoliv při překladu) – je vyhozena výjimka ```ArrayIndexOutOfBoundsException```
- Použití pole jako parametr metody
- Pole může být použito jako parametr metody (stejně jako primitivní datový
typ nebo třída)
- POZOR! – Stejně jako u tříd a instancí platí, že změny provedené v hodnotách pole předaného do metody jako parametr se projeví vně metody
#### Výpis celého pole, inicializace stejnou hodnotou
- Pro práci s poli existuje utility třída ```java.util.Arrays```
- Obsahuje statické metody (podobně jako třída ```Math```) pro práci s poli
- Výpis celého pole
- Metoda ```Arrays.toString()```
- Převede celé pole na řetězec, který lze následně vypsat např. metodou ```System.out.println();```
- POZOR!
- Sama metoda řetězec pouze vrací, nevypisuje ho
- Podobně jako metoda instance toString() u objektů
- Pokud necháme vypsat pole metodou ```System.out.println()``` přímo (bez metody ```Arrays.toString()```), vypíše se pouze identifikace „instance pole“
- Podobně jako implicitní implementace metody instance ```toString()``` u objektů
- Např. volání ```System.out.println(vektor1);``` vypíše např. [D@1b6d3586 (čísla za „@“ se budou při různých spuštěních lišit)
- Inicializace prvků pole stejnou hodnotou
- Prvky pole jsou při vytvoření implicitně inicializovány na ```0, 0.0, false``` nebo ```null``` podle datového typu pole
- Pokud je potřeba inicializovat pole jinou hodnotou (stejnou pro všechny prvky), je možné využít metodu ```Arrays.fill(pole, hodnota);```
- Např. ```Arrays.fill(ciselnaRada, 1);``` naplní všechny prvky pole ```ciselnaRada``` hodnotou ```1```
- Metoda je překrytá pro pole všech základních datových typů a pole typu ```Object```
- Existuje i varianta s určením počátečního a koncového indexu vyplnění pole ```Arrays.fill(pole, indexOd, indexDo, hodnota);```
Např. ```Arrays.fill(ciselnaRada, 0, 2, 10);``` naplní první dva prvky (**počáteční index je včetně**, **koncový není včetně**) pole ```ciselnaRada``` hodnotou ```10```
#### Použití zápisu ```for - each```
- Pokud nepotřebujeme pracovat s indexem pole a stačí nám postupný přístup ke všem jednotlivým prvkům, je možné použít zkrácený zápis cyklu ```for``` (známý též jako ```for - each```)
- ```for (datovýTyp prvek: pole)```
- Cyklus zaručí, že se dostane na všechny prvky – projde se celé pole od začátku do konce
- V každé obrátce cyklu je v proměnné prvek následující prvek pole
- Běžně se používá pro pole (a kolekce – viz předmět KIV/PPA2) objektů
#### Pole jako tabulka, přepočet indexů
- Tabulka
- Datová struktura obsahující dvojice klíč a hodnota
- Pro daný klíč můžeme získat hodnotu
- Viz předměty KIV/PPA2 a KIV/PT
- Pole se dá použít jako jednoduchá tabulka
- Index může sloužit jako klíč
- Hodnota prvku pole jako hodnota
- Indexy pole začínají vždy od 0 – pokud je potřeba jiný začátek klíčů, je potřeba přepočet
#### Reprezentace množiny polem
- Množina
- Soubor prvků (např. čísel) chápaných jako celek
- Každý prvek může být obsažen v množině maximálně jednou
- Pro reprezentaci množiny lze využít pole typu ```boolean[]```
- Indexy odpovídají prvkům množiny
- Hodnoty prvků pole udávají, zda prvek je přítomný v množině (```true```) nebo není (```false```)
### Pole objektů
- Prvkem pole můžou být kromě základních datových typů i instance
- Použití se nijak neliší, jen je potřeba nezapomenout vytvořit instance jednotlivých prvků, což se u základních datových typů nedělá
#### Deklarace pole objektů a jeho inicializace
- Deklarace a vytvoření pole se neliší od polí základních datových typů
- Je potřeba deklarovat referenční proměnnou a vytvořit novou „instanci pole“ operátorem ```new```
- ```Třída[] proměnná = new Třída[početPrvků];```
- Např. ```Vysledek[] vysledky = new Vysledek[POCET];```
- Opět je možné nejprve deklarovat referenční proměnnou a později vytvořit nové pole
- Jednotlivé prvky referenční proměnné na instance třídy odpovídající typu pole
- Po vytvoření pole jsou všechny implicitně inicializovány na hodnotu ```null```
- POZOR! – V tomto okamžiku (po vytvoření pole) tedy jednotlivé instance prvků neexistují – dosud nebyly vytvořeny operátorem ```new```
- Vytvoření instancí prvků pole
- Instanci každého prvku je potřeba vytvořit zvlášť, typicky v cyklu ```for```
#### Přístup k prvkům pole a k proměnným a metodám instance prvků
- Přístup k prvkům pole je stejný jako u polí základních datových typů pomocí indexu v hranatých závorkách „[“ a „]“
- Jednotlivé prvky jsou referenční proměnné ukazující na jednotlivé instance
- Přístup k atributům a metodám instance je přes tečkovou notaci použitou nad prvkem pole
### Vícerozměrná pole
- Pole může mít více rozměrů
- Často se využívají dvourozměrná (např. pro uložení matic), ale mohou být i tří a vícerozměrná
- Pole s více než třemi rozměry většinou nemají reálné opodstatnění
- Pro určení požadovaného prvku pole je potřeba více indexů
- Počet odpovídá počtu rozměrů pole
- Vícerozměrné pole jako **pole polí**
- Dvourozměrné pole v Javě je ve skutečnosti jednorozměrné pole referenčních proměnných, kde každá ukazuje na jednorozměrná pole (tj. „řádku“)
- Díky tomu má každé jednorozměrné pole svou délku, kterou je možné zjistit, a dvourozměrné pole ji má též
- Z dvourozměrného pole tak lze zjistit jeho počet řádek i sloupců
- Každé jednorozměrné pole může mít jinou délku
- Trojrozměrné pole v Javě je pak jednorozměrné pole referenčních proměnných, kde každá ukazuje na dvourozměrné pole, atd.
#### Deklarace a vytvoření vícerozměrného pole
- Deklarace referenční proměnné pro vícerozměrné pole je podobná jako pro jednorozměrné
- Pouze obsahuje více prázdných párů hranatých závorek „[]“ – jeden pár pro každý rozměr pole
- ```datovýTyp[][]…[] proměnná;```
Např. ```double[][] prvkyMatice;```
- Vytvoření všech rozměrů najednou
- Nejběžnější použití vícerozměrných polí
- Počty prvků ve všech rozměrech pole udány najednou
- V případě dvourozměrného pole má každý řádek stejnou šířku
- Tzv. pravoúhlé pole – pole tvoří pravoúhlý obrazec – obdélník, kvádr, teserakt, atd.
- ```proměnná = new datovýTyp[počet1][počet2]…[početN];```
- Např. ```prvkyMatice = new double[vyska][sirka];```
- Vytvoření rozměrů postupně
- Počty prvků v jednotlivých rozměrech udány postupně
- Nejprve vytvoříme „vnější“ pole a pak do jeho jednotlivých prvků přiřadíme nové „instance“ „vnitřních“ polí
- V případě dvourozměrného pole může mít každý řádek různou délku
- Pole je „zubaté“
- ```proměnná = new datovýTyp[počet1][]…[];```
- POZOR!
- Musí se vždy začínat rozměrem nejvíc vně (tj. první závorky zleva)
- Nelze ```proměnná = new datovýTyp[][počet2]…[];```
- Vytvoření pole výčtem hodnot
- I vícerozměrné pole je možné vytvořit výčtem hodnot
- Pole může být pravoúhlé i „zubaté“
- Platí stejná pravidla, jako při vytváření jednorozměrného pole
- Použití samotného výčtu je možné pouze při deklaraci, při pozdějším vytvoření pole je nutné použít i operátor ```new```
#### Přístup k prvkům pole
- Pro přístup k jednotlivým prvkům vícerozměrného pole se používá více indexů
- Počet indexů odpovídá počtu rozměrů pole
- Použití méně indexů než je rozměrů pole
- Při použití méně indexů se nedostaneme k prvku pole, ale k poli s menším rozměrem
- Např. pokud máme dvourozměrné pole a použijeme pouze jeden index, dostaneme se k jednorozměrnému („vnitřnímu“) poli, tj. k „řádce“ pole
- V okamžiku, kdy se dostaneme na „vnitřní“ pole, můžeme zjistit jeho délku
- To se velmi často využívá
- Funguje dobře při procházení vícerozměrného pole, i pokud je pole „zubaté“
- Příklady přístupu k prvkům pole a k „vnitřním“ polím kvůli jejich délce je na
- Deklarace a vytvoření pole ```jednotkovaMatice```
- Kompletní příklad na použití dvojrozměrných polí k násobení matic (v kombinaci s objekty)
- Použitá třída ```Matice```
### Pole v paměti
- Pole je ve skutečnosti instance speciální třídy a je celé uloženo na haldě (heap)
- Jak to vypadá v paměti při práci s poli, je demonstrováno na příkladu s polem primitivního datového typu a na příkladu s polem objektů
- **Pole nulové délky**
- Pole může mít délku 0 prvků
- Pak nemá žádný prvek, do kterého by šla zapsat hodnota, ale může být použitelná informace o nulové délce
- Rozdíl oproti referenční proměnné pole rovné ```null```
- **Referenční proměnná pole rovná null** neukazuje na žádné pole (**žádné pole není na haldě**)
- Pole nulové délky na haldě existuje a ukazuje na něj referenční proměnná, neobsahuje ale žádný prvek
#### Pole primitivních datových typů v paměti
- Pole primitivních datových typů ve své „instanci“ **přímo obsahuje hodnoty jednotlivých prvků**
## Ověřování správnosti programu, ladění
- Při vytváření programů je do zdrojového kódu (neúmyslně) zaneseno mnoho různých chyb od překlepů přes neošetření hraničních případů až po logické chyby v celkovém chování programu
- Část chyb odhalí překladač (a upozorní nás na ně IDE nástroj) – chyby při překladu
- Část chyb překladač neodhalí a program jde přeložit
- POZOR!
- Pokud jde program přeložit, neznamená to, že funguje správně!
- Program může (někdy nebo vždy) dávat nesprávné výsledky
- Může docházet k chybám za běhu programu
- Chyby, které překladač neodhalí (chyby za běhu programu), je třeba najít a opravit opakovaným opravováním, překládáním a spouštěním programu s využitím vhodných vstupních dat
- Tato činnost se nazývá ladění (častěji debugging)
- Lze provádět ručně nebo s využitím specializovaného nástroje zvaného debugger – součást téměř všech IDE nástrojů
- Často se používá kombinace obou přístupů
- Vyšší fází ladění je testování
- Zjišťuje se, zda program pracuje správně pro všechny typy vstupů, zda reaguje správně na neplatné vstupy apod.
- Podrobně viz předmět KIV/OKS
### Odhalení chyb při psaní zdrojového kódu a při překladu
- Překladač ```javac``` umí odhalit především syntaktické chyby
- Často způsobené překlepy v názvech proměnných, metod, zapomenutím na import třídy, zapomenutím deklarace proměnné, atd.
- Všechny nalezené chyby jsou vypsány při překladu
- Překlad v příkazové řádce
- Pokud překládáme program ručně v příkazové řádce příkazem javac, objevíme chyby až po spuštění překladu
- Protože překlad netrvá dlouho (pro malé programy), je možné provádět ho během vývoje opakovaně, např. při každém inkrementálním přidání funkcionality
- Nalezené chyby lze průběžně odstraňovat
- Odstranění chyby se ověří opakovaným překladem
- Je možné i napsat celý program a poté odstranit chyby najednou
- Odstranění chyb se opět ověří opakovaným překladem
- POZOR!
- Při opakovaném překladu se počty chyb mohou snižovat i zvyšovat
- Překladač se snaží při překladu najít co možná nejvíce chyb tj. neskončí při první nalezené chybě, ale pokud to jde, pokračuje dále
- Některé chyby jsou však z pohledu překladače natolik zásadní (ač z pohledu člověka vypadají banálně – např. zapomenutý středník „;“ nebo složená závorka „}“), že mu znemožní kontrolu velké části kódu
- Po opravení takové chyby může překladač tuto přeskočenou část zkontrolovat a tím odhalit další, dosud neodhalené chyby počet chyb může po odstranění chyby vzrůst
#### Čtení a porozumění výstupu překladače
- Výstup překladače (tj. výpis chyb při překladu) se zobrazí po skončení překladu v příkazové řádce nebo v konzoli IDE nástroje
- Výstup nemusí být stejný v IDE a v příkazové řádce
### Ladění (debugging)
- Pokud se **program podaří přeložit**, ještě to **neznamená, že funguje správně**
- Většinou správně nefunguje, i když jde přeložit
- Chyby v chování programu neodhalí překladač, musí je najít sám programátor
- Chybné chování programu se typicky projevuje:
- Program je předčasně ukončen s chybovým hlášením (vždy nebo někdy)
- Je třeba rozumět chybovému hlášení
- Program zdánlivě funguje, ale dává pro některé či všechny vstupy zcela špatné nebo částečně špatné výsledky
- Ladění je možno provádět ručně tzv. metodou ladících výpisů a/nebo s využitím specializovaného ladícího nástroje (debuggeru)
- POZOR!
- Program se nedá považovat za odladěný po vyzkoušení jednoho či několika málo vstupů
- Je potřeba zkoušet více různých vstupních hodnot, netypické hodnoty apod.
- Je potřeba zkoušet i neplatné hodnoty, na něž by měl program adekvátně reagovat
- To však zatím není probráno
#### Chybové hlášení za běhu programu
- Pokud dojde za běhu programu k chybě (přesněji k vyhození výjimky) a tato chyba není v programu ošetřena, program je předčasně ukončen a do konzole (či příkazové řádky) se vypíše chybové hlášení
- Chybové hlášení
- Vypíše, o jakou chybu (výjimku) se jedná (její název a někdy i popis)
- Vypíše tzv. stack trace (výpis zásobníku)
- Zjednodušený obsah zásobníku (stack) programu v okamžiku, kdy k chybě došlo
- Obsahuje volání metod – je jasné, v jaké metodě přesně došlo k chybě (první uvedená metoda) a ze které metody byla tato metoda volána (další uvedená metoda)
- Následují další metody, které byly hierarchicky volány až k metodě ```main()```
- V jednoduchých programech je většinou zobrazeno i číslo řádky, na které k chybě došlo
- Hlášení o chybách za běhu programu typicky vypadají stejně v příkazové řádce i v konzoli IDE nástroje
#### Metoda ladících výpisů
- Metoda ladících výpisů se používá, **pokud nemáme k dispozici debugger**, nebo ho z nějakého důvodu nechceme použít
- Na vhodná místa programu vložíme volání metody System.out.println()
- Můžeme vypisovat hodnoty důležitých proměnných
- Můžeme pomocí výpisu unikátních značek (tj. textů) určit, kde se program
- přesně nachází (podle toho, co a v jakém pořadí program vypíše)
#### Použití debuggeru v Eclipse
- Debugger umožňuje dělat automaticky to, co musíme ručn pomocí kontrolních výpisů a umožňuje mnohem více
- Sledování hodnot vybraných proměnných a výrazů
- Krokování programu řádku po řádce
- Nastavení breakpointů – bodů, ve kterých se program zastaví a umožní od něj krokování
- Spuštění debuggeru v Eclipse
- Vytvoření breakpointu
- Pro zapnutí debuggeru je potřeba nastavit breakpoint, tedy bod, od kterého bude program krokován
- Breakpoint se na určitou řádku nastaví dvojklikem vlevo od požadované řádky
- Alternativou je kliknout pravým tlačítkem na stejné místo => vybrat Toogle breakpoint
- Přítomnost breakpointu na řádce je indikována symbolem
- Stejným způsobem lze breakpoint odstranit
- Spuštění debuggeru
- Mít aktivní třídu s breakpointem
- Debug as… => Java Application
- Pokud si Eclipse není jistý, který program chcete debuggovat, dá vám na výběr
- Pokud není zvolen žádný breakpoint, program proběhne jako při normálním spuštění
- Po spuštění debuggeru program běží normálně, dokud nedosáhne breakpointu
- Potom se objeví dotaz, zda chceme spustit debug perspektivu, která přepne rozložení oken Eclipse
- Popis debug perspektivy v Eclipse
- Okno zásobníku
- Ukazuje, v jaké části programu se právě nacházíme
- Jde o zobrazení části paměti zásobník obsahující rámce pro jednotlivé volání metod
- Toto okno příliš nevyužíváme
- Okno editoru
- Okno se zdrojovým kódem
- V debug perspektivě se zpravidla nepoužívá pro úpravu kódu
- Zelený pruh určuje řádku, na které se program právě nachází při jeho krokování
- Jsou vidět nastavené breakpointy
- Nejdůležitější okno debuggeru
- Okno se strukturou programu (outline)
- Zobrazuje strukturu programu (jednotlivé třídy a metody)
- Toto okno příliš nevyužíváme
- Okno konzole
- Okno, do kterého se vypisuje výstup programu
- Uživatel zde rovněž zadává vstup programu, pokud je třeba
- Okno sledování proměnných
- Zde můžeme sledovat všechny proměnné a jejich aktuální hodnoty během krokování programu
- Druhé nejdůležitější okno debuggeru
- V záložce Breakpoints je seznam všech nastavených breakpointů
- Ovládání debuggeru
- V okamžiku, kdy se program zastaví na breakpointu, lze pokračovat v jeho krokování různými způsoby
- Step Into - též klávesa [F5]
- Provede jeden krok programu
- Pokud je tímto krokem volání metody, skočí do této metody
- Step Over – též klávesa [F6]
- Provede jeden krok programu
- Pokud je tímto krokem volání metody, provede ji celou jako jeden krok (tj. do metody neskočí)
- Step Return – též klávesa [F7]
- Provede všechny zbývající příkazy v metodě, vyskočí z ní a zastaví se na dalším řádku volající metody
- Resume – též klávesa [F8]
- Provede všechny příkazy od aktuální pozice až k dalšímu breakpointu (nebo do ukončení programu) normálně (tj. bez krokování)
- Terminate – též [Ctrl]+[F2]
- Ukončí provádění programu
- Nastavení filtrů krokování (step filters)
- Umožní omezit, do kterých metod je možné při krokování skočit
- Např. nechceme, abychom se při krokování dostali do knihovních tříd a metod Java Core API
- Zapnutí filtrů krokování (Use Step Filters – též [Ctrl]+[F5])
- Pokud je tlačítko zapnuté, filtry jsou použity a do vybraných balíků nevstoupí ani možnost Step Into
- Tento postup jsme používali dosud (aniž jsme věděli o tom, že vznikají instance třídy ```String```)
- Tento postup se používá běžně
- Je možné i přímo vytvořit novou instanci třídy String operátorem ```new```
- Třída ```String``` obsahuje několik konstruktorů umožňující vytvořit řetězec z pole znaků, pole bytů, atd.
- Je možné i vytvořit nový řetězec z jiného řetězce
- Např. ```String pozdrav = new String("Ahoj!");```
- Tento zápis NEPOUŽÍVAT
- Protože samotný zápis literálu "```Ahoj```" způsobí vytvoření nové instance třídy ```String```, volání new ```String()``` zbytečně vytvoří další instanci
#### Konstantnost řetězce
- Řetězce v Javě (tj. instance třídy ```String```) jsou konstantní, neměnné (immutable)
- Nelze do nich přidávat text, mazat, nebo měnit jednotlivé znaky
- Veškeré metody zdánlivě upravující řetězec ve skutečnosti vytvoří novou instanci třídy ```String``` a text v původní instanci zůstane nedotčen
- Existují třídy pro práci s měnitelným řetězcem
- Třída StringBuilder
- Třída StringBuffer
- Přesto si ve většině případů vystačíme s třídou ```String```
- To, že při změně obsahu řetězce dojde k vytvoření nové instance a původní zůstane nezměněná, nám nevadí (v podstatě si toho nevšimneme)
#### Spojení řetězců pomocí operátoru „+“ (zřetězení)
- Od začátku jsme běžně používali
- Především v metodě ```System.out.println()```
- Operátor „+“ spojí dva řetězce (operandy) a vytvoří novou instanci obsahující texty obou řetězců (operandů)
- Operátor „+“ také umožňuje připojit k řetězci libovolný datový typ
- Hodnota daného typu se převede na řetězec
- Alespoň jeden operand musí být řetězec, pokud ne, má operátor „+“ význam sčítání
- Pro přehlednost je lepší začínat řetězcem, pokud nechceme začínat uvozujícím textem, lze použít prázdný řetězec
- Časté je použití přímo v metodě ```System.out.println()```
### Práce s řetězci
- Metody pro práci s řetězci jsou převážně **metody instance třídy String**
- Proto se volají nad referenční proměnnou ukazující na instanci řetězce
- Porovnání pomocí operátoru „```==```“, pouze zjistí, zda se jedná o stejné instance **nepoužívat**
- **Porovnání podle obsahů** (důsledně včetně velikosti písmen) –**shodné/rozdílné**
- Metoda ```equals```(```jinýŘetězec```)
- Výsledek ```true``` (řetězce jsou shodné) nebo ```false``` (řetězce jsou rozdílné)
- Porovnání podle obsahů **bez ohledu na velikost písmen**–**shodné/rozdílné**
- Metoda ```equalsIgnoreCase```(```jinýŘetězec```)
- Výsledek ```true``` (řetězce jsou shodné bez ohledu na velikost písmen) nebo ```false``` (řetězce jsou rozdílné bez ohledu na velikost písmen)
- Porovnání podle obsahů (**důsledně včetně velikosti písmen**) –**větší/menší/stejný**
- Metoda ```compareTo```(```jinýŘetězec```)
- Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je dále od začátku abecedy)
- Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je blíže konci abecedy)
- POZOR! – Návratové hodnoty metod ```compareTo…()```
- Vrácené záporné a kladné číslo (když řetězce nejsou shodné) nemusí být (a není) jen -1 nebo 1
- Návratovou hodnotu metody je třeba porovnávat pomocí operátorů „>“ a „<“, nikoliv porovnáním operátorem „==“ s -1 či 1
- **Test začátku a konce řetězce**
- Výsledek ```true```, pokud řetězec začíná/končí zadaným podřetězcem, jinak vrací ```false```
- Metoda ```startsWith(prefix)```
- Metoda ```endsWith(postFix)```
- Metoda ```startsWithIgnoreCase(prefix)```
- Metoda ```endsWithIgnoreCase(postFix)```
#### Získání podřetězce z řetězce
- Stále předpokládáme deklaraci ```String pozdrav = "Nazdar";```
- Získání podřetězce od zadaného indexu (**včetně**) do konce
- Metoda ```substring(indexOd)```
- ```String p1 = pozdrav.substring(2); //p1 bude "zdar"```
- Získání podřetězce od zadaného indexu (**včetně**) do zadaného indexu (**vyjma**)
- Metoda ```substring(indexOd, indexDo)```
- ```String p2 = pozdrav.substring(0, 2); //p2 bude "Na"```
- Odstranění bílých znaků ze začátku a konce řetězce
- ```String oriznuty = bz.trim(); //oriznuty bude "ahoj"```
### Konverze řetězce na jiné datové typy a obráceně
- Relativně časté operace
- **Převod řetězce na číselný datový typ**
- Typicky při vstupu (když nepoužíváme Scanner, nebo je vstup komplikovanější, nebo v GUI)
- Číselný datový typ je potřeba, abychom mohli provádět aritmetické operace
- ```Např. "1" + "2" je řetězec "12", ale 1 + 2 je 3```
- **Převod čísla na řetězec**
- Implicitně se provádí při každém výstupu
- Explicitně, když chceme využít operace nad řetězci např. pro čísla (např. zjištění počtu znaků (tj. číslic), zřetězení s řetězcem)
- **Převod instance (objektu) na řetězec**
- Pokud chceme instanci vypsat
#### Konverze řetězce na jiné datové typy
- Pro základní datové typy se používá metoda ```Typ.parseTyp(řetězec)``` z příslušné obalovací třídy základního datového typu
- Jedná se o metody třídy, volá se s názvem třídy, není potřeba vytvářet instanci
- Např. ```int i = Integer.parseInt("42");```
- Např. ```long l = Long.parseLong("2444111333");```
- Např. ```double d = Double.parseDouble("5.972E24");```
- Např. ```boolean b = Boolean.parseBoolean("false");```
- Pro objekty
- Není žádný standardní a obecný postup pro převod řetězce na instanci jiné třídy
#### Konverze jiných datových typů na řetězec
- Běžně se využívá schopnost operátoru zřetězení „+“ převádět jiné datové typy (základní datové typy a instance tříd) na řetězec
- Pro základní datové typy funguje přímočaře
- Pro objekty také – objekt se převede na řetězec implicitním voláním metody ```toString()```
- Pokud je metoda ```toString()``` překryta, funguje dobře
- Pro pole je potřeba použít metodu třídy ```Arrays.toString(pole)```
- Pokud se použije pouze operátor „+“, použije se implicitní textová reprezentace pole (např. ```[I@15db9742```)
- Pro základní datové typy existuje další možnost – metoda ```Typ.toString (hodnota)``` z příslušné obalovací třídy základního datového typu
- Např. ```String s = Integer.toString(42); //s bude "42"```
- Pro základní datové typy a pro instance tříd existuje další možnost – metoda třídy ```valueOf(hodnota)``` třídy ```String```
- Metoda je překrytá pro všechny základní datové typy a objekty
- Např. ```String s = String.valueOf(42) //s bude "42"```
### Rozdělení řetězce na podřetězce
- Často je potřeba **rozdělit řetězec na několik podřetězců** podle oddělovače (mezer, bílých znaků, čárek, teček, pomlček či jiné interpunkce či jiného znaku)
- Metoda instance ```split(regulárníVýraz)``` ve třídě ```String```
- Metoda má jako parametr regulární výraz
- Regulární výraz
- Řetězec popisující celou množinu řetězců => mnohé znaky tak mají speciální význam
- Parametrem tedy není jen znak, podle kterého se má řetězec rozdělit
- Některé znaky (např. mezera) nemají speciální význam a lze je tak použít bez problémů (tj. ```split(" ")```)
- Některé znaky mají speciální význam a je třeba použít tzv. „escape“ sekvenci
- Zpětné lomítko „\“ před znak, který chceme použít => zruší se tím speciální význam znaku
- Protože však zpětné lomítko má speciální význam i v řetězcových a znakových literálech (umožňuje napsat speciální znaky, např. konec řádky „\n“), je třeba napsat zpětná lomítka
- Metoda vrací pole řetězců, délka pole záleží na počtu podřetězců dvě „\\“
### Proměnný řetězec
- V některých případech (ač jich není mnoho) opravdu potřebujeme, aby se při každé změně textu řetězce nevytvářela nová instance => je potřeba měnitelný (mutable) řetězec
- Pokud provádíme v řetězci mnoho změn a použili bychom třídu ```String```, **vytvářelo by se mnoho instancí**– pro každou změnu se vytvoří nová, což zbytečně zabírá paměť a zpomaluje program (vytvoření instance nějakou dobu trvá)
- Pokud by šel **řetězec měnit**, vystačíme si s jednou instancí
#### Třída StringBuilder
- **Proměnný/měnitelný řetězec** (sekvence znaků)
- Vytvoření instance třídy ```StringBuilder```
- Lze zadat řetězec, nebo kapacitu
- Kapacita se udává kvůli efektivitě – pokud je dostatečná, nemusí se během práce s řetězcem (při jeho prodloužení) kapacita navyšovat
- Je však možné do instance třídy ```StringBuilder``` vložit/přidat řetězec nebo jiný datový typ (viz níže) a překročit aktuální kapacitu kapacita se automaticky navýší
- Např. ```StringBuilder sb1 = new StringBuilder("Ahoj");```
- Např. ```StringBuilder sb2 = new StringBuilder(100);```
- Práce se znaky
- Zjištění konkrétního znaku
- Metoda ```charAt(index)```
- Vrátí znak na zadaném indexu
- Např. ```int i = sb1.charAt(3); //'o'```
- Nastavení konkrétného znaku
- Metoda ```setCharAt(index, znak)```
- Nastaví znak na zadaném indexu na zadaný znak
- Např. ```sb1.setCharAt(0, 'E'); //"Ehoj"```
- Délka řetězce
- Zjištění délky uloženého řetězce
- Metoda ```getLength()```
- Vrátí délku řetězce
- Např. ```int d1 = sb1.getLength(); //4```
- Např. ```int d2 = sb2.getLength(); //0```
- Nastavení délky řetězce
- Metoda ```setLength(délka)```
- Nastaví délku řetězce
- Pokud se řetězec prodlužuje, přidané znaky budou mít hodnotu 0
- Pokud se řetězec zkracuje, znaky nad zadanou délku se oříznou
- Např. ```sb2.setLength(10); //10 znaků hodnoty 0```
- Např. ```sb2.setLength(0); //Prazdny retezec```
- Převrácení řetězce
- Metoda ```reverse()```
- Převrátí pořadí znaků
- Např. ```sb1.reverse(); //"johE"```
- Přidání/vložení libovolného datového typu
- Přidání libovolného datového typu
- Metoda ```append(hodnota)```
- Metoda překryta pro všechny základní datové typy, ```Object```, ```String``` a ```StringBuilder```
- Např. ```sb2.append(true); //"true"```
- Např. ```sb1.append(sb2); //"johEtrue"```
- Vložení libovolného datového typu
- Metoda ```insert(index, hodnota)```
- Metoda překryta pro všechny základní datové typy, ```Object``` a ```String```
- Znaky na pozici ```index``` a dále se odsunou o počet vložených znaků
- Např. ```sb1.insert(3, 42); //"joh42Etrue"```
- Smazání podřetězce či znaku
- Smazání podřetězce
- Metoda ```delete(začátek, konec);```
- Smaže podřetězec začínající na pozici začátek a končící před pozicí ```konec```
- Např. ```sb1.delete(2, 5); //"joEtrue"```
- Smazání znaku
- Metoda ```deleteCharAt(index)```
- Smaže znak na zadaném indexu
- Např. ```sb1.deleteCharAt(2); //"jotrue"```
#### Třída StringBuffer
- Proměnný/měnitelný řetězec (sekvence znaků), která má téměř stejné metody a téměř stejné použití jako třída ```StringBuilder```
- Starší a pomalejší
- Vhodný, pokud má s proměnným řetězcem pracovat více vláken (viz předmět KIV/PGS)
### Třída Character
- Obalovací třída pro základní datový typ ```char```
- Obsahuje mnoho konstant důležitých pro práci s různými speciálními znaky (např. z jiných abeced než latinky)
- Obsahuje mj. metody pro určení typu znaku
#### Určení typu znaku
- Metody pro určení typu znaku třídy ```Character```
- Jedná se o metody třídy, volají se nad názvem třídy, vrací ```true```, pokud znak je daného typu (podle názvu metody), jinak vrací ```false```
- Metody pracují správně i pro speciální znaky (které např. nejsou z latinky)
- Metoda ```isDigit(znak)```
- Zjistí, jestli je zadaný znak číslice
- Např. ```Character.isDigit('3'); //true```
- Např. ```Characet.isDigit('A'); //false```
- Metoda ```isLetter(znak)```
- Zjistí, jestli je zadaný znak písmeno
- Např. ```Character.isLetter('3'); //false```
- Např. ```Character.isLetter('A'); //true```
- Metoda ```isLetterOrDigit(znak)```
- Zjistí, jestli je zadaný znak písmeno nebo číslice
- Např. ```Character.isLetterOrDigit('3'); //true```
- Např. ```Character.isLetterOrDigit('A'); //true```
- Metoda ```isWhitespace(znak)```
- Zjistí, jestli je zadaný znak bílý znak
- POZOR! – druhé „```s```“ v názvu metody je také malé
- Např. ```Character.isWhitespace(' '); //true```
- Např. ```Character.isWhitespace('\n'); //true```
- Metoda ```isLowerCase(znak)```
- Zjistí, jestli je zadaný znak malé písmeno
- Např. ```Character.isLowerCase('a'); //true```
- Např. ```Character.isLowerCase('A'); //false```
- Např. ```Character.isLowerCase('3'); //false```
- Metoda ```isUpperCase(znak)```
- Zjistí, jestli je zadaný znak velké písmeno
- Např. ```Character.isUpperCase('a'); //false```
- Např. ```Character.isUpperCase('A'); //true```
- Např. ```Character.isUpperCase('3'); //false```
## Práce s parametry příkazové řádky (programu)
- Mnoho programů je možné spustit s **jedním či více parametry příkazové řádky** (též **parametry programu**)
- Např. většina programů pro práci s různými soubory (obrázky, videa, textové soubory) umožňuje zadat jako parametr soubor, který mají po spuštění otevřít
### Zadání parametrů příkazové řádky
- Parametry se zadávají při spuštění programu **za příkaz, který program spouští**
- Parametrů může být více
- Jednotlivé parametry jsou odděleny mezerou
- ```java balík.Třída parametr1 parametr2 …```
- Např. ```java VypisParametruProgramu -v 128```
- Parametry s mezerou či mezerami
- Pokud je parametrem řetězec, který obsahuje jednu nebo více mezer, je nutné parametr uzavřít do uvozovek (jinak by byl chápán jako více parametrů)
- Např. ```java VypisParametruProgramu 128 "Program Files"```
### Předání parametrů příkazové řádky do programu
- S parametry zadanými při spuštění programu lze jednoduše pracovat
- Protože metoda ```main()``` je vstupní bod programu, jsou parametry příkazové řádky předány jako skutečný parametr této metody
- Jsou dostupné ve formálním parametru ```args```
- Jedná se o pole řetězců
- Řetězce mohou obsahovat libovolné znaky (tedy čísla, písmena, interpunkci, bílé znaky)
- Jednotlivé parametry (řetězce) jsou v jednotlivých buňkách pole
- Délka pole odpovídá počtu parametrů
- Pokud je program spuštěn bez parametrů (tj. všechny dosud předvedené programy), je ```args``` pole délky 0 (nikoliv ```null```)
### Zpracování parametrů příkazové řádky
- Parametry mohou mít libovolný význam, typicky se jedná o název souboru, přepínače či jiné (např. číselné) hodnoty
- Parametry jsou však vždy předány jako řetězce
- Pokud se jedná o čísla (sloužící k nějakému výpočtu), je potřeba převod z řetězce na číslo
## Postup při návrhu algoritmu (od problému k programu)
- Pokud máme problém, který chceme vyřešit pomocí počítačového programu, je potřeba nejprve promyslet různé aspekty vytvářeného programu
- Jaký je algoritmus či algoritmy programu
- Jakým způsobem lze algoritmus realizovat a dekomponovat na menší části
- Jaké jsou potřebné datové struktury
- Jaký bude vstup a výstup programu (co má program načítat a co vypisovat)
- Jak bude program komunikovat s uživatelem (typ uživatelského rozhraní)
### Obecný postup
- Zde je popsáno několik obecných rad, jak při vytváření (rozsáhlejšího) programu postupovat
- Nejedná se o žádnou konkrétní metodiku
- Nejedná se o dogma, které by muselo být dodržováno striktně
#### Promyšlení jednotlivých aspektů
- Je potřeba rozmyslet všechny zmíněné aspekty o Většina z nich spolu úzce souvisí => změna rozhodnutí v jedné oblasti pravděpodobně ovlivní další oblasti
- Dělat si poznámky, schémata
- Zvláště u složitějších problémů se snadno zapomíná na již vymyšlené věci, proto je potřeba si myšlenky zaznamenávat
#### Postup programování
- S programováním by se mělo začít, až když je rozmyšlená a navržená struktura aplikace
- Tj. na jaké třídy bude aplikace členěna a do jakých balíku budou tyto třídy umístěny
- Co naprogramovat nejdříve
- Je možno více postupů
- Častý je postup shora dolů
- Vytvoří se kostry jednotlivých (téměř všech) tříd i s hlavičkami metod
- Do těchto koster se následně postupně doplní funkcionalita (těla metod)
- Pokud budeme mít nejprve hotovou kostru většiny tříd metod (s prázdnými těly), hodí se to při následném psaní těl metod
- Těla metod mimo jiné obsahují volání jiných metod naší aplikace => pokud tyto metody existují (byť s prázdnými těly), IDE nástroj může při psaní pomoci s doplňováním jejich volání
- Průběžná kontrola funkcionality
- IDE nástroj nás upozorní na překlepy a jiné syntaktické chyby je možné vytvořit program, který půjde hned napoprvé přeložit (tj. bez chyb při překladu)
- Program však s vysokou pravděpodobností obsahuje chyby v chování programu, na které nás IDE nástroj neupozorní je potřeba ladění
- Řádné ladění je možné až po dokončení aplikace
- Ladění částí kódu (např. jednotlivých výpočtů) je však možné už v průběhu může to usnadnit ladění v závěrečné fázi, protože části kódu byly už alespoň částečně prověřeny
#### Úpravy algoritmů a refaktoring
- Pro začátečníky ale i pro zkušené programátory není snadné zohlednit při návrhu programu všechny aspekty
- Často se na něco zapomene
- Náprava opomenutí může být drobná, ale také rozsáhlá
- Je poměrně běžné, že se v již hotovém kódu dělají úpravy
- Za účelem doplnění či změny funkcionality
- Typicky proto, že se na něco zapomnělo, nebo se objevil nový požadavek
- Např. změna algoritmů, změna formátu vstupů a výstupů
- Za účelem vylepšení zdrojového kódu (bez změny funkcionality)
- Tzv. refaktoring
- Např. změna struktury aplikace (rozdělení funkcionality do více tříd ametod), přejmenování a přesunutí tříd, rozdělení aplikace do více balíků apod.
- IDE nástroje často poskytují nástroje pro jeho usnadnění
- Např. přejmenování a přesunutí třídy
- Ve skutečnosti se málokdy stane, že původní návrh, jak by měl program vypadat, se naprogramuje 1:1 a nedojde k žádným změnám
#### Ladění a testování
- Po dokončení programu je potřeba provést jeho ladění
- Program obsahuje chyby za běhu programu, které je potřeba odstranit
- Důležité je zkoušet program spouštět s různými typy vstupů (včetně neplatných vstupů) a ověřovat, zda dává správné výstupy
- V případě nalezení problému (program padá a/nebo dává nesprávné výsledky), je vhodné použít debugger (případně kontrolní výpisy) pro zjištění, co se v programu děje a pro nalezení a odstranění chyb
#### Odevzdání programu
- Po dokončení testování je třeba vytvořit formu programu, která je vhodná pro odevzdání či distribuci
- Typicky spustitelný soubor JAR
- Tato forma by rovněž měla být řádně otestována
## Řazení
- Velmi častá operace v mnoha různorodých algoritmech
- Slouží především pro usnadnění následného vyhledávání
- Používá se nejen v programování, ale i v běžném životě (často se setkáváme s abecedním pořadím, např. slova v rejstříku knihy, které usnadní nalezení požadovaného výrazu)
### Základní pojmy
- Pro řazení se v angličtině používá slovo „sort“
- Toto slovo má však dva odlišné významy
- Řazení – činnost, kdy přeskupíme prvky posloupnosti (nejčastěji uložené v poli) tak, aby mezi sousedními prvky platily vztahy „předchůdce-následník“ či „menší-větší“
- Např. seřadíme pole čísel podle velikosti od nejmenšího čísla k největšímu nebo seřadíme studenty podle příjmení od A do Z
- V předmětu KIV/PPA1 a navazujících předmětech budeme důsledně používat slovo „řazení“
- Třídění – činnost, kdy prvky z určité skupiny (množiny) rozdělujeme do podskupin podle nějaké společné vlastnosti
- Např. roztřídíme celá čísla na sudá a lichá V českém překladu se občas slovo **„třídění“ používá ve významu řazení => NEPOUŽÍVAT**!
- Klíč
- Řadit je možné prvky primitivních datových typů nebo instance
- Pokud řadíme instance, které mají obecně více atributů, pak typicky řadíme podle jednoho nebo několika z nich
- Atribut, podle kterého řadíme, se nazývá klíč
- Protože se řazení používá velmi často, existuje množství rozmanitých algoritmů, které se navzájem liší některými svými vlastnostmi, zejména svou rychlostí a složitostí implementace
#### Vlastnosti algoritmů řazení
- Směr řazení
- Řazení vzestupně
- Předchozí prvek je menší nebo roven následujícímu prvku
- Např. 1, 2, 3, 3, 3, 4, 6, 9, 9
- Častější směr řazení
- Řazení sestupně
- Předchozí prvek je větší nebo roven následujícímu prvku
- Např. 9, 9, 6, 4, 3, 3, 3, 2, 1
- Pokud nebude explicitně uvedeno jinak, budeme ve zbylém textu uvažovat řazení vzestupně
- Umístění řazených prvků
- **vnitřní řazení**
- **Všechny prvky**, které chceme seřadit, **jsou uloženy v jeden okamžik v operační paměti**
- Ve zbylém textu budeme **uvažovat pouze vnitřní řazení**
- Paměti je „dost“ – lze bez problémů řadit desítky milionů prvků
- **Vnější řazení**
- Řazených prvků je **extrémní množství** a **všechny najednou se do operační paměti nevejdou**
- Prvky jsou uloženy v jednom či více souborech nebo v databázi na vnější paměti (např. na pevném disku)
- **V jeden okamžik je v operační paměti pouze část prvků**
- Stabilita
- Stabilní řazení
- **Řazení je stabilní**, **pokud relativní pořadí prvků se stejnou hodnotou klíče zůstává v seřazeném poli** (posloupnosti) **stejné jako v původním poli** (posloupnosti)
- Např. pokud budu **řadit pole osob s atributy jméno a příjmení podle příjmení**, pořadí osob se stejným příjmením zůstane zachované
- Neseřazené osoby: Jana Volná, Tomáš Marný, Petr Dobrý, Martin Marný, Lenka Malá, Jitka Volná
- Seřazené osoby: Petr Dobrý, Lenka Malá, Tomáš Marný, Martin Marný, Jana Volná, Jitka Volná
- Nestabilní řazení
- Řazení je nestabilní, pokud se relativní pořadí prvků se stejnou hodnotou klíče může po seřazení pole změnit
- Např. pokud budu řadit pole osob s atributy jméno a příjmení podle příjmení, pořadí osob se stejným příjmením nemusí zůstat zachované
- Neseřazené osoby: Jana Volná, Tomáš Marný, Petr Dobrý, Martin Marný, Lenka Malá, Jitka Volná
- Seřazené osoby: Petr Dobrý, Lenka Malá, Tomáš Marný, Martin Marný, Jitka Volná, Jana Volná
- Má význam pouze u řazení objektů
- Pokud řadíme pole základních datových typů, vzájemná poloha dvou stejných prvků není důležitá
- Protože prvky stejné hodnoty stejně nemůžeme rozlišit
- „Je jedno, která trojka bude první a která druhá“
- Objekty se mohou shodovat v klíči, podle kterého jsme řadili, ale můžou se lišit (a často liší) v hodnotách dalších atributů
- Jejich pořadí může mít význam
- Složitost
- Vlastnost každého algoritmu (nejen algoritmu řazení)
- Dá se použít pro zhodnocení „jak rychlý“ daný algoritmus je nebo „kolik paměti“ daný algoritmus potřebuje
- Udává, jak roste časová (nebo paměťová) náročnost algoritmu v závislosti na velikosti vstupu
- V případě řadících algoritmů je velikost vstupu počet řazených prvků
- Podrobně viz předmět KIV/PPA2
### Základní algoritmy řazení
- U všech příkladů budeme předpokládat, že posloupnost prvků, kterou chceme seřadit, je uložená v poli
- Všechny zmíněné algoritmy procházejí pole, přičemž alespoň část pole se prochází opakovaně
- Pro průchod polem jsou využity dva vnořené cykly – typicky cykly for, nebo kombinace cyklů for a while
- Základní operace, které se provádějí v běžných algoritmech řazení, je porovnání prvků a prohození prvků
- Postupným prohazováním dvojic prvků na základě porovnání jejich hodnoty se z neseřazené posloupnosti uložené v poli stane seřazená posloupnost
- **Základní algoritmy řazení**
- Jsou **jednoduché na implementaci** (a tedy i na pochopení jejich principu)
- Všechny mají **časovou složitost Ο(n²)**
- Udává, jak roste čas potřebný pro seřazení posloupnosti prvků v závislosti na počtu prvků n (v nejhorším případě)
- Pokud bude algoritmus potřebovat čas t pro seřazení n prvků, bude pro seřazení 2n prvků potřebovat čas 4t
- Čas roste kvadraticky v závislosti na počtu prvků n
- **Pokročilé algoritmy řazení**
- Jsou složitější na implementaci a pochopení
- Mají **nižší časovou složitost (typicky Ο(nlog2n)**)
- Podrobně viz předmět KIV/PPA2
#### Řazení výběrem (selection sort)
- Též řazení výběrem mezního prvku, řazení s přímým výběrem
- Princip řešení
- V celém poli nalezneme index prvku s nejnižší hodnotou
- Vyměníme nalezený prvek s prvním prvkem pole (na indexu 0)
- V poli vyjma prvního prvku nalezneme index prvku s nejnižší hodnotou
- Vyměníme nalezený prvek s druhým prvkem pole (na indexu 1)
- Pokračujeme stejným způsobem pro další prvky, dokud nedosáhneme konce pole
- Vlastnosti **řazení výběrem**
- Řazení **je nestabilní**
- **Složitost Ο(n²)**
#### Řazení vkládáním (insertion sort)
- Princip řešení
- Pole máme rozdělené na seřazenou (na začátku jeden prvek) a neseřazenou část (na začátku všechny prvky kromě prvního (na indexu 0))
- Vezme se první prvek z neseřazené části a vloží se na správné místo do seřazené části
- Prvky v seřazené části větší než zařazovaný prvek se posunou o jedno místo doprava => seřazená část se zvětší o jeden prvek
- Opakuji, dokud není pole celé seřazené
- Vlastnosti **řazení vkládáním**
- Řazení **je stabilní**
- **Složitost Ο(n²)**
#### Řazení záměnou (bubble sort)
- Též bublinkové řazení
- Princip řešení
- Porovnáváme vždy dva sousední prvky, začínáme odzadu
- Pokud jsou prvky v nesprávném pořadí (prvek s nižším indexem je větší), prohodíme je
- Porovnávání a prohazování opakujeme, dokud nedojdeme na začátek pole
- Tím se nejmenší prvek dostane na začátek pole („vybublá nahoru“)
- V průběhu vybublání se i ostatní prvky částečně řadí
- Celý postup opakujeme znovu, ale pouze do druhého prvku pole
- Tím vybublá nahoru druhý nejmenší prvek
- Opakujeme pro třetí nejmenší prvek, atd.
- Předčasné ukončení
- Pokud nedojde při běhu vnitřního cyklu k žádné výměně, je pole seřazené a mohu skončit
- Vlastnosti **řazení záměnou**
- Řazení **je stabilní**
- **Složitost Ο(n2)**
#### Porovnání základních algoritmů řazení
- **Všechny** tři zmíněné algoritmy mají stejnou **složitost Ο(n²)**
- To neznamená, že jsou **všechny stejně efektivní**, pouze, že **doba řazení roste stejným tempem** (s druhou mocninou počtu řazených prvků)
- Všechny algoritmy řazení provádějí převážně **dvě základní operace**
- **Porovnání** – typicky porovnání dvou prvků
- **Přiřazení** – typicky při prohození dvou prvků (celkem tři přiřazení na jedno prohození)
- Různé řadící algoritmy provedou různý počet porovnání a přiřazení pro stejnou neseřazenou posloupnost
- Podle počtu provedených porovnání a přiřazení lze algoritmy porovnat
- Do algoritmů se přidají dva čítače
- Jeden pro počet porovnání a druhý pro počet přiřazení
- Inkrementují se „ručně“ (tj. je nutné inkrementaci ručně přidat do kódu) při každém provedeném porovnání/přiřazení
- **Základní algoritmy** řazení jsou **efektivní pro malé posloupnosti** (cca několik desítek prvků)
- Pro **větší množství prvků** se používají **algoritmy se složitostí Ο(nlog²n)**, které jsou typicky **obsažené v knihovních metodách většiny běžných programovacích jazyků**
### Řazení pole řetězců (lexikografické řazení)
- **Řazení řetězců funguje stejně** jako řazení základních datových typů **s výjimkou porovnání**
- Pro porovnání dvou prvků nelze použít operátory „```<```“ a „```>```“
- Je potřeba použít metodu instance třídy ```String compareTo()```, která vrací 0, kladnou či zápornou hodnotu podle pořadí porovnávaných řetězců v abecedě
- 0 – řetězce jsou stejné (včetně velikosti písmen)
- **Záporná hodnota** – řetězec, nad kterým je metoda volaná, je „menší“ než řetězec v parametru metody
- **Kladná hodnota** – řetězec, nad kterým je metoda volaná, je „větší“ než řetězec v parametru metody
- POZOR! – Kladné a záporné hodnoty jsou obecně různá kladná a záporná čísla v závislosti na obsahu řetězců – není to jen -1 a 1
#### Problémy s lexikografickým řazením
- Uspořádání podle abecedy však může mít neočekávané důsledky, typicky při řazení názvů souborů (což je nejčastěji podle názvu)
- Pokud seřadíme čísla ```1, 40, 10, 3, 17, 4```, očekáváme výsledek ```1, 3, 4, 10, 17, 40```
- Pokud ale budeme řadit řetězce (názvy souborů) ```"1.txt", "40.txt", "10.txt", "3.txt", "17.txt", "4.txt"```, dostaneme výsledek ```"1.txt", "10.txt", "17.txt", "3.txt", "4.txt", "40.txt"```
- Toto seřazení je **důsledkem porovnání řetězců**
- Běžné porovnávání řetězců implementované i v metodě ```compareTo()``` probíhá postupně podle jednotlivých znaků od začátku řetězce
- Pokud se řetězce shodují v prvním znaku, porovnají se podle druhého znaku atd.
- Jednotlivé znaky se porovnávají podle jejich hodnot
- Jakmile se narazí na znak, který není shodný, hodnota tohoto znaku určí výsledek porovnání řetězců
- Např. při porovnání řetězců ```"Jana"``` a ```"Janicka"``` rozhodnou až znaky ```'a'``` a ```'i'``` na indexu 3 protože ```'a'``` má nižší hodnotu než ```'i'```, „menší“ (tj. blíže začátku abecedy) je řetězec ```"Jana"```
- Pokud je jeden řetězec předponou druhého, je „menší“ ten kratší řetězec (např. ```"Jan"``` je „menší“ než ```"Jana"```)
- Pokud se porovná řetězec ```"10.txt"``` a ```"3.txt"```, tak hned první znaky (na indexu 0) jsou rozdílné – ```'1'``` a ```'3'```
- Protože ```'1'``` je menší než ```'3'```, je řetězec ```"10.txt"``` „menší“ než řetězec ```"3.txt"```, i když číslo 3 je menší než 10
- Řešení –**doplnit nevýznamové nuly**, které jsou však z hlediska lexikografického řazení významové => místo ```"3.txt"``` použít ```"03.txt"```
### Řazení pole objektů
- Pole objektů lze řadit **stejnými algoritmy** jako pole základních datových typů
- **Je** ale **nutné určit**, **podle čeho se mají jednotlivé instance porovnávat** (tj. **určit, co bude klíčem**)
- Podle jednoho atributu
- Podle více atributů (víceúrovňové řazení)
#### Řazení podle jednoho atributu
- Jediný rozdíl oproti řazení pole základních datových typů je, že porovnáváme hodnoty atributů, nikoliv samotné instance
- Pokud je atribut základního datového typu, použijeme přímo operátory porovnání „```<```“ a „```>```“
- Pokud je atribut referenční proměnná na instanci jiné třídy, musíme použít porovnání definované pro danou třídu
- Např. pro třídu ```String``` je to metoda ```compareTo()```
- Poměrně často se může stát, že chceme řadit pole objektů podle více atributů
- Např. osoby podle příjmení a následně podle jména
- Osoby se tedy seřadí podle příjmení, a pokud mají stejné příjmení, seřadí se ještě podle jména
- Je možné udělat v řazení komplexnější podmínku pro prohození prvků obsahující všechny atributy, podle kterých chceme řadit
- Tento postup podstatně znepřehledňuje samotné řazení, zvláště pokud je atributů, podle kterých řadíme, větší množství
- Je vhodnější udělat metodu pro porovnání dvou instancí stejné třídy, která bude vracet hodnoty indikující, která instance je „větší“
- Tato metoda může obsahovat i poměrně složitou podmínku skládající se z porovnání několika atributů
- Díky umístění v metodě instance nebude znepřehledňovat kód řazení
- Metodu můžeme po vzoru třídy ```String``` nazvat ```compareTo()``` a může vracet hodnoty ```0```, ```1``` a ```-1```
- Metoda ```compareTo()``` se využívá i při řazení objektů knihovní metodou řazení
- Metoda ```compareTo()``` se může využít i při řazení podle jediného atributu
#### Víceúrovňové řazení provedené postupně (nepoužívat)
- Další možnost seřazení pole objektů podle více atributů je seřadit ho nejprve podle jednoho atributu a následně podle dalšího
- Je potřeba použít stabilní algoritmus řazení
- Nejprve se pole seřadí podle nejméně důležitého atributu (u osoby podle jména)
- Následně se pole seřadí podle více důležitého atributu (u osoby podle příjmení)
- Protože pořadí prvků se stejným klíčem zůstává při použití stabilního řazení nezměněno, seřazení podle méně důležitého atributu (jména) zůstane zachováno (pro osoby se stejným příjmením)
- Tento postup vyžaduje zopakovat řazení dvakrát a je proto rozumné ho nevyužívat, pokud není nezbytně nutno
- Pokud však není možné řadit podle více atributů najednou (např. v GUI MS Access), tento postup se může hodit
### Metody řazení v Java Core API
- V **naprosté většině případů není důvod si programovat algoritmus řazení**– využijí se **knihovní metody pro řazení** z třídy ```Arrays``` (nebo ```Collections```) z balíku ```java.util```
- Pro pole základních datových typů i pole objektů se používají metody ```Arrays.sort(pole)``` a ```Arrays.sort(pole, indexOd, indexDo)```
- Metody jsou překryté pro pole všech základních datových typů a pole objektů
- Metoda s indexy řadí pouze část pole od indexu ```indexOd``` (včetně) do indexu ```indexDo``` (vyjma)
#### Řazení polí základních datových typů metodou z Java Core API
- Řazení pole základních datových typů **nevyžaduje žádnou speciální úpravu**, **pouze se zavolá metoda řazení**
- Metody ```sort()``` pro pole základních datových typů obsahují **algoritmus quick sort**
- Je **velmi rychlý**
- Má **složitost Ο(nlog²n)** (v průměrném případě)
- **Není stabilní** – u základních datových typů nepodstatné
- Viz předmět KIV/PPA2
#### Řazení polí objektů metodou z Java Core API
- Aby bylo možné **řadit pole objektů** knihovními metodami řazení, **je potřeba, aby třída implementovala rozhraní** ```Comparable<Třída>```
- Mnoho knihovních tříd to dělá, a dají se tak řadit knihovními metodami – např. ```String```
- Podrobnosti viz předměty KIV/PPA2 a KIV/OOP
- Existuje i alternativní možnost, umožňující řadit podle různých kritérií podle toho, které řazení aktuálně potřebujeme
- Je potřeba, aby třída měla rozšířenou hlavičku
- ```public class Třída implements Comparable<Třída>```
- Je potřeba, aby třída obsahovala metodu pro porovnání dvou instancí třídy
- ```public int compareTo(Třída třída)```
- Tato metoda musí vracet zápornou hodnotu, pokud je instance, nad kterou se metoda volá, „menší“ než instance v parametru metody, kladnou hodnotu, pokud je „větší“, a nula, pokud jsou obě instance stejné
- Podle čeho se instance porovnávají, **záleží na těle metody** ```compareTo()```, může to být podle jednoho či více atributů
### Kopie pole
- Protože při knihovním řazení metodami ```Arrays.sort()``` dojde přímo k seřazení zadaného pole, může se hodit pole před řazením zkopírovat, abychom měli uloženou seřazenou i neseřazenou posloupnost
- Pole lze překopírovat ručně
- Vytvořit nové pole stejného typu o stejné velikosti jako původní pole
- V cyklu ```for``` projít původní pole a do prvků nového pole přiřadit odpovídající prvky původního pole
- **Pole lze překopírovat využitím knihovní metody** ```Arrays.copyOf(pole, nováDélkaPole)```
- **Metoda je rychlejší** než ruční kopírování
- Metoda umožňuje **pole** také **zkrátit** nebo **prodloužit** (**při zadání jiné délky** než původní délky pole)
- Při zadání **menší délky** se **pole ořízne**
- Při zadání **větší délky** se **prvky navíc nastaví na hodnotu** ```0, 0.0, false``` nebo ```null``` **podle typu pole**
#### Kopie polí základních datových typů
- Při kopírování polí základních datových typů, kdy jednotlivé hodnoty jsou přímo prvky pole, dostaneme „plnohodnotnou“ kopii pole
- Pokud provedeme změnu prvku v kopii pole, změna se nijak neprojeví v původním poli
#### Kopie polí objektů
- Při **kopírování polí objektů** jsou v prvcích pole uloženy **pouze reference na jednotlivé instance**
- Zkopírováním pole se **zkopírují pouze reference**, které ale **stále ukazují na původní instance**
- Pokud provedu změnu atributu prvku v kopii pole, projeví se tato změna i v odpovídajícím prvku původního pole (protože se stále jedná o stejnou instanci)
- Jedná o tzv. **mělkou kopii pole**
## Vyhledávání
- Vyhledávání je velmi často prováděná činnost
- **Zjišťujeme**, **zda je prvek určité hodnoty** (též prvek s hodnotou klíče) **přítomen v poli**
- Někdy stačí informace, zda je či není (```true```/```false```)
- Většinou je potřeba zjistit index, na kterém se hledaný prvek nachází
- Typ vyhledávání
- **Neúplné**
- Nalezneme **první výskyt** prvku
- **Úplné**
- Nalezneme **všechny výskyty** prvku
- Výsledek neúplného vyhledávání
- Typicky první index od začátku pole, na kterém se prvek nachází (prvek může být v poli obsažen vícekrát), nebo záporná hodnota, pokud se prvek v poli nenachází (typické použití, protože index prvku nemůže být záporný)
- Pokud je důležité pouze, zda prvek v poli je či není, ale není důležité kde je, je výsledek vyhledávání pouze ```true``` (prvek je obsažen) nebo ```false``` (prvek není obsažen)
- Výsledek úplného vyhledávání
- Pole (případně výpis) všech indexů, na kterých se hledaný prvek nachází, nebo prázdné pole, pokud prvek není v poli obsažen
- Pokud není důležité, na kterých indexech se prvek nachází, ale zajímá nás, kolikrát je v poli obsažen, výsledkem je počet výskytů prvku (0 pokud prvek není obsažen)
### Vyhledávání v neseřazené posloupnosti (poli)
- Pokud není pole, ve kterém prvek hledáme, seřazené, je jediná možnost sekvenční vyhledávání
#### Neúplné sekvenční vyhledávání v poli základních datových typů
- Neúplné sekvenční vyhledávání má **složitost Ο(n)**
- V **nejhorším případě je nutné projít celé pole**, tedy všech n prvků
- Princip vyhledávání
- Procházíme pole od začátku do konce a porovnáváme hodnoty prvků pole s hodnotou hledaného prvku
- Když prvek nalezneme, ukončíme procházení pole a vrátíme index, na kterém jsme prvek nalezli
- Pokud dojdeme až do konce pole a prvek nenajdeme, vrátíme zápornou hodnotu (typicky ```-1```)
#### Neúplné sekvenční vyhledávání v poli objektů
- Vyhledávání v poli objektů je velice podobné, jako vyhledávání v poli základních datových typů
- Pro porovnání ale **nemůžeme použít operátor** „```==```“, protože pro objekty vrací true pouze v případě, že se jedná o stejnou instanci
- Můžeme **porovnávat přímo jeden či více atributů instance**
- Můžeme **využít metodu** ```equals()```, **pokud je** v dané třídě **správně implementovaná**
#### Úplné sekvenční vyhledávání
- Úplné sekvenční vyhledávání má **složitost Ο(n)**
- V každém případě **je nutné projít celé pole**, tedy všech n prvků
- Princip vyhledávání
- **Princip** je **stejný jako u neúplného sekvenčního vyhledávání**, pouze **neukončíme procházení pole při nalezení prvního výskytu** prvku, ale projdeme pole **vždy až do konce**
- Protože indexů s pozicemi prvků je více, nestačí vrátit jeden index místo jednoho indexu **vrátíme pole s jednotlivými indexy**
- Délka pole indexů může být maximálně stejná, jako je počet prvků prohledávaného pole a minimálně může být 0, pokud hledaný prvek nebyl v poli nalezen
- Počet výskytů hledaného prvku v poli (a tedy délku pole indexů) na začátku neznáme
- Délku pole indexů tedy volíme jako délku prohledávaného pole
- Délku můžeme po skončení algoritmu zkrátit vytvořením kratší kopie pole na skutečný počet indexů
### Vyhledávání v seřazené posloupnosti (poli)
- **Pokud je posloupnost seřazená** (předpokládáme vzestupně, ale mohla by být i sestupně), je možné **použít vyhledávání půlením intervalů** (též binární vyhledávání)
- Sekvenční vyhledávání je možné použít také, stejně jako na neseřazenou posloupnost, ale je podstatně pomalejší, takže není důvod ho používat, pokud je posloupnost seřazená
- Pokud provádíme vyhledávání opakovaně a pořadí prvků v prohledávaném poli není důležité, vyplatí se pole jednou seřadit a následně opakovaně používat vyhledávání půlením intervalů
#### Neúplné vyhledávání půlením intervalů v poli základních datových typů
- Neúplné vyhledávání půlením intervalů (binární vyhledávání) má **složitost Ο(log₂n)**
- Čas vyhledávání tedy roste pouze s logaritmem počtu prvků prohledávaného pole pro **velký počet prvků** prohledávaného pole je **podstatně rychlejší než sekvenční vyhledávání**
- Princip vyhledávání
- V každém kroku rozdělíme prohledávaný interval na dvě poloviny a následně hledáme jen v jedné z polovin
- Zjistíme hodnotu prvku ležícího na prostředním indexu
- Pokud je rovna hledané hodnotě, algoritmus končí
- Pokud je větší než hledaná hodnota, hledáme v levé polovině
- Pokud je menší než hledaná hodnota, hledáme v pravé polovině
#### Úplné vyhledávání půlením intervalů
- Pokud je hledaný prvek v poli obsažen vícekrát, vyhledávání půlením intervalů najde jeden z výskytů, ale není jasné, který výskyt to je
- Nalevo i napravo od nalezeného indexu se mohou vyskytovat prvky se stejnou hodnotou
- Pro úplné vyhledávání je potřeba sekvenčně prohledat pravé i levé okolí nalezeného indexu, dokud se nenarazí na jiný prvek nebo konec či začátek pole
- Protože stejné prvky jsou v seřazeném poli vždy u sebe, není třeba vracet pole všech indexů, na kterých se hledaný prvek nachází, stačí vrátit první a poslední index
#### Metody pro vyhledávání půlením intervalů z Java Core API
- Třída ```Arrays``` obsahuje metody pro vyhledávání půlením intervalů
- Metoda ```Arrays.binarySearch(pole, klíč)```
- Prohledává celé pole
- Metoda ```Arrays.binarySearch(pole, od, do, klíč)```
- Prohledává pouze část pole udanou indexy ```od``` (včetně) a ```do``` (vyjma)
- Metody jsou překryté pro pole všech základních datových typů a pro pole objektů
- Prohledávané pole musí být seřazené, typicky vzestupně (typicky knihovní metodou ```Arrays.sort()```)
- Metoda vrací index nalezeného prvku, nebo zápornou hodnotu, pokud prvek nebyl nalezen
- Tato hodnota obecně není ```-1``` nutno testovat hodnotu, zda je menší než ```0```, nikoliv rovna ```-1```
- Absolutní hodnota záporného čísla udává index, na kterém by prvek byl, kdyby v poli byl
#### Vyhledávání půlením intervalů v poli objektů
- Pokud bychom chtěli použít binární vyhledávání v poli objektů, je nutné určit, podle čeho se mají objekty porovnávat (podle jakého atributu)
- Je nutné seřadit pole podle tohoto vybraného porovnání a stejné porovnání použít i v algoritmu binárního vyhledávání
- Nejrozumnější je použít metodu ```compareTo()```, kterou jsme použili při ručním i knihovním řazení
- Pro správné použití knihovní metody ```Arrays.binarySearch()``` je nezbytné, aby třída, jejíž instance jsou v poli, implementovala rozhraní ```Comparable<Třída>```
- Hlavička třídy, jejíž instance jsou v prohledávaném poli, musí být ```public Třída implements Comparable<Třída>```
- Musí obsahovat metodu ```public int compareTo(Třída třída)```