====== 4 - Řídicí struktury, vstupy, výstupy ====== * [[https://cw.fel.cvut.cz/wiki/courses/a0b36pr1/lectures/start#retezce_a_ridici_struktury|Přednáška]] Cílem cvičení je seznámit se se zadáváním základních typů, textovým vstupem a výstupem spolu s větvením programu. Cvičení se skládá ze čtyř hlavní částí, které jsou zaměřeny na procvičení jednotlivých programových konstruktů. /* * řešení: [[courses:A0B36PR1:tutorials:solutions:04:start]] */ * pro vyučující: [[courses:A0B36PR1:internal:tutorials:04:start]] ===== Výchozí program v Javě ===== V tomto cvičení již přejdeme od Karla k čisté Javě. Podobně jako v předchozích úlohách využijeme poskytnuté zdrojové soubory, pro které si založte ve vývojovém prostředí nový projekt. Výchozí zdrojové soubory pro toto cvičení si stáhněte z archívu: {{:courses:a0b36pr1:labs:pr1-lab04.zip|}}, který rozbalte do svého domovského adresáře (složky), např. ~/pr1/pr1-lab04 . * V NetBeans vytvořte nový projekt "pr1-lab04" z existujících zdrojových souborů z poskytnutého archivu. * Třída ''Start'' obsahuje pouze metodu ''public static void main(String[] args)'', která zajistí volání metody ze public static void main(String[] args) { Lab04 lab = new Lab04(); lab.start(args); } * třídy ''Lab04'', konkrétně metodu start(). Tato metoda tvoří hlavní vstup do vašeho programu. final int PART = 1; if (PART == 1) { part1(); } else if (PART == 2) { part2(); } else { System.out.println("part1 nor part2 has been specified"); } * Z této metody se volají jednotlivé části cvičení pojmenované ''part1''(), ''part2''(), atd., které v průběhu cvičení doplníme o další části. ===== Informace k procvičovanému tématu ===== ==== Formátovaný textový vstup ==== Pro vstup dat z klávesnice se s výhodou používá třída Scanner: Scanner scan = new Scanner(System.in); System.out.println("Enter a number:"); int cislo = scan.nextInt(); System.out.println("Enter a floating point number:"); double d = scan.nextDouble(); System.out.println("Enter a word:"); String s = scan.next(); System.out.println("Enter a whole line:"); String r = scan.nextLine(); **Poznámky:** * Desetinné číslo se zadává s oddělovačem desetinné části podle zvoleného národního prostředí. Například v prostředí anglické lokalizace MS Windows je nutné zadávat desetinnou tečku. V případě českého prostředí se naopak používá desetinná čárka. * Načítání textového vstupu prostřednictvím standardního vstupu ''System.in'' je zpravidla konfigurováno pro zadání kompletního příkazu / vstupu počítače, historicky to odpovídá potvrzení vstupu klávesou ''Enter'', proto je nutné předat vstup stiskem ''Enter''. * Nicméně dílčí volání ''nextInt()'', ''nextDouble()'' a ''next()'' zpracovávají takzvaný token, tj. textový řetězec oddělený definovaných znakem, např. mezerou nebo obecně takzvanou bílou mezerou z anglického "white space". * Zkuste si proto při testování zadávání vstupu například zadat jediný řádek obsahující všechny očekávané vstupy ''10 1023,44 slovo a zbytek celeho radku'' Nepoužívejte více instancí třídy Scanner - test na odevzdávacím serveru pravděpodobně skončí s chybou! Chcete-li použít Scanner v několika metodách, použijte ho takto: public class Lab { Scanner scan = new Scanner(System.in); public void method1() { System.out.println("Enter a number:"); int cislo = scan.nextInt(); System.out.println("Enter a floating point number:"); double d = scan.nextDouble(); ... } public void method2() { System.out.println("Enter a word:"); String s = scan.next(); System.out.println("Enter a whole line:"); String r = scan.nextLine(); ... } ==== Formátovaný textový výstup ==== Programovací jazyk Java poskytuje nejen základní metody pro formátování číselných typů a výpis řetězců, ale také způsob pro textovou reprezentaci času a data, který se zvláště hodí při unifikace a následné načítání. Předpis způsobu formátování je realizován textovým řetězcem obsahující vyhrazené formátovací znaky. String str = "Pepa"; char ch = 'x'; int i = 12; float f = 4.5F; Date date = new Date(); System.out.printf("%b%n", str); System.out.printf("%c%n", ch); System.out.printf("%03d%n", i); System.out.printf("%e%n", f); System.out.printf("%03f%n", f); System.out.printf("%.2f%n", f); System.out.printf("{%07.3f}%n", f); System.out.printf("%f%n", f); System.out.printf("%g%n", f); System.out.printf("%h%n", f); System.out.printf("%s%n", 5); System.out.printf("%s://%s/%s%n", str, str, str); System.out.printf("%1$s...%n", str); System.out.printf("%5s%n", str); System.out.printf("%-5s%n", str); System.out.printf("%-10.10s %s%n", str, 3); System.out.printf("%.5s%n", str); System.out.printf("%s%n", date); System.out.printf("%tc%n", date); //(lowercase t, lowercase c) System.out.printf("%tC%n", date); //(lowercase t, uppercase C) System.out.printf("%tD%n", date); System.out.printf("%tF%n", date); System.out.printf("%tr%n", date); System.out.printf("%tR%n", date); System.out.printf("%tT%n", date); System.out.printf("%tz%n", date); System.out.printf("%Tc%n", date); System.out.printf("%1$x, %1$X%n", 0xCAFE); System.out.printf(Locale.CHINA, "%tc%n", date); System.out.printf(Locale.ITALIAN, "%tc%n", date); System.out.printf(Locale.getDefault(), "%tc%n", date); **Podívejte se na přehled [[courses:a0b36pr1:literature:printf:start|formátových specifikátorů a speciálních znaků]].** ===== Řídicí struktury ===== ==== Podmíněný příkaz ==== Příkaz if (podmíněný příkaz) umožňuje větvení na základě podmínky. Má dva tvary: - if ( podmínka ) příkaz1 else příkaz2 - if ( podmínka ) příkaz1 //Podmínka// je logický výraz (výraz, jehož hodnota je typu ''boolean'', tj. ''true'' nebo ''false''). Přestože lze tuto podmínku zapsat na jeden řádek volíme pro přehlednost spíše zápis se složenými závorkami if ( podmínka ) { příkaz1 } else { příkaz2 } Podmínky můžeme také řetězit: if ( podmínka1 ) { příkaz1 } else if ( podmínka2 ) { příkaz2 } else { příkaz3 } ==== Operátor ? ==== Tento operátor nazýváme ternárním, neboť má tři argumenty. Umožňuje zapsat úplnou podmínku stručnějším, avšak v některých případech méně přehledným způsobem, zvláště pokud je těchto operátorů vnořeno více do sebe. Jeho syntax je: Podmínka ? Výraz1 : Výraz2; Je-li podmínka vyhodnocena jako pravdivá, bere se hodnota výraz1, v opačném případě výraz2. Podmínku if (a lze tedy zapsat jako c = a < b ? a++ : b++; ==== Příkaz switch ==== Na rozdíl od konstrukce //if-then// a //if-then-else//, příkaz //switch// povoluje více cest větvení programu na základě hodnoty celočíselné proměnné, která je argumentem příkazu ''switch''. Příkaz ''switch'' pracuje s primitivními typy: ''byte'', ''short'', ''char'', ''int'' a s instancemi třídy ''String''. Taktéž pracuje s výčtovými typy a se speciálními třídami obalujícími primitivní datové typy: Character, Byte, Short a Integer. Strukturu příkazu switch lze zapsat: switch(vyraz){ case konstanta1: Prikaz1; break; case konstanta2: Prikaz2; break; ... default: PrikazX; break; } ===== Kódovací styl ===== Dobrý program nejen funguje podle očekávání, ale je také snadno čitelný a to jak pro jeho autora, tak pro další programátory. Čitelnost programu lze zvýšit komentáři nicméně dobrý zdrojový kód zpravidla komentáře nepotřebuje a jeho pochopení je intuitivní a pochopitelné z vhodně zvolených jmen proměnných a funkcí. Čitelnost a přehlednost lze také zvýšit dodržováním správných návyků (kódovacích konvencí) a formátovacího stylu zápisu programu. V tomto cvičení si proto povšimněte, jak jsou zapisovány proměnné, konstanty a jména funkcí. * Proměnné by měly pokud možno co nejlépe vystihovat podstatu proměnné a její použití. Pro jméno proměnné volíme podstatná jména a nebojíme se použít delšího názvu. Čím specifičtější a jednoznačnější jméno proměnné je, tím lépe. Z názvu bychom měli být schopni intuitivně odvodit její použití a co vyjadřuje. * V programech jste se již setkali s voláním funkcí. Všiměte si, že jména funkcí jsou slovesa, která vyjadřují činnost, kterou funkce realizuje. Příklad kódovacích stylů lze najít například na * [[http://www.oracle.com/technetwork/java/codeconvtoc-136057.html]] nebo * [[https://google-styleguide.googlecode.com/svn/trunk/javaguide.html]]. Při práci na větším projektu nebo ve firemním prostředí je zpravidla použit vlastní styl a kódovací konvence, která však téměř vždy vychází ze zažitých zvyklostí pro konkrétní programovací jazyk. To je dáno především faktem, že dodržování kódovacího stylu usnadňuje porozumění a orientaci v kódu. Zdá-li se vám dodržování pravidel, zejména formátovacích zvyklostí náročné, tak nezoufejte, většina moderních vývojových prostředí nabízí kontrolu stylu a také podporu pro automatické formátování dle definovaných pravidel. Nejinak je tomu v prostředí Netbeans, kde základní formátování naleznete v menu Source->Format (nebo pod zkratkou Alt+Shift+F v základní konfiguraci). ===== Průběh cvičení ===== ==== Část 1 ==== V první části ''part1''() poskytnutého projektu jsou uvedeny ukázky formátovaného výstupu celočíselné proměnné a výpis čísla s desetinnou částí. Podívejte se na přehled formátových specifikátorů a vyzkoušejte si různé výpisy celých a desetinných čísel. ==== Část 2 ==== Ve druhé části je využito standardní třídy ''Scanner'' pro načítání hodnot proměnných ze standardního vstupu programu. Upravte hodnotu konstanty ''PART'' v metodě ''start'' tak, aby byla volána právě část dvě, tj. metoda ''part2()''. ==== Část 3 ==== V další části ''part3()'' se seznamte s úskalím reprezentace desetinného čísla. Zkuste objasnit proč při součtu velmi velkého a velmi malého čísla dochází ke ztratě numerické přesnosti. Pro volání tohoto kódu upravte obsah metody ''start'' s využitím větvení programu příkazem ''switch / case'' a nastavte hodnotu proměnné ''PART'' tak, aby byla volána metoda ''part3()''. ==== Část 4 ==== V části ''part4()'' jsou uvedeny způsoby načítání vstupu do různých proměnných. Pro volání tohoto kódu přidejte do metody ''start'' další větev ''case 4:'' a nastavte hodnotu proměnné ''PART'' tak, aby byla volána metoda ''part4()''. Ověřte chování programu při zadání jiného než očekávaného vstupu, tj. například místo čísla zadejte slovo nebo použijte jiný než očekávaný vstup. Také si vyzkoušejte zadání očekávaných vstupu na jeden nebo více řádků. ==== Část 5 ==== V části part5() je uveden kód pro porovnání hodnot dvou textových řetězců. Seznamte se s kódem, upravte metodu ''start'' pro jeho volání a vyzkoušejte si chování programu pro různé vstupy. ===== Úkoly na cvičení ===== - Využijte řídicí konstrukci ''switch / case'' a přepište volání ''if/else'' podle hodnoty proměnné PART. - Rozšiřte program o volání části ''part3()'' a ověřte ztrátu přesnosti reprezentace desetinných míst. - Seznamte se s možnostmi načítání standardního vstupu v části ''part4()'' a použitím metod třídy Scanner a vyzkoušejte si chování programu pro různé vstupy. - Rozšiřte program o volání části ''part5()'' a seznamte se se způsobem porovnání hodnot dvou textových řetězců. - Napište kód, který zjistí, zda je zadané číslo sudé či liché. Realizujte tuto funkcionalitu jako novou část ''part6()''. - Napište program, který načte číslo v rozsahu 1 - 7 a slovně vypíše odpovídající den v týdnu (1 .. Mon, 2 .. Tue, ..., 7 .. Sun ). V opačném případě vypíše chybu. Realizujte jako část ''part7()''. Pro větvení programu využijte konstruci ''switch / case''. - Určete, jakých hodnot bude nabývat proměnná ''"a"'' po provedení následujících výrazů. Svůj výpočet ověřte implementací (jako část ''part8()'' ). - b = 1; c = 2; a = ++b + c++; - b = 1; c = b += 2; a = b / c; ===== Další úlohy na procvičení ===== - Napište program, který vypíše cenu letenky v závislosti na destinaci: do Vídně a Bratislavy stojí letenka 12000 (lépe jet autem), do Londýna 2000 Kč, do Paříže za 3500 Kč a jinam nelétájí. Využijte větvení příkazem ''switch'' podle 1. písmene destinace, které zjistítem metodou ''charAt()''. - Napište program, který pro dané číslo < 100 000 vypíše slovně počet míst v jeho desítkovém zápise. Použijte funkci ''Math.log10()'' a příkaz ''switch''. - Vypište zda zadaný rok je přestupný. Použijte Gregoriánský kalendář platný od září 1752, ve kterém platí: je-li rok dělitelný 4, pak je přestupný. Je-li rok dělitelný 100, pak není přestupný a je-li rok dělitelný 400, pak je přestupný. - Napište program, který vypíše počet dní v měsíci (30 či 31, nezapomeňte na přestupný rok u únoru). ===== Domácí úkol ===== [[courses:a0b36pr1:hw:lab04|]]