Search
Cílem tohoto cvičení je seznámit se se způsoby volání funkcí (metod), předávání argumentů a návratových hodnot v trochu složitějším programu. Konkrétně v programu, jehož účelem je zpracování textového záznamu z průběhu několika experimentů do podoby textové tabulky. Následně si vytvoříme graf průběhu sledovaných parametrů z experimentu.
Vedlejším cílem cvičení je pochopení již hotového kódu a schopnost jej rozšířit, což se ověří i na domácí úloze.
Zároveň si na začátek napíšeme krátký písemný test.
Výchozí projekt pr1-lab07.zip se skládá z připravené třídy Lab07, v které se používá rozšířená třída TextIO pro zpracování souboru se záznamy. Projekt také obsahuje třídu Demo, která je určena pro testování předávání argumentů a návratových hodnot funkcí. Pro volání metody start z třídy Demo je nutné modifikovat funkci main ve třídě Start. Hlavní část programu je implementována v metodě processFile, ve které je opakovaně načítán vstupní soubor a průměrná hodnota je vypočtena metodou getAvg. Již používaná třída TextIO v předchozích cvičení je v tomto projektu rozšířena o načítání textového souboru se záznamy. Práce se soubory není náplní tohoto cvičení, proto do této třídy pouze nahlédněte, případně se pokuste porozumět jakým stylem je vstupní soubor zpracován.
Lab07
TextIO
Demo
start
main
Start
processFile
getAvg
Součastí archívu projektu jsou také vstupní datové soubory v adresáři dat a sada skriptů (programů) pro vykreslení grafu získaných hodnot z datových souborů se záznamy experimentů. Tyto skripty jsou uloženy v adresáři scripts a jejich volání předpokládá dva argumenty, první je jméno souboru s tabulkou (vytvoří náš program) a druhý argument specifikuje výstupní pdf soubor, do kterého je vykreslen graf průběhu hodnot.
dat
scripts
readLine
getColumnValue
Hlavní mechanismus předávání vstupních parametrů funkcí jsou v programovacím jazyku Java argumenty, které se formálně zapisují (a pojmenovávají) v hlavičce funkce (metody). Argumenty funkcí jsou předávány v podstatě pouze hodnotou, můžeme však rozlišit mezi předáváním základního typu nebo referencí (odkazem) na existující objekt (obdoba ukazatele). V prvním případě volání hodnotou se ve funkci vytváří kopie proměnné a nastaví se její hodnota, proto změna této proměnné nemění hodnotu proměnné předchozí do funkce vstupující. Tento způsob předávání je využíván pro základní datové typy, jako jsou int, float, double atd. Příklad použití je například:
int
float
double
public void print(int n) { System.out.println("Input number is: " + n); //tisk hodnoty lokální proměnné na obrazovku, vytiskne 10 n += 10; System.out.println("Now, the number is: " + n); //tisk hodnoty lokální proměnné na obrazovku, vytiskne 20 } public void start() { int number = 10; //lokální proměnná s rozsahem platnosti v rámci metody start print(number); //předání proměnné (její hodnoty) funkci print System.out.println("Number is: " + number); //vytiskne 10, protože byla předána hodnota }
Druhým mechanismem je předávání odkazem (referencí), který se používá pro složitější datové typy (instance tříd). Při tomto předání není kopírován obsah celého objektu, ale pouze odkaz na vyhrazené místo v paměti, kde se jednotlivá data objektu nacházejí. Je dobré si uvědomit, že vlastně dochází pouze k předání (a kopírování) paměťové adresy, kde se objekt nachází, lokálně tak ve funkci vzniká nová proměnná typu reference, která však ukazuje na identické místo v paměti. Můžeme tak měnit obsah objektů, který takto do funkce vstupuje, ale také můžeme do této lokální proměnné (reference) přiřadit adresu jiného objektu, aniž bychom pak ovlivňovali stav předchozího objektu. To je demonstrováno na následujícím příkladu:
public void print1(StringBuilder str) { System.out.println("Print1: Input string is " + str); str.append(", CTU in Prague"); System.out.println("Print1: Now, the str is " + str); } public void print2(StringBuilder str) { System.out.println("Print2: Input string is " + str); str = new StringBuilder("CVUT"); //here, we create a new string and add the reference to the local variable str System.out.println("Print2: Now, the str is " + str); } public void printStrings(String[] args) { StringBuilder str = new StringBuilder("FEE"); print1(str); System.out.println("Main: str is " + str); print2(str); System.out.println("Main: after calling print2 str is still " + str); }
Očekávaný výstup programu je:
Print1: Input string is FEE Print1: Now, the str is FEE, CTU in Prague Main: str is FEE, CTU in Prague Print2: Input string is FEE, CTU in Prague Print2: Now, the str is CVUT Main: after calling print2 str is still FEE, CTU in Pragu
Pro výstupní hodnoty funkce slouží primárně návratový typ funkce, který se specifikuje v definici funkce jménem typu před jménem funkce. Například pro funkci isNumber s návratovou hodnotu typu boolean lze použít následující deklaraci hlavičky funkce.
isNumber
boolean
public boolean isNumber(String str) { ... return true; }
return
Je-li dovoleno používat ve funkci více příkazů return, využíváme jej zpravidla pro předčasný návrat z volání funkce, pokud nejsou splněny vstupní předpoklady, např. hodnoty argumentů nejsou v požadovaných mezích
void print(String[] strs) { if (strs == null || strs.length == 0) { return; } ... return; }
Požadujeme-li aby funkce vracela více hodnot nebo předávala více proměnných je nutné použít jako návratový typ složitější objekt, např. kontejner typu ArrayList. Lze také využít předávání argumentů odkazem, které jsou následně ve funkci vyplněny, ale tento způsob je běžný spíše v jazycích C/C++.
ArrayList
Náplní cvičení je vyzkoušet si předávání vstupních parametrů a výstupních hodnot funkcí, které kromě kratičkých demonstračních kódů je dále použito v řešení načítání a zpracování dat. Hlavní náplní cvičení je tak seznámit se s poskytnutým projektem a realizací jednoduchého programu pro zpracování textového záznamu z průběhu několika experimentů, ve kterém je každý experiment dokumentován jedním řádkem, ve kterém je informace o metodě, hodnotě parametru MNE a dvou hodnotách studovaných proměnných DISTANCE a CPUTIME. Jedná se o konrétní data z průběhu experimentů robotického průzkumu, ve kterém studujeme vliv parametru MNE na rychlost průzkumu a požadovaný výpočetní čas. Parameter MNE udává jak často je prováděno plánování, které se skládá z generování cílů a jejich přidělení mobilním robotům provádějícím průzkum. Vliv tohoto parametru analyzujeme pro čtyři metody přidělování cílů robotům, které jsou označeny GA, IA, HA a MA. Ukázku experimentálních mobilních robotů při exploraci a také porovnání exploračních cest pro plánovací metody HA a MA jsou zobrazeny na přiložených obrázcích.
MNE
DISTANCE
CPUTIME
GA
IA
HA
MA
Bližší informace problému, použitích metodách a vyhodnocení exploračních strategii lze nalézt na:
Průběh experimentu je ovlivněn mnoha faktory jako je schopnost lokalizace robotu, a proto lze považovat měrené hodnoty délky nejdelší explorační cesty robotu a potřebný procesorový čas za náhodné veličiny a měření je opakováno pro několik běhu se stejnými parametry. Výsledky jednotlivých běhů jsou uloženy jako zaznámy v souboru, kde na každém řádku je uloženo jedno měření pro konkrétní plánovací metodu a parametr MNE. Soubor tak má strukturu:
METHOD:ia;MNE:10;DISTANCE:61.1212;CPUTIME:116.25 METHOD:ha;MNE:10;DISTANCE:62.1952;CPUTIME:119.09 METHOD:ia;MNE:11;DISTANCE:58.7025;CPUTIME:132.73
Ukázkový vstupní soubor lze najít v dat/results-jh-l3r5.log. Pro vyhodnocení a porovnání jednotlivých metod nás zajímají průměrné hodnoty DISTANCE a CPUTIME v závislosti na parametru MNE v rozsahu 5 až 20 pro každou plánovací metodu. Proto chceme tento soubor zpracovat do podoby přehledové tabulky průměrných hodnot:
dat/results-jh-l3r5.log
MNE ga ia ha 5 77,6 63,9 58,1 6 71,3 60,3 55,8 7 69,4 55,6 56,1 8 70,8 60,8 56,7 9 75,2 59,4 58,5 10 71,2 62,8 60,1 11 70,1 64,0 59,4 12 71,8 61,1 58,6 13 69,2 62,2 60,3 14 73,2 62,9 60,7 15 70,0 62,3 59,9 16 73,3 63,2 62,5 17 75,8 65,3 61,0 18 72,6 62,4 62,3 19 74,4 69,0 64,2 20 73,2 67,4 65,8
Tabulka obsahuje čtyři sloupce oddělené tabulátorem (znak '\t') a na prvním řádku jsou uvedeny jmena sloupců. Tuto tabulku získáme spuštěním výchozího projektu, který ji při načtení vstupního souboru výpíše na standardní výstup. Program můžeme spustit z příkazové řádky voláním:
java -jar dist/lab07.jar
které vytvoří datový soubor jh-l3r5-avg.dat v aktuálním pracovním adresáři. Ten můžeme dále použít pro vykreslení grafu hodnot použitím dodaného skriptu voláním:
jh-l3r5-avg.dat
./scripts/graph_3methods_distance_avg_only.sh jh-l3r5-avg.dat jh-l3r5-avg.pdf
který vygeneruje PDF soubor zobrazující průběh vzdálenosti pro jednolivé plánovací metody v závislosti na parametru MNE, který je v grafu označen jak s_max.
printToFile
appendToFile
graph_4methods_distance_avg_only.sh
graph_4methods_cpu_avg_only.sh
Až budete mít hotové všechny úkoly ze cvičení (zpracování argumentů programu) i domácí úkol, můžete vyzkoušet zbylé skripty, které zpracovávají i tabulku směrodatných odchylek:
--- Příklad volání programu pro vytvoření souborů s tabulkami ant jar java -jar dist/lab07.jar dat/results-jh-l3r5.log DISTANCE jh-l3r5-avg.dat jh-l3r5-sd.dat java -jar dist/lab07.jar dat/results-jh-l3r5.log CPUTIME jh-l3r5-ctime-avg.dat jh-l3r5-ctime-sd.dat
--- Příklad vytvoření PDF souborů s grafy a jejich zobrazaní programem xpdf ./scripts/graph_4methods_distance.sh jh-l3r5-avg.dat jh-l3r5-sd.dat jh-l3r5-distance.pdf ./scripts/graph_4methods_cpu.sh jh-l3r5-ctime-avg.dat jh-l3r5-ctime-sd.dat jh-l3r5-ctime.pdf xpdf jh-l3r5-distance.pdf & xpdf jh-l3r5-ctime.pdf &
lab07