Obsah 7. přednášky: Soubory - terminologie Adresáře a soubory - třída File Výjimky - úvod Druhy výjimek Způsoby reakce na výjimku Kompletní ošetření výjimky Nejhorší reakce na výjimku Seskupování a selekce výjimek Výjimky pro pokročilé* Ladění programů Tato tematika je zpracována v Záznamy přednášek: str. 153 166 Přednášky KIV/PPA1, A. Netrvalová, 2016 7. přednáška
Soubory - terminologie Soubor - množina údajů uložená na vnější paměti počítače, obvykle na disku Soubor (pro začátečníky) - základní struktura pro ukládání dat na vnější paměťové médium - složen z jednotlivých záznamů, které se skládají z položek - soubory s pevnou délkou nebo soubory s proměnnou délkou - data v souborech se zpracovávají pouze v operační paměti. Přesouvání dat z vnější do operační paměti se provádí použitím vyrovnávací paměti, tj. tzv. bufferem - jednotkou přenosu dat je tzv. logický blok (cluster, page, stránka). - základní ideou při fyzické implementaci souborů je minimalizace přístupů na disk při zpracování dat. Přístupy na disk nejvíce zpomalují proces zpracování dat. - nejčastěji se používají soubory sekvenční, indexsekvenční, indexové a s přímým přístupem Jen pro informaci: Kromě primárního souboru, tj. souboru obsahujícího všechna data, může soubor obsahovat i přídavnou datovou strukturu, spojenou vždy s vybranou položkou (položkami) primárního souboru. Tato položka (atribut) se nazývá vyhledávací klíč a datovou strukturou je index. Strana 2 (celkem 31)
Typy souborů přístup k datům v souboru - sekvenční - index-sekvenční - indexové soubory - soubory s přímým přístupem Sekvenční soubor je kolekce záznamů, obvykle pevné délky, umístěných postupně za sebou (tj. v předem určeném pořadí) ve vymezeném prostoru na vnějším paměťovém médiu. My budeme dále pracovat pouze se sekvenčními soubory. Jen pro informaci: Index-sekvenční soubor je tvořen tzv. primárním souborem, tj. seřazeným sekvenčním souborem (dle primárního klíče) a přídavnou datovou strukturou - index. Indexový soubor je tvořen primárním souborem a indexy pro různé vyhledávací klíče, ale indexovány jsou záznamy, proto nemusí být primární soubor seřazen (na rozdíl od index-sekvenčního souboru) a nevyžaduje umístění do souvislé části paměti. Soubor s přímým přístupem umožňuje rychlý způsob vyhledávání záznamů podle hodnoty primárního klíče i jeho aktualizaci. Při ukládání záznamu do souboru se z hodnoty primárního klíče vypočte adresa bloku (stránky) disku, na níž má být daný výskyt záznamu uložen. Hodnota primárního klíče je vstupem a adresa stránky je výstupem tzv. hashovacích algoritmů (viz PPA2 a PT). Strana 3 (celkem 31)
Terminologie sjednocení pojmů Přípona vše za poslední tečkou:.java,.txt Jméno souboru Kruh.java, data.txt (někdy jen část před tečkou, např. spouštění programu v Javě z příkazové řádky: java Kruh) Aktuální adresář - značení. Nadřazený adresář (rodičovský) - značení.. Podadresář (vnořený) Kořenový adresář značení Win \, Linux / Úplná cesta adresářová cesta z kořenového do aktuálního adresáře, např. D:\vyuka\ppa1\programy Úplné jméno souboru úplná cesta + jméno souboru, např. D:\vyuka\ppa1\programy\Kruh.java Relativní cesta (neúplná), relativní jméno souboru - cesta z nějakého adresáře (např. aktuálního) k souboru (raději moc neužívat častá chyba), např... \ppa1\programy\kruh.java Poznámka pozor na odlišnosti oddělování adresářů a souborů v různých operačních systémech (\, /) Typické operace se souborem - otevření, zápis, čtení, uzavření Strana 4 (celkem 31)
Adresáře a soubory - třída File Poznámka zde soubor chápán jako celek bez uvažování o obsahu Práce se soubory třída File - souborový manažer, který nezajišťuje způsob čtení, zápisu, používá se i pro adresáře (rozlišuje se pomocí metod isdirectory(), isfile()) - zajišťuje např. test existence, vytváření, mazání, přejmenování, přesun, zisk informací o souboru - balík java.io (import java.io.*.;) Vytvoření instance File - soubor nemusí existovat! JVM Program a.txt? a.txt Poznámka Vytvoření instance využívající jméno souboru nebo adresáře neznamená, že uvedený soubor nebo adresář existuje fyzicky na disku. Existovat může, ale také nemusí. Způsoby vytvoření instance - konstruktory: - jméno souboru v aktuálním adresáři - objekt podadresáře a souboru v podadresáři - jméno podadresáře v aktuálním adresáři a jméno souboru v tomto podadresáři Strana 5 (celkem 31)
File soubora = new File("sA.txt"); System.out.println(souborA.getCanonicalPath()); D:\vyuka\ppa1\soubory\sA.txt File actualadr = new File("."); System.out.println(actualAdr.getCanonicalPath()); File souborb = new File(actualAdr,"sB.txt"); System.out.println(souborB.getCanonicalPath()); D:\vyuka\ppa1\soubory D:\vyuka\ppa1\soubory\sB.txt File souborc = new File("adresar", "sc.txt"); System.out.println(souborC.getCanonicalPath()); D:\vyuka\ppa1\soubory\adresar\sC.txt Poznámka: Ani jeden z předchozích souborů a ani adresář adresar neexistoval. Práce s existujícím souborem či adresářem Metody pro zisk informací o souboru: boolean exists() - testuje existenci souboru boolean isfile() - testuje, je-li to soubor boolean isdirectory() - testuje, je-li to adresář long length() - velikost souboru (počet bytů) long lastmodified() - čas poslední úpravy (počet ms od 1.1.1970), pro výpis data je nutno použít viz následující příklad: Strana 6 (celkem 31)
File soubor = new File("s.txt"); System.out.println(soubor.getCanonicalPath()); Calendar c = new GregorianCalendar(); c.settimeinmillis(soubor.lastmodified()); System.out.format("%tF%n",c); // pokud soubor s.txt existuje // pokud soubor s.txt neexistuje Metody pro změny: delete() vymazání souboru renameto(file x) přejmenování, přesun souboru import java.io.file; public class Vymazani { 2010-08-14 1970-01-01 public static void main(string[] a) throws IOException { String jmeno = "src\\p07priklady\\tridafile\\smazani\\data.txt"; File f = new File(jmeno); // zde jiz existuje System.out.println(f.getName()+ " " + f.exists()); if(f.exists()) f.delete(); // pokud byl jiz vytvoren, smaze ho System.out.println(f.getName()+ " " + f.exists()); f.createnewfile(); /* vytvori prazdny soubor, jen pokud soubor daneho jmena jiz neexistuje */ System.out.println(f.getName()+ " " + f.exists()); f.delete(); // zakomentovat dalsi smazani souboru System.out.println(f.getName()+ " " + f.exists()); data.txt true data.txt false data.txt true data.txt false Strana 7 (celkem 31)
File soubora = new File("sA.txt"); System.out.println(souborA.getName()+ " " + soubora.exists()); File souborb = new File("sB.txt"); soubora.renameto(souborb); System.out.println(souborB.getCanonicalPath()); System.out.println(souborA.getName()+ " " + soubora.exists()); sa.txt true D:\vyuka\ppa1\soubory\sB.txt sa.txt false Metody pro vytvoření adresáře: mkdirs() - vytvoří 1 nebo skupinu adresářů File adr =new File("nadrazeny" + File.separator + "vnoreny"); System.out.println(adr.getCanonicalPath()+ " " + adr.exists()); adr.mkdirs(); System.out.println(adr.getCanonicalPath()+ " " + adr.exists()); D:\vyuka\ppa1\soubory\ nadrazeny\vnoreny false D:\vyuka\ppa1\soubory\ nadrazeny\vnoreny true Metody pro výpis položek adresáře: String [] list() - jména souborů a podadresářů File [] listfiles() - soubory a podadresáře (objektyfile) import java.io.*; import java.util.*; public class VypisAdr { public static void main (String[] args) throws Exception { File adr =new File(".."); String []jmena = adr.list(); System.out.println(Arrays.toString(jmena)); // napriklad: [info, uvod, vypis, vytvoreni, zmeny] Strana 8 (celkem 31)
Výjimky úvod jen základ více v dalších předmětech (OOP, PT) - pojem výjimka (exception) označení nežádoucí události, jejíž vznik chceme odstranit - mechanismus výjimek velmi silný bezpečnostní prvek - na úrovni kompilátoru nutí programátora k reakci na možné chybové stavy - vyhození výjimky (throws exception) - reakce na výjimku - propagace, deklarace - ošetření (konstrukce try-catch) - kombinace obou způsobů Druhy výjimek z pohledu programátora - Exception (checked exception) nutné ošetření např. u metod V/V - RunTimeException - dobrovolné ošetření např. dělení nulou, index mimo rozsah pole ClassNotFoundException Exception IOException AWTException RuntimeException... další třídy ArithmeticException NullPointerException IndexOutOfBoundsException... další třídy Strana 9 (celkem 31)
1. Příklad: čtení ze souboru Exception (povinné ošetření neprovedeno) import java.util.*; import java.io.*; public class IlustraceVyjimky { private static Scanner sc; public static int [] nactipole(){ sc = new Scanner(new File("pole.txt")); int pocetprvku = sc.nextint(); int [] pole = new int [pocetprvku]; for(int i=0; i<pole.length; i++){ pole[i] = sc.nextint(); return pole; public static void main(string[]args){ System.out.print(Arrays.toString(nactiPole())); IlustraceVyjimky.java:7: unreported exception java.io.filenotfoundexception; must be caught or declared to be thrown Scanner sc = new Scanner(new File("pole.txt")); ^ 1 error Poznámka Vstupní soubor totiž nemusí existovat, či může mít jiné jméno. Potřebná úprava bude uvedena v další části. Strana 10 (celkem 31)
2. Příklad: nastavení indexu mimo rozsah pole RunTimeException (neošetřená výjimka) public class IlustraceVyjimkyNeosetrene { public static void main(string[]args){ int [] pole = new int [5]; System.out.println(pole[5]); >"C:\Program Files\Java\jdk1.6.0_02\bin\java" IlustraceVyjimkyNeosetrene Exception in thread "main" java.lang.arrayindexoutofboundsexception: 5 at IlustraceVyjimkyNeosetrene.main(IlustraceVyjimkyNeosetre ne.java:5) >Exit code: 1 Způsoby reakce na výjimku - propagace, deklarace (předání nadřazené úrovni) - ošetření (zachycení a ošetření v místě výskytu) - ošetření v místě výskytu a předání informace nadřazené úrovni Propagace - neboli šíření výjimek metoda, v níž se výjimka vyskytla, se zříká odpovědnosti za zpracování, což provede deklarací v hlavičce metody - throws (vyhazuje) Strana 11 (celkem 31)
throws Exception - znamená pouhé odsunutí problému ošetření musí být někdy a někde (např. v main()) provedeno Příklad import java.util.*; import java.io.*; public class IlustraceVyjimky { private static Scanner sc; public static int [] nactipole() throws Exception { sc = new Scanner(new File("pole.txt")); int pocetprvku = sc.nextint(); int [] pole = new int [pocetprvku]; for(int i=0; i<pole.length; i++){ pole[i] = sc.nextint(); return pole; public static void main(string[]args) { System.out.print(Arrays.toString(nactiPole())); IlustraceVyjimkyPovinneOsetreni.java:17: unreported IlustraceVyjimkyPovinneOsetreni.java:17: exception java.lang.exception; must be caught or declared to be thrown System.out.print(Arrays.toString(nactiPole())); 1 error unreported exception java.lang.exception; must be caught or declared to be thrown System.out.print(Arrays.toString(nactiPole())); ^ ^ 1 error Chybové hlášení po překladu je způsobeno odsunutím řešení problému do metody main(). Náprava - v hlavičce metody main() provedeme stejnou úpravu throws Exception Strana 12 (celkem 31)
import java.util.*; import java.io.*; public class IlustraceVyjimky { private static Scanner sc; public static int [] nactipole() throws Exception { sc = new Scanner(new File("pole.txt")); int pocetprvku = sc.nextint(); int [] pole = new int [pocetprvku]; for(int i=0; i<pole.length; i++){ pole[i] = sc.nextint(); return pole; public static void main(string[]args) throws Exception { System.out.print(Arrays.toString(nactiPole())); Exception in thread "main" java.io.filenotfoundexception: pole.txt (Systém nemůže nalézt uvedený soubor) at java.io.fileinputstream.open(native Method) at java.io.fileinputstream.<init>(fileinputstream.ja va:106) at java.util.scanner.<init>(scanner.java:636) at IlustraceVyjimkyPovinneOsetreni.nactiPole(Ilustra cevyjimkypovinneosetreni.java:7) at IlustraceVyjimkyPovinneOsetreni.main(IlustraceVyj imkypovinneosetreni.java:17) Chybové hlášení je způsobeno faktem, že soubor neexistuje (není ve společném adresáři). Pokud jej vytvoříme a naplníme správnými daty, vše funguje. Strana 13 (celkem 31)
Výhody jednoduchost, minimum práce Nevýhody nutno při každém použití metody řešit vzniklé problémy. Pro volání často a z různých míst naprosto nevhodné! Kompletní ošetření výjimky - řešena přímo v metodě, neproniká ven - konstrukce try-catch blok try - výkonný kód blok catch - druh výjimky a způsob reakce (výpis chyby a ukončení, nebo i řešení) Příklad 1a: jen výpis a ukončení (rozumná reakce) import java.util.*; import java.io.*; public class IlustraceVyjimkyOsetreniVypisem { private static Scanner sc; public static int[]nactipole() throws Exception { int pole [] = null; // vysunuti deklarace try { sc = new Scanner(new File("pole.txt")); int pocetprvku = sc.nextint(); pole = new int [pocetprvku]; for(int i=0; i<pole.length; i++){ pole[i] = sc.nextint(); return pole; catch (Exception e) { e.printstacktrace(); // chybovy vypis (použijeme v SP) System.exit(1); // ukonceni return pole; Strana 14 (celkem 31)
// pokracovani z predchozi stranky public static void main(string[]args) throws Exception { System.out.println(Arrays.toString(nactiPole())); Poznámka: Samotný výpis výjimky program neukončí, nutno provést ukončení příkazem: System.exit(1); Chybový výpis, pokud soubor neexistuje: java.io.filenotfoundexception: pole.txt (Systém nemůže nalézt uvedený soubor) at java.io.fileinputstream.open(native Method) at java.io.fileinputstream.<init>(fileinputstre am.java:106) at java.util.scanner.<init>(scanner.java:636) at IlustraceVyjimkyOsetreniVypisem.nactiPole(Il ustracevyjimkyosetrenivypisem.java:10) at IlustraceVyjimkyOsetreniVypisem.main(Ilustra cevyjimkyosetrenivypisem.java:26) Strana 15 (celkem 31)
Příklad 1b: RunTimeException (rozumná reakce) nastavení indexu mimo rozsah pole ošetření výpisem a ukončení (neošetřená výjimka - viz Druhy výjimek Příklad 2) public class IlustraceVyjimkyOsetrene { static int vratprvekpole(int [] pole, int index) { try { return pole[index]; // vraceni indexu catch (ArrayIndexOutOfBoundsException e) { System.out.println("Zachycena vyjimka: index = " + e.getmessage()); return -index; // vraceni zaporneho indexu public static void main(string[] args) { int xxx [] = new int[10]; for(int i=0; i<xxx.length; i++){ xxx[i] =i; for(int i=1; ;i+=xxx.length) { int ind = vratprvekpole(xxx, i); if(ind < 0){ // a jeho vyuziti System.out.println("Program ukoncen."); System.exit(1); else { System.out.println("index = " + ind); index = 1 Zachycena vyjimka: index = 11 Program ukoncen. // lepe: spojit s: assert (viz str. 25) Strana 16 (celkem 31)
Příklad 2: lepší řešení je (pokud to lze) pokusit se o nápravu vzniklého problému Např. - pokud je chybně zadán název souboru, umožnit jeho opětovné zadání import java.util.*; import java.io.*; public class IlustraceVyjimkyKompletniOsetreni { public static int [] nactipole(){ int pole [] = null; String nazevsouboru = "xxx.txt"; // spravne: pole.txt while (true){ try{ Scanner sc = new Scanner(new File(nazevSouboru)); int pocetprvku = sc.nextint(); pole = new int [pocetprvku]; for(int i=0; i<pole.length; i++){ pole[i] = sc.nextint(); break; catch (Exception e) { System.out.println("Soubor " + nazevsouboru + " nenalezen."); System.out.print("Zadej spravne jmeno: "); Scanner klavesnice = new Scanner (System.in); nazevsouboru = klavesnice.next(); Soubor xxx.txt nenalezen. return pole; Zadej spravne jmeno: pole Soubor pole nenalezen. /* Pozor na umisteni souboru a Zadej spravne jmeno: pole.txt pripadne zadani cesty k nemu. [1, 2, 3, 4, 5] */ Strana 17 (celkem 31)
Nejhorší reakce na výjimku - na první pohled nejjednodušší řešení, ale...! - většinou zapomenutí či lenost programátora import java.util.*; import java.io.*; public class IlustraceVyjimkyOsetreniNevhodne { private static Scanner; public static int []nactipole() { int pole [] = null; try{ sc = new Scanner(new File("pole.txt")); int pocetprvku = sc.nextint(); pole = new int [pocetprvku]; for(int i=0; i<pole.length; i++){ pole[i] = sc.nextint(); return pole; catch (Exception e) { // NIC!!! // takto rozhodne ne! return pole; public static void main(string[]args) { System.out.println(Arrays.toString(nactiPole())); Pokud soubor neexistuje - vypis null Takto ztratíme veškeré výhody výjimek, výjimka proběhne, ale nedozvíme se kdy a kde! Strana 18 (celkem 31)
Seskupování a selekce výjimek - např. dvě výjimky a chceme reagovat na obě. - to lze, neboť není omezen počet catch bloků Seskupování výjimek try {... catch(numberformatexception e){ System.out.println("Cislo " + e.getmessage() + " :spatne zadano "); catch(ioexception e){ System.out.println("Chyba pri cteni"); Postupná selekce výjimek try {... catch(numberformatexception e){ /* zpracuje se pouze jedna vyjimka ze tridy RuntimeException */ catch(runtimeexception e){ /* zpracuji se vsechny ostatní vyjimky ze tridy RuntimeException */ Strana 19 (celkem 31)
Výjimky - pouze pro pokročilé* někdy je třeba na zachycenou výjimku nereagovat, pak je nutno napsat do bloku catch komentář proč. Další možnost: převedení Exception na RunTimeException (používá se při zavírání souborů) Konstrukce try-catch-finally konstrukce try-catch se často doplňuje dalším blokem finally, ten probíhá vždy - bez ohledu, zda nastane výjimka (catch) nebo nenastane (try) (používá se při práci se soubory uzavření souborů) try { // vykonny kod, // provede se cely, nevznikne-li vyjimka catch (Exception e) { // kod zachyceni vyjimky // provadi se po vyskytu vyjimky finally { // ukoncovaci kod // provadi se vzdy jako posledni... více v P. Herout: Učebnice jazyka Java (str. 257-260) Poznámka: od Java verze 1.7 příkaz try-with-resources - viz http://docs.oracle.com/javase/7/docs/technotes/guides/langure/t ry-wit-resources.html a catching-multiple-exception-types catchmultiple.html Strana 20 (celkem 31)
static String readfirstlinefromfilewithfinallyblock(string path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readline(); finally { if (br!= null) br.close(); //---------------------- od verze Java 1.7 ------------------------------------ static String readfirstlinefromfile(string path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readline(); catch (IOException ex) { logger.log(ex); throw ex; catch (SQLException ex) { logger.log(ex); throw ex; //---------------------- od verze Java 1.7 ------------------------------------ catch (IOException SQLException ex) { logger.log(ex); throw ex; Poznámka ukázka (spustit) motivační příklad pro další přednášku (použití textových souborů) Strana 21 (celkem 31)
Ladění programů, příkaz Assert Jak přehledně zapisovat kód? - vhodná volba názvů identifikátorů - odsazení pomocí Tab - vkládaní mezer a volných řádek - neopakování sekvencí kódu Typy chyb Syntaktické ( pravopisné chyby) - porušení syntaxe daného jazyka, projeví chybou při kompilaci Logické, chyby v logickém návrhu programu, nejhůře se hledají (program běží, nevypisuje žádné chybové hlášení, ale nepracuje správně) Run time - vznikají až při běhu programu (různé příčiny) Ladění programu shora/zdola: Shora: ladíme nejprve kostru, zatím chybějící metody nahradíme provizorními, které dávají nějaký triviální výstup (zvolenou hodnotu) v požadovaném tvaru Zdola: ladíme nejprve dílčí metody, pro otestování správné funkce metod si vytváříme pomocné testovací programy, které metody volají se zvolenými parametry a vypisují (případně i testují) jejich výstupy Odstraňování chyb Postupné zakomentování jednotlivých částí kódu Průběžné výpisy proměnných Debugger - hledávání chyb (body přerušení, krokování kódu, sledování hodnot proměnných, ) Automatické testování - zabraňuje návratu opravených chyb, snižuje výskyt chyb v budoucnu Strana 22 (celkem 31)
Jakým způsobem testovat programy? - žádný nástroj za nás nevymyslí, JAK máme své programy testovat - data - vhodná volba testovacích dat, náhodná data - testovat okrajové a extrémní hodnoty - program - otestovat všechny větve - otestovat podmínky, konečnost cyklů - ověřování podmínek za běhu - assert Assert (bez kontroly obvyklé spuštění, pro kontrolu spustit: java ea Jmeno) Příklad 1 ilustrace použití dat (známe výsledek!) Spočtěte 5 cislo, log10 hodnota Řešení: cislo = 32, hodnota = 10 Příklad 2 (ilustrace použití Assert) Pro zadané číslo c má platit podmínka: 0 c 10 import java.util.scanner; /** použijte -ea v příkazu java */ public class Assert { private static Scanner sc = new Scanner(System.in); public static void main( String args[] ) { System.out.print("Zadejte cislo mezi 0 and 10: "); int cislo = sc.nextint(); // pozadavek: cislo musi byt >= 0 a <= 10 assert (cislo >= 0 && cislo <= 10) : "Chybne cislo: " + cislo; System.out.printf( "Zadali jste %d\n", cislo ); Strana 23 (celkem 31)
Obdobně: ochrana před použitím indexu mimo rozsah pole: assert (index >= 0 && index < a.length): "\nchyba: index = " + index + " je mimo meze: [0.." + a.length + "]"; import java.util.*; public class AssertPoleIlustracni { // pouzijte -ea v prikazu java private static Random r = new Random(); public static void main( String args[] ) { int[] a = new int[r.nextint(10) + 1]; // náhodná int index = a.length+1; // index = 0 ; // tento index bude vždy ok! for(int i=0; i<a.length; i++){ a[i] = r.nextint(10); System.out.println("Pole: " + Arrays.toString(a)); System.out.println("Meze pole: [0.." + a.length + "]"); // tvrdime, ze index musi byt >= 0 a < delka pole a assert(index >= 0 && index < a.length): "\nchyba: index = " + index + " mimo meze: [0.." + a.length + "]"; System.out.printf("Zvolen index %d, ", index); System.out.println("a[" + index + "] = " + a[index]); // jeste vylepsime pouzitim vyjimek Strana 24 (celkem 31)
Při zpracování výjimky v bloku catch možno použít příkaz assert. Příklad: ještě jednou - ošetření mezí pole public class AssertArrayBoundsExample { private static Scanner sc = new Scanner( System.in ); public static void osetrenimezipole(int [] pole, int index) { try { int x = pole[index]; catch (Exception e){ assert (index >= 0): "\nchyba - index mimo dolni mez! Index = " + index + ", ale mez = " + "0."; assert (index <= pole.length-1) : "\nchyba - index mimo horni mez! Index = " + index + ", ale mez = " + (pole.length-1) + "."; e.printstacktrace(); System.out.println("Detailni popis chyby - spustte s: -ea"); System.exit(1); Strana 25 (celkem 31)
public static void main( String args[] ) { // vytvoreni pole dane velikosti System.out.print( "Zadejte velikost pole: " ); int velikostpole = sc.nextint(); int pole [] = new int [velikostpole]; // naplneni pole for(int i=0; i<pole.length; i++) { pole[i]=i+1; // osetrime rozsah pole: musi byt >= 0 a < pole.length int j=0; while(true){ System.out.print("Vypiste prvek na indexu: "); j = sc.nextint(); osetrenimezipole(pole, j); System.out.format("Zadali jste index %d, hodnota prvku je %d\n", j, pole[j]); // vysledek spusteni bez volby ea: pro pole o 5 prvcich (0,4) Zadejte velikost pole: 5 Vypiste prvek na indexu: 5 java.lang.arrayindexoutofboundsexception: 5 at AssertArrayBoundsExample.osetreniMeziPole(AssertArrayBou ndsexample.java:13) at AssertArrayBoundsExample.main(AssertArrayBoundsExample.j ava:48) Detailni popis chyby - spustte s: -ea Strana 26 (celkem 31)
Příklad: Problém - dekompozice - program - ladění POMŮŽETE PASÁČKOVI? Pasáček hlídá na louce stádo koz. Kozy jsou méně či více vypasené (nejsou dvě stejné) a běhají různými rychlostmi. Jednoho kalného rána zavítá na louku hladový vlk. Prohlédne si všechny kozy a jak jinak, rozběhne se za tou nejvypasenější. Pokud bude koza rychlejší než vlk, tak mu samozřejmě uteče. Vlka však lov natolik vyčerpá, že si musí oddechnout a tak se znovu na louku vrátí až za dvě hodiny. A vše se opakuje. Protože je to ale chytrý vlk, nebude nikdy honit kozu, která mu už jednou utekla. Vybere si další nejvypasenější a zkusí to znovu. Chytí-li kozu, sežere ji a pak z louky odejde pryč. Pokud jsou kozy v dobré kondici a vlkovi se nepodaří za deset hodin některou z nich ulovit, odejde hladový lovit jinam. Kdyby měl pasáček k dispozici počítač a někdy už chodil na PPA1, mohl by si napsat program, který by mu řekl, je-li moudré stádo odehnat či, jak dlouho na louce setrvat. Poradíte pasáčkovi? Vstup Na prvním řádku je zadána celočíselná hodnota r v (0 > r v 50) reprezentující rychlost vlka. Na dalším řádku je zadán počet koz ve stádě p (1 p 15). Na dalších p řádkách je zadána vždy dvojice čísel, navzájem oddělených jednou mezerou, kde první z čísel reprezentuje vypasenost kozy v (1 v 15) a druhé číslo udává její rychlost r (1 r 15). Výstup Pokud bude vlk neúspěšný, vypište text: Vlk se nenazere, stado muze zustat!. Pokud nějakou kozu sežere, vypište text: Vlk by kozu sezral! na dalším řádku následovaný textem: Pasacek musí stado odehnat do: a počtem hodin, kdy bude stádo v bezpečí. Sežere-li vlk ovci ihned při prvním lovu, vypište text: Pasacek prijde o kozu!. Strana 27 (celkem 31)
Příklad vstupu 50 5 45 60 35 65 50 50 40 55 35 49 Příklad výstupu Pasacek prijde o kozu! Dekompozice: - vstup dat - vyber kozy - lov - výstup výsledku Struktura programu: Konstanty: - nejdelší doba lovu: 10 hodin - opakování lovu: po 2 hodinách - texty výsledku lovu Proměnné: - rychlost vlka - počet koz - kozy (hmotnost a rychlost) - dvourozměrné pole - počet hodin lovu Metody: - načtení vstupu - výběr kozy - lov - výpis výsledku Strana 28 (celkem 31)
import java.util.scanner; public class PasacekKoz { private static Scanner sc = new Scanner(System.in); static final int MAX_HODIN = 10; static String NEUSPECH = "Vlk se nenazere, stado muze zustat!"; static String USPECH_POZDEJI = "Vlk by sezral kozu! \npasacek musi stado odehnat do: "; static String USPECH_NAPOPRVE= "Pasacek prijde o kozu!"; static int [][] nactikozy(int pocetkoz){ int [][] kozy = new int[pocetkoz][2]; for(int i=0; i<kozy.length; i++){ kozy[i][0] = sc.nextint(); kozy[i][1] = sc.nextint(); return kozy; static int najdirychlostnejvypasenejsi(int[][] kozy){ int nejvypasenejsi = kozy[0][0]; //prvni int indexnejvypas = 0; for(int i=0; i<kozy.length; i++){ if(kozy[i][0] > nejvypasenejsi) { nejvypasenejsi = kozy[i][0]; // vaha nejvypasenejsi indexnejvypas = i; // index nejvypasenejsi if(kozy[indexnejvypas][0] > 0){ //nalezena kozy[indexnejvypas][0] = -1; // oznac - uz nehonit return kozy[indexnejvypas][1]; //vracena jeji rychlost else { return -1; //nenalezena (uz není zadna) Strana 29 (celkem 31)
static String lov(int rvlka, int kozy[][]){ String text = NEUSPECH; for(int pocethodin=0; pocethodin<=max_hodin; pocethodin += 2){ int rnejvypas = najdirychlostnejvypasenejsi(kozy); if(rnejvypas > 0){ // koza nalezena if(rnejvypas > rvlka){ // vlk je pomalejsi continue; // hledej dalsi kozu else { // uz neni dalsi koza text= NEUSPECH; // vlk nebude uspesny break; if(pocethodin > 0){ // vlk bude uspesny, pokud stado zustane text = USPECH_POZDEJI + pocethodin; break; else { // vlk sezere uz prvni kozu text = USPECH_NAPOPRVE; break; return text; static void vypis(string s){ System.out.println(s); Zadej rychlost vlka: 50 Zadej pocet koz: 5 Zadej hmotnosti a rychlosti koz: 45 60 35 65 50 50 40 55 35 49 Pasacek prijde o kozu! public static void main(string[] args) { System.out.print("Zadej rychlost vlka: "); int rvlka = sc.nextint(); System.out.print("Zadej pocet koz: "); int pocetkoz = sc.nextint(); System.out.println("Zadej hmotnosti a rychlosti koz: "); vypis(lov(rvlka, nactikozy(pocetkoz))); Strana 30 (celkem 31)
Návrh dat pro ladění programu: Existuje několik variant k prověření: Výběr dle hmotnosti (hledání maxima) a - rychlost každé z koz > rychlost vlka (neúspěch vlka) - rychlost jedné < rychlost vlka (úspěch vlka) - rychlost jedné = rychlost vlka (úspěch vlka) - rychlost více koz < rychlost vlka (úspěch vlka) Sledování doby lovu - rychlost první nejvypasenější rychlost vlka (sežere ji) - rychlost další (doba max) nejvypasenější rychlost vlka (stádo odehnat do spočtené doby) - rychlost další (doba > max) nejvypasenější rychlost vlka (stádo může zůstat) Počet koz - je jich dost na celou dobu lovu (možný úspěch) - je jich málo, tj. není-li další koza (neúspěch vlka) Zadej rychlost vlka: 50 Zadej pocet koz: 4 Zadej hmotnosti a rychlosti koz: 45 60 35 65 50 51 40 55 Vlk se nenazere, stado muze zustat! Zadej rychlost vlka: 50 Zadej pocet koz: 6 Zadej hmotnosti a rychlosti koz: 45 60 35 65 50 51 40 55 41 52 38 58 Vlk se nenazere, stado muze zustat! Zadej rychlost vlka: 50 Zadej pocet koz: 6 Zadej hmotnosti a rychlosti koz: 45 60 35 65 50 51 40 55 41 52 38 50 Vlk by sezral kozu! Pasacek musi stado odehnat do: 8 Zadej rychlost vlka: 50 Zadej pocet koz: 7 Zadej hmotnosti a rychlosti koz: 45 60 35 65 50 51 40 55 41 52 38 50 43 58 Vlk by sezral kozu! Pasacek musi stado odehnat do: 10 Zadej rychlost vlka: 50 Zadej pocet koz: 3 Zadej hmotnosti a rychlosti koz: 40 55 41 52 38 50 Vlk by sezral kozu! Pasacek musi stado odehnat do: 4 Zadej rychlost vlka: 50 Zadej pocet koz: 3 Zadej hmotnosti a rychlosti koz: 45 49 41 52 38 50 Pasacek prijde o kozu! atd. Strana 31 (celkem 31)