Image
22.6.2016 0 Comments

Java pod lupou I. /5.časť

Späť na úvod >> Späť na programovanie >> Späť na seriál

Príkazy

Vitajte pri ďalšom pokračovaní nášho rozprávania o Jave. V piatej časti sa dozviete, ako pomocou príkazov jazyka vysvetlíme počítaču, čo má presne robiť pri vykonávaní nášho programu. Skôr však, než začneme, treba uzavrieť ešte tému operátory. Podľa môjho pôvodného úmyslu k tomu malo dôjsť ešte v predošlej časti, ale vzhľadom na určité problémy pri výrobe časopisu sme po dohode s redakciou štvrtú časť Javy pod lupou o niečo skrátili. Chýbajúci záver teda dostávate do rúk teraz.

Pretypovanie

Poslednou témou, ktorá spadá do časti venovanej operátorom, je špeciálny typ výrazu, tzv. pretypovávací výraz. Jeho syntax je jednoduchá – pred výraz, ktorému chceme explicitne zmeniť typ, napíšeme tento výsledný typ do okrúhlych zátvoriek. V C++, vlastne ešte v C blahej pamäti, sa tomuto zápisu hovorí aj operátor pretypovania. V Jave sa dáva prednosť pojmu pretypovávací výraz (cast expression). V praxi sa obyčajne tento výraz používa pri explicitnom pretypovaní číselných výrazov či pri explicitnej zmene typu referenčnej premennej, ktorá ukazuje na nejaký objekt (to ide s ohľadom na dedičnosť). Príklad:

byte b = 0x3C;
byte c = (byte)(b << 4);

Ak chceme uložiť výsledok posunu premennej b typu byte o štyri bity vľavo naspäť do inej premennej c typu byte, musíme použiť explicitné pretypovanie, inak prekladač ohlási chybu „Possible loss of precision“ a program nepreloží.

Výsledkom pretypovania nikdy nie je premenná, zápis z C++:

(double)x = 1.23;

je teda chybou. V Jave ostatne takýto zápis pravdepodobne nikdy nebudeme potrebovať.

Pretypovávať možno medzi sebou len niektoré typy, napríklad pokus pretypovať primitívny typ na referenčný sa skončí chybou už počas prekladu. Niektoré pretypovania uspejú za každých okolností (napr. pretypovanie potomka na predka v objektovej hierarchii tried), správnosť iných treba overiť až za behu programu.

Priorita operátorov

Aby bolo rozprávanie o operátoroch úplné, treba ešte uviesť poradie, v ktorom sa budú vyhodnocovať operátory vo výraze, ktorý neobsahuje zátvorky. Jednotlivé operátory totiž majú rôznu prioritu a klasickým spôsobom zľava doprava sa budú vyhodnocovať len operátory s rovnakou prioritou. Zoznam operátorov zoradený podľa ich klesajúcich priorít je v tabuľke 1. Najvyššiu prioritu má, samozrejme, explicitné uzátvorkovanie príslušných častí výrazu. Zátvorky sa odporúča použiť vždy, keď by mohlo dôjsť k omylu či zmätku pri riešení poradia vyhodnocovania (samozrejme, omylu zo strany programátora, počítač stanovené poradie vždy dodrží).

***** DTP *****
Niekde k tomuto odseku (Priorita operátorov) prosím umiestniť tabuľku 1.
***** DTP *****

Krátka rekapitulácia

Zhrňme si teraz v krátkosti, čo sme dosiaľ prebrali. Vieme, že Java stavia na princípoch objektovo orientovaného programovania. Všetok kód v Jave je organizovaný do tried, čo sú v princípe šablóny na tvorbu objektov. Každý existujúci objekt v programe je inštanciou nejakej triedy. Objekty medzi sebou komunikujú pomocou zasielania správ, čo sa zo syntaktického hľadiska realizuje volaním metód. Metódy sú ekvivalentmi céplusplusovských členských funkcií tried. Okrem metód, ktoré opisujú správanie objektov, nájdeme v triedach členské premenné, v ktorých je uložený stav objektov. Na úrovni zdrojového kódu je trieda syntaktickou konštrukciou, ktorá obsahuje opis členských premenných a metód. Tomuto opisu inak hovoríme deklarácia. Deklarovať vo všeobecnosti treba všetky premenné, ktoré jednotlivé objekty budú používať, čo okrem členských premenných predpokladá aj lokálne premenné, používané pri vykonávaní kódu metód. Pri deklarácii premennej je nevyhnutné uviesť jej typ a názov a prípadne aj inicializačnú hodnotu. Deklarácia metódy oznamuje prekladaču okrem názvu metódy počet a typ jej argumentov a typ návratovej hodnoty. Metódy, pochopiteľne, nemusia mať argumenty ani vracať nijakú konkrétnu hodnotu. Čo sa týka typov údajov, s ktorými program pracuje, možno ich rozdeliť na primitívne a referenčné. Prvá množina typov zahŕňa číselné typy (celočíselné i s desatinnou čiarkou) a logický typ. Druhá množina predstavuje v zásade štruktúrované typy, menovite objekty (inštancie tried) a polia. Špeciálnym referenčným typom sú rozhrania. Spôsob spracovania údajov v programe sa vyjadruje spôsobom takmer matematickým, pomocou výrazov. Každý výraz je tvorený kombináciou operátorov a ich operandov. Operátory sú symboly vyjadrujúce požadovaný druh operácie, ktorú treba vykonať na operandoch. Výsledkom vyhodnotenia výrazu je vždy nejaká hodnota. Jednotlivé operátory možno roztriediť do skupín podľa priority vyhodnocovania.

Intermezzo: praktický príklad

Dosť bolo teórie, ukážeme si teraz krátky, ale praktický príklad, ktorým bude program na výpočet koreňov kvadratickej rovnice. Aby bol program reálne použiteľný, budeme chcieť vypočítať korene aj v prípade, že riešenie bude ležať mimo množiny reálnych čísel, v komplexnej oblasti. Bohužiaľ, dosiaľ sme nehovorili o podmienenom vykonávaní príkazov, preto prosím čitateľov o prepáčenie, že v programe nájdu zatiaľ neznámy príkaz if. Jeho použitie je však pomerne zrozumiteľné a okrem toho bližšie informácie sa nachádzajú o niekoľko odsekov ďalej.

Takže tu je program (výnimočne kompletný):

 
import java.io.*;
 
class Quadratic
{
  public static void main(String[] args) throws IOException
  {
    BufferedReader in =
    new BufferedReader(new InputStreamReader(System.in));
    double a, b, c;
 
    System.out.print("a = ");
    a = Double.valueOf(in.readLine()).doubleValue();
    System.out.print("b = ");
    b = Double.valueOf(in.readLine()).doubleValue();
    System.out.print("c = ");
    c = Double.valueOf(in.readLine()).doubleValue();
 
    double D = discr(a, b, c);
 
    if (D > 0)
    {
      System.out.println("\nTwo roots:");
      System.out.println("  x1 = " + ((-b + Math.sqrt(D)) / 2 / a));
      System.out.println("  x2 = " + ((-b - Math.sqrt(D)) / 2 / a));
    }
    else if (D == 0)
    {
      System.out.println("\nOne double root:");
      System.out.println("  x = " + (-b / 2 / a));
    }
    else
    {
      System.out.println("\nTwo complex roots:");
      System.out.println("  x1 = " + (-b / 2 / a) +
                  " + " + (Math.sqrt(-D) / 2 / a) + "i");
      System.out.println("  x2 = " + (-b / 2 / a) +
                  " - " + (Math.sqrt(-D) / 2 / a) + "i");
    }
  }
 
  private static double discr(double a, double b, double c)
  {
    return b * b - 4 * a * c;
  }
}

Zdrojový text treba, samozrejme, prepísať do súboru Quadratic.java. Ak program preložíte a spustíte, vypýta si od vás tri koeficienty kvadratickej rovnice a, b a c. S ohľadom na jednoduchosť sa nikde nekontroluje, či zadáte kvadratický koeficient a nenulový (program v tom prípade poskytne kuriózne výsledky – presvedčte sa sami). Takisto nie je nijako ošetrené zadanie nečíselných hodnôt. Spôsob zadávania vstupu vyzerá veľmi komplikovane, ale zatiaľ ho čitateľ bude musieť akceptovať bez vysvetlenia.

Na výpočet diskriminantu je v triede Quadratic zavedená súkromná metóda discr(). Spočítaná hodnota diskriminantu sa testuje voči nule. V prípade, že je diskriminant kladný, program vypočíta a vypíše dva reálne korene, nulový diskriminant znamená jeden dvojnásobný koreň a konečne záporná hodnota diskriminantu spôsobí výpočet dvoch komplexných koreňov.

Verím, že sa na mňa nebude ani jeden čitateľ hnevať za použitie anglických textov v programe. Angličtina, ako lingua franca počítačového sveta (internet nevynímajúc), dnes totiž patrí medzi nevyhnutné, i keď rozhodne nie postačujúce znalosti úspešného programátora.

Hor’ sa na príkazy

Ako sme už niekoľkokrát uviedli, bežiaci program v Jave si možno predstaviť ako množinu vytvorených objektov, ktoré medzi sebou komunikujú prostredníctvom správ. Na syntaktickej úrovni je poslanie správy realizované ako zavolanie konkrétnej metódy konkrétneho objektu. Ako však virtuálny počítač vie, čo má robiť pri vyvolaní danej metódy? Nuž, povie mu to obsah tela metódy, ktoré, ako sme videli, je uzavreté do zložených zátvoriek ({}). Telo každej metódy je tvorené postupnosťou príkazov.

Ak sú teda stavebnými jednotkami programu objekty so svojimi atribútmi a metódami, možno povedať, že stavebnými jednotkami jednotlivých metód sú príkazy. Každý príkaz opisuje jeden malý krok algoritmu, ktorý daná metóda realizuje. V uvedenom príklade sme mali metódu discr(), ktorá obsahovala jediný príkaz na výpočet hodnoty diskriminantu. Mohli sme, pravda, tento výpočet rozdeliť do viacerých krokov, a teda do viacerých príkazov, ale bolo by to zbytočné.

Každá metóda obsahuje žiaden, jeden či viacero príkazov, ktoré sú navzájom oddelené bodkočiarkou. Áno, metóda môže obsahovať aj nulový počet príkazov – takáto prázdna metóda síce nerobí nič užitočné, ale môže slúžiť ako akýsi zástupca (angl. placeholder, ktorý doslova „drží miesto“) do doby, kým potrebné príkazy do jej tela doplníme (nič neobyčajné pri vývoji väčších programov).

Deklaračné a výrazové príkazy

Prvé dva typy príkazov už dobre poznáte, ani o tom neviete. Každá deklarácia lokálnej premennej je príkazom. V tele metódy, samozrejme, nemožno deklarovať nič iné ako lokálne premenné (a takisto lokálne triedy, ale o tom ešte budeme hovoriť). Zoberme si príklad:

double a, b, c;

Tento zápis je príkazom, ktorého účinok je zrejmý: prekladač odteraz až do skončenia príslušného rozsahu platnosti bude identifikátory a, b a c považovať za premenné typu double a podľa toho bude s nimi aj narábať.

Iným typom príkazu je výrazový príkaz. Takmer každý výraz, ktorý je správne zapísaný podľa syntaktických pravidiel Javy, môžeme použiť ako samostatný príkaz. Slovko takmer je namieste – Java totiž na rozdiel od C++ povoľuje ako príkazy použiť len výrazy, ktoré spôsobujú nejaký trvalý efekt. Medzi ne patrí volanie metódy (možno zavolať aj metódu, ktorá „nič nemení“, ako napr. naša metóda discr(), ktorá len vráti vypočítanú hodnotu), priraďovací výraz či výrazy s operátormi ++ a ––. Pri pokuse použiť ako príkaz výraz, ktorý iba vracia hodnotu, prekladač ohlási chybu. Tu je príklad výrazového príkazu, ktorý má účinok – zmení obsah premennej x:

x *= (x – 1);

A pre úplnosť je tu aj chybný výrazový príkaz, ktorý „nič nerobí“:

x * (x – 1);  // CHYBA!

Výsledná hodnota výrazu použitého vo výrazovom príkaze sa ignoruje.

Podmienený príkaz if

S týmto príkazom sme sa už stretli v príklade o niekoľko odsekov vyššie. Príkaz if slúži na vyjadrenie podmieneného vykonávania určitej časti programu v závislosti od splnenia či nesplnenia zadanej podmienky. Jeho syntax je nasledujúca:

if ( podmienka )
    príkaz

Príkaz if má ešte jeden možný zápis:

if ( podmienka )

    príkaz1
else
    príkaz2

V prvom, kratšom tvare sa príkaz vykoná vtedy a len vtedy, keď výraz podmienka bude mať hodnotu true. Na rozdiel od C++ musí byť podmienkový výraz typu boolean, inak dôjde k chybe pri preklade. V prípade, že podmienka nie je splnená, teda výraz má hodnotu false, príkaz sa preskočí. Druhý zápis umožňuje vybrať z dvojice príkazov podľa toho, či je podmienka pravdivá alebo nie. Ak bude výsledkom výrazu podmienka hodnota true, vykoná sa príkaz1, ak sa podmienka vyhodnotí na false, vykoná sa príkaz2.

Bolo by dosť nešikovné, keby sme v rámci príkazu if mohli skutočne použiť iba jeden príkaz, vykonávaný v závislosti od splnenia či nesplnenia podmienky. Preto je v Jave podobne ako v C++ možné na mieste takmer každého príkazu použiť tzv. zložený príkaz, resp. blok príkazov. Takýto blok vytvoríme jednoducho: uzavrieme požadované príkazy do zložených zátvoriek. Za zloženým príkazom na rozdiel od jednoduchého nepíšeme nikdy bodkočiarku.

I keď použitie príkazu if je zrejmé z programu na riešenie kvadratickej rovnice, ukážeme si ešte nejaký príklad:

if (a == 0)

  System.out.println("a is zero");
else
  System.out.println("a is non-zero");

Takýto úsek kódu vypíše, či obsah premennej a je nulový alebo nenulový. Príslušné vetvy príkazu if obsahujú len po jednom príkaze, preto sú zložené zátvorky zbytočné. Ak však budeme mať nasledujúci príklad:

if (a != 0)
{
  b = 5 / a;
  System.out.println("5 / a = " + b);
}
else
  System.out.println("cannot divide");

zložené zátvorky okolo dvoch príkazov v „true“ vetve príkazu if sú nevyhnutné.

V súvislosti s príkazom if treba spomenúť jeden z najznámejších zádrhov v programovacích jazykoch. Obsahom kladnej vetvy príkazu if môže byť opäť príkaz if. Ako však vyriešiť nasledujúcu situáciu?

if (x != 0)
  if (y != 0)
    z = 1 / (x * y);
  else
    z = 1 / x;

Patrí časť else prvému či druhému príkazu if? V tomto príklade odsadenie kódu nasvedčuje druhej možnosti. Skutočne, prakticky vo všetkých programovacích jazykoch, ktorých sa tento problém týka, existuje pravidlo, podľa ktorého časť else prislúcha vždy najbližšiemu neuzavretému príkazu if, v našom prípade druhému, vnorenému. Pozor teda, ak chceme mať časť else len pri vonkajšom if, musíme použiť zložené zátvorky:

if (x != 0)
{
  if (y != 0)
    z = 1 / (x * y);
}
else
  z = 1;

Mimochodom, v ukážkovom programe na riešenie kvadratickej rovnice je použité iné združovanie príkazov if, ktoré nie sú vnorené jeden do druhého, ale sú takpovediac zreťazené – ak nie je splnená jedna podmienka, testuje sa druhá, prípadne tretia a ďalšie. Ak by sme chceli dodržiavať pravidlá pre „pekné“ formátovanie zdrojového textu, rýchlo by zdrojový kód začal pretekať cez pravý okraj okna editora. V praxi teda obyčajne namiesto zápisu:

if (D > 0)
{
  // ...
}
else
  if (D == 0)
  {
    // ...
  }
  else
    if (D < 0)
    {
      // ...
    }

použijeme úspornejší zápis:

if (D > 0)
{
  // ...
}
else if (D == 0)
{
  // ...
}
else if (D < 0)
{
  // ...
}

Poznámka: ak je čitateľ zvyknutý z C++ testovať nenulovosť či nulovosť premennej (napr. x) takto:

if (x) { ... }
 
resp.
 
if (!x) { ... }

má v Jave smolu, takéto zápisy sú chybné. Podmienkové výrazy totiž musia byť typu boolean a treba použiť tvary:

if (x != 0) { ... }

prípadne

if (x == 0) { ... }

Podmienený príkaz switch

Ďalším príkazom, pomocou ktorého možno vetviť vykonávanie programu v závislosti od určitej podmienky, je príkaz switch. Ako napovedá jeho názov, ide doslova o prepínač, ktorý vyberie vetvu programu na základe hodnoty nejakého výrazu. Takýto kód možno naprogramovať aj pomocou zreťazených príkazov if, ale pri použití príkazu switch ušetríme dačo miesta a ešte k tomu zabránime viacnásobnému vyhodnocovaniu testovaného výrazu (čo oceníme v prípade, že tento výraz má nejaké vedľajšie účinky).

Ako vyzerá príkaz switch? Jeho syntax je nasledujúca:

switch ( výraz )
{
case hodnota1 :
    príkazy
case hodnota2 :
    príkazy
 
    // ...
 
default:
    príkazy
}

Pozrime sa na túto schému podrobnejšie. Za kľúčovým slovom switch nájdeme v okrúhlych zátvorkách testovaný výraz. Ten musí mať niektorý z typov char, byte, short alebo int. Za výrazom nasleduje v zložených zátvorkách uzavretý blok príkazov. V tomto bloku sa na určitých miestach vyskytujú tzv. návestia v tvare case hodnota. Jednotlivé hodnoty v návestiach musia byť rôzne a kompatibilné s typom výrazu.

Keď program počas behu dospeje k príkazu switch, určí hodnotu výrazu a postupne bude prehľadávať hodnoty uvedené v návestiach v bloku príkazov. Ak nájde zhodu, začne vykonávať príkazy za nájdeným návestím až do konca tela príkazu switch. V prípade, že ani jedno návestie neobsahuje hľadanú hodnotu, program pokračuje príkazmi za návestím default. Toto návestie nie je povinné, a ak sa v tele príkazu switch nenachádza, program jednoducho pri neúspešnom hľadaní zhody príkaz switch preskočí.

Podobne ako v C++ sa v okamihu nájdenia zhody ďalšie návestia ignorujú a program takpovediac „prepadáva“ cez jednotlivé návestiami oddelené úseky príkazov, až kým dospeje na koniec príkazu switch. To ilustruje nasledujúci príklad:

class OneTwo
{
  public static void main(String[] args)
  {
    show(3);
    show(2);
    show(1);
  }
  static void show(int n)
  {
    switch (n)
    {
    case 1:
      System.out.print("one ");
    case 2:
      System.out.print("two ");
    default:
      System.out.print("other");
    }
    System.out.println("");
  }
}

Tento program po spustení vypíše riadky:

other
two other
one two other

pretože po odskoku na návestie case 1, resp. case 2, a vypísaní príslušného textu program jednoducho pokračuje ďalšími príkazmi v tele switch. Ak tomu chceme zabrániť, treba použiť iný príkaz break, ktorý v tele príkazu switch spôsobí, že program z tohto tela vyskočí a bude pokračovať prvým príkazom za celým blokom switch.

Upravená metóda show() bude potom vyzerať takto:

static void show(int n)
{
  switch (n)
  {
  case 1:
    System.out.print("one");
    break;
  case 2:
    System.out.print("two");
    break;
  default:
    System.out.print("other");
  }
  System.out.println("");
}

S takouto verziou show() už program vypíše správny výstup:

other
two
one

Príkaz cyklu while

Dva predchádzajúce príkazy, if a switch, patria medzi príkazy selekcie, resp. alternatívy, takisto sa im hovorí podmienkové príkazy. Druhý okruh príkazov, na ktorých je založená teória štruktúrovaného programovania, sú príkazy cyklu.

Na realizáciu jednoduchého cyklu s testovaním podmienky na začiatku slúži príkaz while. Syntax tohto príkazu je:

while ( podmienka )
    príkaz

Výraz podmienka musí byť podobne ako v príkaze if typu boolean, iný typ prekladač odmietne. Na mieste príkazu môže stáť aj zložený príkaz, teda blok príkazov, uzavretý v zložených zátvorkách.

Príkaz while sa vykonáva týmto spôsobom: najprv sa vyhodnotí podmienkový výraz. Ak je jeho hodnota pravdivá, teda true, vykoná sa príkaz a opätovne sa riadenie programu vráti akoby pred príkaz while. Ak bude hodnota podmienky nepravdivá, cyklus while sa končí, príkaz sa ďalej vykonávať nebude. Treba si uvedomiť, že ak bude už na začiatku cyklu podmienka nesplnená, telo cyklu sa nevykoná ani raz.

Slovo „while“ v angličtine znamená „kým, pokiaľ“ a podľa toho sa aj cyklus while správa: vykonáva príkaz, kým je splnená určitá podmienka. Podmienka sa testuje pred vykonaním tela cyklu.

Ukážme si príklad na tento cyklus. Chceme nájsť najmenšieho spoločného deliteľa dvoch čísel uložených v premenných a a b. Použijeme známy Euklidov algoritmus:

while (a != b)
{
  if (a > b)
    a = a – b;
  else
    b = b – a;
}

Cyklus bude „cykliť“ dovtedy, kým budú hodnoty premenných a a b rôzne. Po skončení cyklu bude v oboch premenných a aj b ich najmenší spoločný deliteľ (ukončovacou podmienkou je rovnosť premenných a a b). Program, pochopiteľne, nefunguje pre záporné hodnoty.

V cykle while, podobne ako v príkaze switch, môžeme použiť príkaz break. V tele cyklu však tento príkaz spôsobí okamžité prerušenie vykonávania cyklu a vyskočenie programu za koniec tohto cyklu. Jedným z častých príkladov použitia je cyklus, v ktorom testujeme podmienku niekde „uprostred“:

while (true)
{
  a++;
  if (a > 100)
    break;
  b––;
}

(Nehľadajte v tomto úseku kódu hlbší zmysel, nie je tam.) Za povšimnutie stojí, že ako podmienku cyklu while sme uviedli literál true. Takáto podmienka bude vždy splnená, a preto by sa cyklus nikdy neskončil, nebyť toho, že v určitom momente (v tomto prípade, keď premenná a prekročí stovku) príkazom break cyklus prerušíme.

Príkaz cyklu do

Pri príkaze while sa testuje iteračná podmienka na začiatku cyklu. Môže sa však stať, že budeme potrebovať túto podmienku testovať až na konci cyklu, pretože napríklad jej obsah závisí od toho, čo sa v tele cyklu vykonalo. Pre tento variant máme v Jave k dispozícii príkaz do s nasledujúcou syntaxou:

do
    príkaz
while ( podmienka );

Podmienka musí byť opäť typu boolean a príkaz môže byť zložený.

Pri realizácii cyklu do sa vykoná príkaz a otestuje sa hodnota podmienkového výrazu. Ak je true, cyklus sa bude opakovať, ak false, program pokračuje ďalším príkazom za cyklom do. Na rozdiel od cyklu while sa telo cyklu do vykoná vždy aspoň raz. Na predčasné opustenie tela cyklu môžeme použiť už spomínaný príkaz break.

Príklad cyklu do:

double d;
do {
  d = Math.random();
}
while (d >= 0.1);

Knižničná metóda Math.random() vracia náhodné číslo z intervalu <0; 1>. Cyklus sa teda bude opakovať, kým táto metóda nevygeneruje číslo menšie ako 0,1. Výsledkom bude náhodné oneskorenie programu (na súčasných počítačoch, samozrejme, neveľmi badateľné).

Dokončenie nabudúce

V budúcom pokračovaní tému príkazov uzavrieme univerzálnym príkazom cyklu for a pomocnými príkazmi break a continue. Prajem vám pekný začiatok roka a o mesiac dovidenia.

Príkaz cyklu for

Tretí príkaz cyklu, príkaz for, je značne univerzálny. Syntax má trošku zložitejšiu:

for ( init ; podmienka ; iterácia )
    príkaz

Všimnime si podrobnejšie obsah zátvorky. Skladá sa z troch častí oddelených bodkočiarkou. Prvá časť, nazvaná init, predstavuje jeden alebo viacero výrazových príkazov (ak ich je viac, oddelíme ich čiarkou). Táto časť sa vykoná pred začiatkom cyklu for – môžeme povedať, že to je inicializačná časť. Dávame do nej obyčajne inicializáciu riadiacich premenných cyklu.

Druhá časť, výraz podmienka, má podobný význam ako v cykle while. Teda telo cyklu for sa bude vykonávať dovtedy, kým bude táto podmienka splnená. Len čo sa stane podmienka nepravdivou, cyklus sa končí. Podmienkový výraz sa vyhodnocuje pred telom cyklu.

Tretia časť, označená ako iterácia, obsahuje výrazy, ktoré sa majú vykonať po každom prechode cyklom. Obyčajne sa tu podľa potrieb menia riadiace premenné. Telo cyklu je tvorené príkazom, ktorý opätovne môže byť aj zložený.

Použitie príkazu for si ukážeme na úseku programu, ktorý spočíta prvých N prirodzených čísel, kde N je nejaké vopred známe číslo, uložené v premennej N:

int N = 100;
int i, sum = 0;
for (i = 1; i <= N; i++)
  sum += i;
System.out.println(sum);

Spočítavané čísla z intervalu <1; 100> uchovávame v premennej i. Táto premenná je tzv. riadiacou premennou cyklu, čo sa dá preložiť aj tak, že obsah premennej i sa vhodne mení pri každom prechode telom cyklu. Inicializačná časť príkazu for, t. j. príkaz i = 1, nastaví hodnotu premennej i na prvú spočítavanú hodnotu, teda na jednotku. Podmienka cyklu znie: i <= N. Cyklus sa teda bude opakovať dovtedy, kým premenná i nepresiahne koncovú hodnotu N. V tele cyklu vykonávame triviálnu operáciu – pripočítanie aktuálnej hodnoty i k premennej sum, kde uchovávame priebežný súčet. Túto premennú nesmieme zabudnúť na začiatku vynulovať. Konečne pravidelné zvyšovanie hodnoty i o jednu zabezpečí tretí výraz, i++.

Nikde nie je napísané, že riadiacu premennú cyklu musíme v tele cyklu použiť. Keby sme chceli vypísať desaťkrát hoci reťazec „Java pod lupou“ (síce neviem načo, ale ako príklad to postačí), napíšeme cyklus:

for (int i = 0; i < 10; i++)
  System.out.println("Java pod lupou");

Pozorný čitateľ si isto všimne, že v inicializačnej časti cyklu sa nachádza deklaračný príkaz int i = 0. To je dovolené, ale pozor, takto deklarovaná premenná i je lokálna pre daný cyklus a po jeho skončení zaniká. Okrem toho nesmieme v inicializácii kombinovať deklaračné a výrazové príkazy. Inak by totiž mohlo dôjsť k dvojznačnosti, napr. pri takomto cykle:

for (int i = 0, j = 10; ... )

kde sú v inicializačnej časti dva príkazy, by nebolo jasné, či druhý príkaz j = 10 priraďuje hodnotu 10 existujúcej premennej j alebo deklaruje novú premennú j typu int a nastavuje ju na hodnotu 10. Z tohto dôvodu platí pravidlo, že ak je prvý príkaz deklaračný, za deklaračné sa považujú aj ostatné.

Riadiacu premennú cyklu nemusíme nevyhnutne pri každom prechode cyklom inkrementovať. Dajme tomu, že potrebujeme vypísať mocniny dvojky od 20 po 210. Nič ľahšie:

for (int i = 1; i <= 1024; i *= 2)
  System.out.println(i);

Premenná i sa po každej iterácii cyklu zdvojnásobí pomocou výrazu i *= 2.

Ak sa zamyslíme nad spôsobom vykonávania cyklu for, dôjdeme k záveru, že ho môžeme teoreticky prepísať takýmto spôsobom:

init ;
while ( podmienka )
{
    príkaz ;
    iterácia ;
}

Tento prepis platí okrem jednej malej výnimky, ktorú si uvedieme v ďalšom odseku. K príkazu for zostáva už len dodať, že ak chceme cyklus ukončiť predčasne, použijeme známy príkaz break.

Príkazy break a continue

Posledné dva príkazy, o ktorých bude reč, sú príkazy break a continue. Prvý z nich, break, sme už niekoľkokrát spomínali. Tento príkaz možno použiť buď vo vetviacom príkaze switch na okamžité vyskočenie von z bloku, alebo v príkazoch cyklu while, do a for na okamžité ukončenie cyklu. Inde jeho použitie vedie k chybe pri preklade.

Príkaz break však možno použiť aj s jedným argumentom, ktorým je tzv. návestie. O návestiach sme sa už zmienili v súvislosti s príkazom switch. V Jave však môže byť každý zložený príkaz, resp. každý z príkazov switch, while, do, for, ktoré obsahujú zložený príkaz, označený pomocou návestia. Návestím je obyčajný reťazec znakov (platia rovnaké pravidlá ako pre názvy premenných), ukončený dvojbodkou, ktorý umiestnime pred príslušný zložený príkaz. Výskyt príkazu break s návestím potom spôsobí okamžité vyskočenie zo zloženého príkazu, ktorý je týmto návestím označený. Je zrejmé, že sa tento break musí v danom zloženom príkaze nachádzať.

Typicky sa príkaz break s návestím používa na vyskočenie z vnoreného cyklu, čo sa v C++ s obľubou robí pomocou príkazu goto. Tento azda najpolemizovanejší príkaz nepodmieneného skoku v Jave totiž nenájdeme. Ukážme si príklad:

outer:
for (int i = 0; i < 10; i++)
{
  for (int j = 0; j < 10; j++)
  {
    if (i == j)
      break;
    if (i == 8)
      break outer;
    System.out.print(i + "–" + j + " ");
  }
  System.out.println("");
}

V príklade máme dva vnorené cykly, pomocou ktorých prechádzame pomyselnú súradnicovú mriežku, súradnice máme v premenných i a j. V každom prechode vnútorným cyklom vypíšeme súradnice aktuálneho bodu mriežky na obrazovku. V prípade, že sa nachádzame na diagonále, kde sú obe súradnice rovnaké (i == j), tento a nasledujúce body na aktuálnom riadku „preskočíme“. Okrem toho, keď sa dostaneme na predposledný riadok, pre ktorý bude v i hodnota 8, vyskočíme pomocou break outer z celého cyklu, a teda body na riadkoch so súradnicami 8 a 9 vôbec nevypíšeme. Všetko bude oveľa jasnejšie po spustení programu.

Druhý príkaz, continue, sa používa iba v príkazoch cyklu, teda while, do a for. Pokiaľ ho použijeme bez návestia, spôsobí okamžité ukončenie práve prebiehajúcej iterácie cyklu a skok na pomyselný začiatok cyklu, čo spôsobí nové vyhodnotenie cyklovacej podmienky a podľa jej výsledku prípadné pokračovanie či nepokračovanie v cykle. V príkaze for sa pred týmto opätovným testovaním podmienky ešte vykonajú všetky výrazy tretej, iteračnej časti (pozri vyššie). To je ten spomínaný malý rozdiel medzi for a jeho náhradou pomocou while.

Aj príkaz continue možno použiť s návestím, význam je analogický: ukončí sa práve prebiehajúca iterácia toho cyklu, ku ktorému dané návestie patrí. Modifikujme predchádzajúci príklad tak, že príkazy break nahradíme príkazmi continue:

outer:
for (int i = 0; i < 10; i++)
{
  for (int j = 0; j < 10; j++)
  {
    if (i == j)
      continue;
    if (i == 8)
      continue outer;
    System.out.print(i + "–" + j + " ");
  }
  System.out.println("");
}

Tentoraz sa z výpisu vynechajú iba body ležiace na diagonále a celý riadok so súradnicou 8.

Prázdny príkaz

Príkazov v Jave nájdeme ešte o niečo viac, ale tie sa vzťahujú buď na výnimky (try, finally, catch, throw), alebo na synchronizáciu v multithreadovom prostredí (synchronized), takže si o nich povieme až neskôr. Na záver sa patrí spomenúť tzv. prázdny príkaz, ktorým je jednoducho „nič“ nasledované bodkočiarkou:

;

Prázdny príkaz možno použiť napríklad ako telo cyklu for, ktorého celú náplň sme vyjadrili buď v podmienkovom, alebo v iteračnom výraze.

Zahráme sa na kombajny

A v budúcom pokračovaní seriálu sa vrhneme na polia a prácu s nimi. Prajem vám pekný začiatok roka a o mesiac dovidenia.

Operátor Význam Asociativita
+ + inkrementácia (postfix)
– –  dekrementácia (postfix)  
+ + inkrementácia (prefix) P ® Ľ
– – dekrementácia (prefix)  
+ unárne plus  
unárne mínus  
~ bitová negácia  
! logická negácia  
(typ) pretypovanie  
* násobenie Ľ ® P
/ delenie  
% zvyšok po delení  
+ sčítanie  Ľ ® P
odčítanie  
<< bitový posun vľavo Ľ ® P
>> bitový posun vpravo so znam.  
>>> bitový posun vpravo bez znam.  
< menší Ľ ® P
<= menší alebo rovný  
> väčší  
>= väčší alebo rovný  
instanceof objekt daného typu  
= = rovný Ľ ® P
! = nerovný  
& bitový logický súčin Ľ ® P
I bitový logický súčet  
^ bitový exkluzívny logický súčet  
& & logický súčin Ľ ® P
I I logický súčet  
? : podmienené vyhodnotenie P ® Ľ
= priradenie P ® Ľ
op = zložené priradenie  

Tab.č.1 - Priorita operátorov

 

 


Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

Ako na to

Ako zbaviť fotky hmly

08.12.2016 11:59

Hmla alebo dym sú často veľmi kreatívne nástroje. No všetkého veľa škodí. Fotka potom stráca kontrast a v podstate na nej nič nevidieť. Hmlu môžete neraz následnými úpravami odstrániť alebo zredukovať ...

Ako na to

Užitočné SW nástroje

08.12.2016 11:53

AllDup v4.0.3 Určenie: program na vyhľadávanie a odstraňovanie duplicitných súborov Vlastnosti: duplicitné súbory sa vyhľadávajú len na zvolených diskových jednotkách alebo len v rámci vybraných ...

Ako na to

Fotografovanie s bleskom

08.12.2016 11:47

Ak máte moderný fotoaparát so vstavaným alebo externým bleskom, zdá sa vám téma článku triviálna. Jednoducho nastavíte vhodný režim, vyberiete najlepšiu kompozíciu záberu, exponujete a o zvyšok sa už ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá