Warning
This page is located in archive.

6 - Cykly

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í program v Javě

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:

    final int DEFAULT_PART = 2;
    int part = (args.length > 0 && TextIO.isInteger(args[0]) ? Integer.parseInt(args[0]) : DEFAULT_PART);

Informace k procvičovanému tématu

Cykly

for cyklus

  for (inicializace; podmínka; změna) {
    tělo cyklu
  }

  • Inicializace u for cyklu se provede pouze před prvním provedením těla cyklu.
  • Podmínka je ověřována před každým provedením těla cyklu.
  • Tělo cyklu se provede pouze, pokud je podmínka splněna.
  • Změna se provede vždy až po provedení těla cyklu. Použití preinkrementu či postinkrementu tuto vlastnost neovlivní.
  • U for cyklu lze vynechat libovolnou část příkazu for. Cyklus for(;;) bude nekonečný.

for cyklus - příklad

cyklus vypíše prvních deset násobků čísla i.

int i = 3;
for (int k=1; k<=10; k++) {
  int j = i * k; 
  System.out.print(j + ", ");
}

while cyklus

  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.

while cyklus - příklad

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 - while cyklus

do {
  tělo cyklu
} while (podmínka);

  • Nejprve se provede tělo cyklu a teprve po jeho prvním provedení se otestuje podmínka. Znovu se tělo cyklu provede pouze v případě platnosti podmínky.
  • Narozdíl od while cyklu se tělo do - while cyklu provede alespoň jednou.

do - while cyklus - příklad

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);

Příkaz break

  • Příkaz break ukončí provádění cyklu a pokračuje zpracováním kódu za tělem cyklu.
  • Výstupem tohoto kódu

for (int i=1; i<4; i++) {
  for (int j=1; j<4; j++) {
    if (i==2 && j==2) {
      break;  
    }
    System.out.println(j + " ");    
  }
}
bude posloupnost

1 2 3 1 1 2 3

Příkaz continue

  • Příkaz continue ukončí provádění těla cyklu a v případě splnění podmínky znovu zahájí zpracování těla cyklu.
  • Výstupem tohoto kódu

for (int i=1; i<4; i++) {
  for (int j=1; j<4; j++) {
    if (i==2 && j==2) {
      continue;  
    }
    System.out.print(j + " ");
  }
}
bude posloupnost

1 2 3 1 3 1 2 3

Kompilace programu z příkazové řádky

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

--- 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.

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:

--- 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
V tomto případě specifikujeme cestu, kde má JVM hledat třídy přepínačem -classpath (-cp) s uvedením cesty k adresářové struktuře, tj. kde jsou uloženy zkombilované třídy (.class).

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.

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).

--- 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:

--- 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.

Přestože je systém ant mocným nástrojem a dobře použitelný pro řadu projektů, v současné době je spíše používán jeho následovník Maven http://maven.apache.org/. Ten představuje moderní nástroj a jeho syntax je však o něco složitější a vyžaduje hlubší nastudování problematiky. To je však odměněno jeho bohatými možnostmi.

Průběh cvičení

Část 1

Nejdříve se seznamte s výpisem deseti hodnot v části part1(). Program modifikujte tak, aby vypsal čísla od deseti do jedné.

--- 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

Část 2

Do části part2() napište program, který

  1. Vypíše všechna sudá čísla v intervalu 1 až 20
  2. a následně čísla dělitelná sedmi v intervalu 13 až 39.

--- 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().

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

Část 3

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.

Kromě testu dělení čísla až do jeho výše minus jedna, je možné test zrychlit testováním až do výše zaokrouhlené druhé odmocniny testovaného čísla. http://en.wikipedia.org/wiki/Primality_test

--- 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

Část 4

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.

Načítání je ukončeno, pokud je detekován konec vstupu, pro který lze použít znak EOF (End-Of-File). Při vstupu z klávesnice je zpravidla možné tento znak zapsat kombinací CTRL+D.

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

Část 5

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.

--- 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:

--- 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.

Více o přesměrování se můžete dozvědět například na

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

Domácí úkol

courses/a0b36pr1/labs/lab06.txt · Last modified: 2015/11/09 13:01 by vanapet1