====== 5 - Zpracování vstupu - kontrola a ošetření vstupních hodnot ====== Cílem cvičení je rozšířit si znalosti zadávání základních typů a ošetření vstupních hodnot. Hlavní motivací je tvorba znovupoužitelných programů, které sice očekávají nějaký vstup, ale ten není vždy možné zajistit, např. nepozornost uživatele či chyby při zadávání hodnot. Proto se v tomto cvičení seznámíme jak v programu kontrolovat zadané hodnoty a jak psát programy, které počítají s tím, že vstupy nejsou vždy bezchybné. Pro použití programu je také výhodné mít možnost program spustit se specifickým vstupem a ovlivňovat jeho činnost aniž bychom jej museli znovu kompilovat. Proto se také seznámíme se způsobem předávání argumentů programu a jejich zpracováním. Opakované spouštění souvisí s dávkovým zpracováním a ukážeme si, jak opakované činnosti realizovat prostřednictvím volání příkazů z terminálu, který nám poskytuje unifikované rozhraní nejen pro naše programy, ale také řadu užitečných nástrojů. Tato volání můžeme řetězit a vytvářet tak efektivní dávky pro hromadné zpracování aniž bychom museli implementovat sofistikované grafické nadstavby. Místo toho se tak můžeme soustředit na zadávání nebo předávání vstupních dat pro vytváření dat výstupních bez čekacích prodlev na vstup uživatele, což nám umožní využít plný výkon počítače pouze pro naši úlohu. ===== Výchozí program v Javě ===== I v tomto cvičení vyjdeme z poskytnutých zdrojových souborů, které si stáhněte z archívu: {{:courses:a0b36pr1:labs:pr1-lab05.zip|}}. Ve vývojovém prostředí si vytvořte nový projekt "pr1-lab05" a přidejte do něj zdrojové soubory z archivu. I v tomto projektu je výchozí třída pro spuštění ''Start'', která vytvoří instanci třídy Lab05 a zavolá její metodu ''start()''. Procvičování zpracování vstupu je rozděleno do několika částí ''part1''(), ''part2''(), atd., které jsou volány podle aktuální hodnoty proměnné PART. Dále výchozí projekt obsahuje třídu ''TextIO'', která poskytuje funkce pro ověření, zda-li textový řetězec obsahuje celé nebo desetinné číslo. Její použití je demonstrováno na následujícím příkladu: String intNumberStr = "10"; String doubleNumberStr = "10.4"; System.out.println("Is '" + intNumberStr + "' a number: " + (TextIO.isInteger(intNumberStr) ? "yes" : "false"); System.out.println("Is '" + intNumberStr + "' a number: " + (TextIO.isInteger(intNumberStr) ? "yes" : "false"); ===== Informace k procvičovanému tématu ===== ==== Zadávání příkazů z terminálu ==== Ovládání počítače můžeme dnes rozdělit na dva základní směry. Ten první je určen pro širší obec uživatelů a nevyžaduje hlubší znalost fungování programů a snaží se uživateli nabídnout omezenou množinu voleb, aby se mohl jednoduše rozhodnout a mohl zadat pouze povolený vstup. Takovým příkladem může být aplikace v chytrém telefonu umožňující přijímat hovory a vytáčet čísla. Na druhé straně spektra uživatelského rozhrání je přímý přístup k zadávání příkazů počítači, který zpravidla umožňuje bohatší možnosti využítí výpočetních prostředků a především je určen pro opakované a hromadné provádění programů. Hodí se tak pro pokročilé uživatele, kteří dokaží použít již vytvořené programy také v jiném kontextu než původně vývojář aplikace zamýšlel a získat tak novou přidanou hodnotu. Neméně důležitou výhodou příkazového ovládání počítače je jednoznačnost a přímočarost zadání příkazů, které se skládá z textového zápisu jména příkazu a jeho argumentů. Není tak nutné složitě popisovat jak a kde má uživatel zadat vstup a jaké grafické symboly použít a stisknout. Lze tak snad vytvořit zápis vedoucí ke stejnému výsledku použitím stejného programu a vstupů, což má nezanedbatelnou úlohu pro opakovatelnost postupů. Tento způsob používání výpočetních prostředků jistě není určen pro každého, nicméně svým způsobem se zápis příkazů v terminálu velmi podobá zápisu zdrojového kódu programu. Z tohoto pohledu lze s jistou dávkou nadsázky říci, že grafická rozhraní jsou určena uživatelům konkrétních programů, kde mohou klikat pouze na dovolená místa. Na druhé straně obecné rozhraní terminálu je spíše určeno pro použití programátory, kteří mají přesnější vizi čeho chtějí dosáhnout a jak. Pro takové uživatele se pak příkazová řádka snadno stane efektivním rozhraním pro komunikaci s počítačem a využitím dostupných programových prostředků. Na počítačích laboratoře je nainstalován operační systém Ubuntu, který nabízí možnost terminálového vstupu a zadávání příkazů protřednictvím grafické aplikace ''Terminal'' jejíž popis základního použití lze najít na * [[http://wiki.ubuntu.cz/syst%C3%A9m/p%C5%99%C3%ADkazov%C3%A1_%C5%99%C3%A1dka/termin%C3%A1l]]. Další informace lze čerpat z * [[http://www.abclinuxu.cz/ucebnice/zaklady/prikazova-radka]], avšak pro potřeby cvičení vystačíme pouze se základní sadou příkazů pro změnu aktuálního adresáře, výpis jeho obsahu a spuštění programu: * ''pwd'' - (print working directory) - tento příkaz vypíše aktuální adresář, ve kterém terminál pracuje. Tento adresář (složka) se někdy také nazývá pracovní adresář a jeho použití je především v konstrukci cesty k souborům, které je možné vztáhnout relativně k tomuto adresáři. Při spuštění programu je tak možné odkazovat na soubory relativně vůči pracovnímu adresáři, což nám umožňuje realizovat přenositelné aplikace, které se odkazují pouze na soubory v příslušné lokální adresářové struktuře. * ''ls'' - (list directory contents) - příkaz vypíše obsah aktuálního adresáře. Tento příkaz zpravidla nabízí velké množstí parametrů, které kontrolují styl výpisu. Pro nás je v tuto chvíli nejzajímavější argument ''-l (long)'', který vypíše podrobné informace k souborům. Jeho použití je ''ls -l''. Další přepínače (argumenty modifikující chování programů) lze nalézt v dokumentaci, kterou vyvoláme napřílad příkazem ''man ls''. * ''cd'' - (change directory) - příkaz pro změnu aktuálního adresáře. Příslušný adresář je prvním argument programu. Zadáním příkazu bez argumentu přepne adresář do domovského adresáře uživatele. Pro názornější průzkum adresářové struktury v grafickém okně terminálu může použít textový správce souboru Midnight Commander, který se vyvolá příkazem ''mc''. Alternativně lze porovnat použití příkazů v okně terminálu s výstupem vámi oblíbeného grafického souborového manažeru. ===== Průběh cvičení ===== ==== Část 1 ==== Seznamte s hlavní metodou ''start'' v souboru L''ab05.java'' a voláním jednotlivým částí na základě hodnoty proměnné ''PART''. V první části je ukázka detekce typu s využitím připravené třídy ''TextIO''. Vyzkoušejte si chování detekce a modifikujte hodnoty proměnných. Nahlédněte do zdrojového souboru ''TextIO.java'' a zkuste se seznámit s principem detekce obsahu řetězce v metodách ''isInteger'' a ''isDouble''. ==== Část 2 ==== Ve druhé části ''part2()'' je využito třídy ''Scanner'' pro načtení řádku ze standardního vstupu a převod zadaného řetězce na číslo s testováním obsahu řetězce. Analyzujte chování programu v části ''part2()'' a diskutujte jaký dopad by mělo na zpracování vstupu opačné pořadí testování řetězce. Tj., nejdříve by se testovalo, zda-li obsahuje desetinné číslo a teprve pak na celé číslo. Vyzkoušejte si modifikaci programu s využitím metody pro načtení textového řetězce metodou ''next''() třídy Scanner. Diskutujte a implementací si vyzkoušejte rozdíl mezi metodami ''next()'' a ''nextLine()''. ==== Část 3 ==== V části ''part3()'' je ukázka testování vstupního argumentu funkce. Tento argument je předáván funkci při spuštění programu a odpovídá parametrům programu. Seznamte se s tímto konceptem a nastavením argumentu programu z vývojového prostředí Netbeans. Zvolte projekt v seznamu projektů a vyvolejte kontextovou nabídkou pravým tlačítkem myši. Zvolte vlastnosti projektu (''properties'') a v položce ''Run'' zadejte argument programu v ''Arguments''. Vyzkoušejte chování programu pro různé vstupní argumenty. Otestujte chování programu pro desetinná čísla s oddělovačem desetinné části čárka a tečka. Vysvětlete rozdíly v chování převodu čísla prostřednictví metody ''parseDouble'' a ''nextDouble''. ==== Část 4 ==== Program je možné spustit také přímo a není nutné využívat pouze vývojového prostředí Netbeans. Tak je možné předávat programu různé parametry a řetězit vykonávání programů a využívat je pro dávkové zpracování. To může být zvláště výhodné při opakované činnosti a realizaci identických nebo velmi podobných postupů. Pro pochopení tohoto konceptu si otevřete aplikaci terminál a zadejte následující sekvenci příkazů: wget http://robotics.fel.cvut.cz/comrob_real-h200.jpg ls convert comrob_real-h200.jpg -scale 50% comrob_real-h100.jpg ls -l Porovnejte velikosti obou souborů a vysvětlete jejich rozdíl. Zkuste odvodit co dělá příkaz convert a jaký je význam zadaných argumentů. ===== Úkoly na cvičení ===== - Seznamte se s částí ''part1()'' poskytnutého projektu. - Ve druhé části part2() si vyzkoušejte testování číselné hodnoty v textovém řetězci a načtení jednoho textového řetězce (tokenu) a celého řádku. - Vyzkoušejte si předání argumentu programu. - Vyzkoušejte si volání programů z příkazové řádky. - Modifikujte metodu start ve tříde ''Lab05'' tak, aby bylo možné zvolit volání příslušné metody part1-5 prvním argumentem programu. Nezapomeňte modifikovat metodu 3 pro správné načtení druhého argumentu. Definujte základní hodnotu načítané proměnné, pokud není vstupní argument zadán. Program při zadání nepovoleného argumentu, tj. mimo rozsah hodnot 1,2,3,4,5 program vypíše na standardní chybový výstup chybové hlášení "Unsupported value of the first program argument" a ukončí se. V případě nezadání prvního argumentu, program vypíše "First argument of the program is missing" na standardní chybový výstup (''System.err'') a ukončí se. Pro převod textového řetězce na celé číslo využijte volání int part = Integer.parseInt(str); ===== Domácí úkol ===== [[courses:a0b36pr1:hw:lab05|]]