Search
Cílem cvičení je seznámit se se způsoby zápisu cyklů a procvičit si zpracování posloupnosti hodnot. Dále pak rozvinout dovednosti programování a kompilace programu z příkazové řádky, zadávání vstupních argumentů programu a přesměrováním standardního vstupu a výstupu programu z/do souboru.
Výchozí projekt obsahuje rozšířenou implementaci třídy TextIO z minulého cvičení, která nově zapouzdřuje volání metody třídy Scanner pro načítání celého řádku ze standardního vstupu. Při vytvoření nové instance třídy TextIO dojde také k vytvoření instance třídy Scanner, která je rovnou napojena na standardní vstup System.in. Výchozí projekt si stáhněte z archívu: pr1-lab06.zip. Struktura zdrojových kódu je podobná projektům předchozích cvičení i zde je hlavní třída Start, ze které je volána metoda start třídy Lab06. V metodě start je však nově implementováno zpracování prvního vstupního argumentu, který určí jaká čast programu bude po spuštění vykonána. Všiměte si, že pokud není zadán žádný argument volá se příslušná část programu odpovídající hodnotě konstantní proměnné DEFAULT_PART. Pro tento účel je využito ternárního operátoru:
Scanner
TextIO
System.in
Start
start
Lab06
DEFAULT_PART
final int DEFAULT_PART = 2; int part = (args.length > 0 && TextIO.isInteger(args[0]) ? Integer.parseInt(args[0]) : DEFAULT_PART);
for (inicializace; podmínka; změna) { tělo cyklu }
for
cyklus vypíše prvních deset násobků čísla i.
i
int i = 3; for (int k=1; k<=10; k++) { int j = i * k; System.out.print(j + ", "); }
while(podmínka) { tělo cyklu }
Nejprve se otestuje platnost podmínky. Je-li splněna, provede se tělo cyklu a poté se opět otestuje platnost podmínky. V případě nesplnění podmínky při prvním testování, neproběhne tělo cyklu ani jednou.
Cyklus vypíše násobky čísla i až do hodnoty menší než 100.
int i = 5, j = 0; while (j < 100) { System.out.print(j + ", "); j += i; }
do { tělo cyklu } while (podmínka);
Co dělá následující kód?
java.util.Scanner in = new java.util.Scanner(System.in); int a; do { a = in.nextInt(); suma += a; if (a!=0) { soucet++; } } while (a!=0);
break
for (int i=1; i<4; i++) { for (int j=1; j<4; j++) { if (i==2 && j==2) { break; } System.out.println(j + " "); } }
1 2 3 1 1 2 3
for (int i=1; i<4; i++) { for (int j=1; j<4; j++) { if (i==2 && j==2) { continue; } System.out.print(j + " "); } }
1 2 3 1 3 1 2 3
Kromě kompilace a spuštění programu ve vývojovém prostředí je součástí standarního vývojářského balíku Java SDK také kompilátor a vlastní virtuální stroj JVM (Java Virtual Machine). Přestože při vývoji je zpravidla pohodlnější využít jak pro kompilaci tak pro spouštění programu vývojového prostředí (např. Netbeans) jsou situace, kdy je výhodnější sestavovat program přímo příkazem. Takové případy jsou například servery automatické kompilace a ověřování zdrojového kódu, u kterého při vývoji ve více členém týmu probíhají modifikace na různých částech a jedním z hlavním problémů je integrace a správné provázání jednotlivých částí. Předklad zdrojového kódu pak probíha kontinuálně tak jak jsou přidávány do projektu nové funkcionality a je vhodné celý proces automatizovat. Právě v takových situací jsou využívány nástroje pro řízení překladu a jedním z nich je systém Apache Ant ( http://ant.apache.org/ ). Ten vyniká jednoduchou syntax zápisu pravidel překladu http://www.root.cz/clanky/ant-nebojte-se-mravence/ a lze jej považovat za de facto standard pro překlad Java projektů. Rovněž vývojové prostředí Netbeans využívá tento systém pro překlad projektů.
Postup sestavení projektu je zapisovám v XML souboru build.xml a ukázku takového souboru můžete najít v poskytovaných projektech na jednotlivá cvičení. Pro naše účely vystačíme se základním použitím a vyjdeme právě z dodaného souboru. Předtím si však připomene sestavení programu kompilátorem javac. Nechť aktuální pracovní adresář obsahuje zdrojové kódy poskytnutého projektu pr1-lab06. Překlad jednolivých souborů lze provést příkazy
build.xml
pr1-lab06
--- Výpis obsahu adresáře zdrojových souborů v balíčku cz.cvut.fel.pr1 ls src/cz/cvut/fel/pr1 Lab06.java Start.java TextIO.java --- Překlad souborů javac src/cz/cvut/fel/pr1/TextIO.java javac -classpath src src/cz/cvut/fel/pr1/Start.java javac -classpath src src/cz/cvut/fel/pr1/Lab06.java --- Výpis obsahu adresáře, nově se zkompilovanými soubory .class ls src/cz/cvut/fel/pr1 Lab06.class Lab06.java Start.class Start.java TextIO.class TextIO.java
Všiměte si, že pro překlad tříd Start a Lab06 je nutné specifikovat dodatečnou cestu, kde má kompilátor hledat závislosti, neboť tyto třídy využívají naši novou třídu TextIO, která není standardní součástí Java SDK. Proto specifikujme cestu k balíku přepínačem -classpath (zkráceně -cp) s jedním argumentem.
classpath
cp
Spuštění programu (přeloženého bytekódu) provedeme příkazem java, kde je nutné uvést plné jméno třídy, tj. včetně jména balíku, ve kterém se třída nalézá. Jméno balíku je uvedeno ve zdrojového souboru za klíčovým slovem package. V našem případě spouštíme třídu Start z balíku cz.cvut.fel.pr1:
java
package
cz.cvut.fel.pr1
--- Spuštění třídy Start a výstup programu pro část part1() java -classpath src cz.cvut.fel.pr1.Start i: 00 - value 0.00 i: 01 - value 0.10 i: 02 - value 0.20 i: 03 - value 0.30 i: 04 - value 0.40 i: 05 - value 0.50 i: 06 - value 0.60 i: 07 - value 0.70 i: 08 - value 0.80 i: 09 - value 0.90
Tento způsob překladu však není příliš komfortní a použitelný je jen pro velmi malé projekty. Nicméně sofistikvanější nástroje nakonec nedělají nic jiného, než že generují takováto individuální volání překladače javac.
javac
V naše případě využijeme pro sestavení projektu příkaz ant, který v základní konfiguraci hledá soubor buidl.xml v aktuálním pracovním adresáři. Po načtení souboru s definicí překladu spustí překlad pro definovaný cíl, který je možné specifikovat prvním argumentem. Pro jednoduchost využijeme cíl jar, který nejen že přeloží příslušné zdrojové soubory projektu, ale také vytvoří archív (zip) přeložených souboru spolu s označením hlavní spustitelné třídy v balíku (v takzvaném manifestu1).
ant
buidl.xml
jar
--- Příklad výpisu při sestavení projektu příkazem ant ant jar Buildfile: build.xml build: [echo] Build Example [mkdir] Created dir: build [javac] Compiling 3 source files to build jar: [jar] Updating jar: dist/lab06.jar BUILD SUCCESSFUL Total time: 2 seconds
Všiměte si, že přeložené třídy .class jsou uloženy v adresáři build a výsledný jar balík je pak umístěn v adresáři dist. Nyní můžeme program spustit přímo z jar:
build
dist
--- Výpis přeložení souborů ls build/cz/cvut/fel/pr1 Lab06.class Start.class TextIO.class --- Výpis vytvořeného distribučního balíku ls dist lab06.jar --- Spuštění balíku java -jar dist/lab06.jar i: 00 - value 0.00 i: 01 - value 0.10 ...
Výhodou výtvořeného balíku je snadné spuštění což v kombinaci s přenositelností Java byte kódu umožňuje jednoduše zkopírovat balík lab06.jar na jiný počítač a spustit jej, je-li vybaven instalací JVM.
lab06.jar
Maven
Nejdříve se seznamte s výpisem deseti hodnot v části part1(). Program modifikujte tak, aby vypsal čísla od deseti do jedné.
part1
--- Příklad očekávaného výstupu programu i: 10 - value 1.00 i: 09 - value 0.90 i: 08 - value 0.80 i: 07 - value 0.70 i: 06 - value 0.60 i: 05 - value 0.50 i: 04 - value 0.40 i: 03 - value 0.30 i: 02 - value 0.20 i: 01 - value 0.10
Do části part2() napište program, který
part2
--- Ukázka výpisu volání programu s argumentem 2 pro spuštění druhé části part2() java -jar dist/lab06.jar 2 Even numbers: 2 4 6 8 10 12 14 16 18 20 Numbers divisible by 7: 14 21 28 35
V metodě start modifikujte větvění tak, aby v případě hodnoty proměnné PART == 1 došlo k volání jak part1() tak part2().
PART == 1
switch(PART) { case 1: part1(); case 2: part2(); break; ... }
Očekávaný výpis při spuštění programu s argumentem 1 pro první část je:
i: 10 - value 1.00 i: 09 - value 0.90 i: 08 - value 0.80 i: 07 - value 0.70 i: 06 - value 0.60 i: 05 - value 0.50 i: 04 - value 0.40 i: 03 - value 0.30 i: 02 - value 0.20 i: 01 - value 0.10 Even numbers: 2 4 6 8 10 12 14 16 18 20 Numbers divisible by 7: 14 21 28 35
Napište program v části part3(), který načte ze standardního vstupu celočíselnou hodnotu a zjistí, zda-li je číslo prvočíslo. Vstupní hodnotu testujte, zda-li je celým číslem metodou TextIO.isInteger a v případě neočekávaného vstupu vypište chybovou hlášku na standardní chybový výstup. Testujte metodu pro různě veliké vstupy a v případě nepřiměřeně dlouhého výpočtu omezte vstupní hodnotu.
part3()
TextIO.isInteger
--- Ukázka výpisu java -jar dist/lab06.jar 3 Enter an integer number > 2 and < 10000000 11 Given number 11 is prime number
--- Ukázka výpisu java -jar dist/lab06.jar 3 Enter an integer number > 2 and < 10000000 6257134 Given number 6257134 is not prime number
--- Ukázka chybového výpisu java -jar dist/lab06.jar 3 Enter an integer number > 2 and < 10000000 0 Given number is out of range
--- Ukázka chybového výpisu java -jar dist/lab06.jar 3 Enter an integer number > 2 and < 10000000 2 Given number is out of range
--- Ukázka chybového výpisu java -jar dist/lab06.jar 3 Enter an integer number > 2 and < 10000000 eleven It is not an integer number
Seznamte se s metodou part4() poskytnutého projektu, která počítá součet hodnot z posloupnosti zadaných čísel ze standardního vstupu. Všiměte si, jak je testován konec vstupu. Vstupní hodnoty jsou čteny jako textové řetězce po řádcích, přičemž se předpokládá, že na každém řádku je jedno číslo. Pokud řádek neobsahuje číslo, je jeho obsah ignorován.
part4
java -jar dist/lab06.jar 4 1 2 3 4 5 End of input detected! Sum of the 5 input numbers is 15.0
Program rozšiřte o výpočet průměrné hodnoty. S očekávaným výstupem ve tvaru
java -jar dist/lab06.jar 4 1 2 3 4 5 End of input detected! Sum of the 5 input numbers is 15.0 Avg of the 5 input numbers is 3.0
V páté části cvičení si vyzkoušíme překlad programu z příkazové řádky a jeho následné spuštění s předáním vstupního argumentu pro výběr příslušné části programu, která bude vykonána. Také si vyzkoušíme přesměrování standardního vstupu ze souboru.
Nejdříve si otevřete terminál a přepněte se do adresáře se staženými projektovými soubory, např. cd ~/pr1/pr1-lab06. V adresáři najdete zdrojové soubory v adresářové struktuře src a dále pak soubor pro řízení předkladu build.xml programu ant, případně další projektové soubory vytvořené prostředím Netbeans.
cd ~/pr1/pr1-lab06
src
--- Překlad zdrojových souborů ant jar
V archívu s projektovými soubory je také příklad vstupního souboru input.txt pro část part4(). Obsah textového souboru můžeme zobrazit příkazem cat:
input.txt
cat
--- Výpis obsahu souboru input.txt na standardní výstup cat input.txt 23 3 1 3 4
Tento soubor použijeme jako vstup našeho programu. Nejdříve tak, že přesměrujeme standardní vstup na tento soubor při spuštění programu:
--- Spuštění programu s přesměrovaným vstupem (a argumentem 4 pro spuštění 4. části) java -jar dist/lab06.jar 4 <input.txt End of input detected! Sum of the 5 input numbers is 34.0 Avg of the 5 input numbers is 6.8
Alternativně můžeme použít standardní výstup jednoho programu jako standardní vstup jiného programu prostřednictvím znaku svislítko | (pipe):
--- Spuštění programu s přesměrovaným vstupem jako výstupem programu cat cat input.txt | java -jar dist/lab06.jar 4 End of input detected! Sum of the 5 input numbers is 34.0 Avg of the 5 input numbers is 6.8
Dále můžeme přesměrovat standardní výstup programu
--- Spuštění programu s přesměrovaným standardním výstupem do souboru output.txt cat input.txt | java -jar dist/lab06.jar 4 >output.txt End of input detected!
a také můžeme přesměrovat standardní chybový výstup, například do souboru err.txt
--- Spuštění programu s přesměrovaným standardním výstupem do souboru output.txt a chybovým výstupem do err.txt cat input.txt | java -jar dist/lab06.jar 4 >output.txt 2>err.txt
V pracovním adresáři vzniknout dva soubory output.txt a err.txt, které můžete vypsat na obrazovku příkazem cat nebo otevřít ve vašem oblíbeném textovém editoru, např. gedit.
output.txt
err.txt
gedit
V případě používání alternativního operačního systému pak třeba přímo na stránkách jeho tvůrce
lab06