Java (4) - Základní operace

V tomto dílu seriálu si ukážeme několik věcí, které budou později naším každodenním chlebem. Nejprve zakončíme problematiku proměnných tím, že si ukážeme, kde jsou námi definované proměnné platné a jakým způsobem se dají proměnné přetypovat (změnit typ hodnoty – například z desetinného čísla na celé). Posléze si předvedeme, jaké základní operace nad daty můžeme v Javě vykonávat.

Platnost proměnných

Každá proměnná je platná (a nesmí být opětovně deklarována) v rámci bloku. Blok je taková část kódu, která je uvnitř jednoho páru složených závorek. V případě vnořených bloků proměnná platí i ve všech vnitřních blocích. Ovšem v okamžiku, kdy opustíme blok, kde byla proměnná deklarována, ji již nesmíme použít (protože neexistuje).

V následujícím příkladu budeme používat pro bloky pouze osamocené znaky složených závorek. Toto je v Javě poměrně neobvyklé, protože se bloky téměř vždy vážou k cyklům, podmínkám, definicím metod a tříd, ale tato problematika nás teprve čeká.

/**
 * Priklad na bloky
 * 
 * V dalsich prikladech budeme pouze vymenovat obsah bloku metody, vse ostatni
 * zustane stejne. Pokud byste si chteli tyto priklady zkusit, tak mejte na
 * pameti, ze tento kod musite umistit do souboru 'Main.java' do vychoziho adresare
 * (v netbeans oznaceno jako 'Source Packages'). Kod pak spustite klikem praveho
 * tlacitka do kodu a volby 'Run File', pripadne analogicke volby v levem menu 
 * (stromu struktury projektu).
 * 
 * Duvody techto konstrukci budou vysvetleny v dalsich dilech
 * 
 * @author Pavel Micka
 */
public class Main { //blok tridy

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) { //blok dany metodou
        int a = 5;
        System.out.println(a); //5
        { //vnitrni blok
            System.out.println(a); //promenna je i ve vnitrnim bloku platna
            int b = 10;
            System.out.println(b); //10
        } //konec vnitrniho bloku

        System.out.println(b); //toto je chyba, zde promenna jiz neexistuje
    } //konec bloku metody
}// konec bloku tridy

Přetypování

V určitých situacích potřebujeme změnit typ proměnné, což může nastat tehdy, chceme-li volat operaci, která přijímá celá čísla (int), ale naše proměnná je typu double. Některé konverze typu proběhnou automaticky (stačí přiřadit hodnotu do nového typu), u jiných o ně musíme explicitně zažádat. Do první skupiny patří ty změny, u nichž zaručeně nedojde k žádné ztrátě dat (byteint, int je schopen pojmout více dat než byte), do té druhé ty změny, kde je ztráta dat možná (doubleint, double má jak větší rozsah, tak obsahuje desetinné pozice).

V případě explicitní konverze o tuto změnu zažádáme tím, že před proměnnou napíšeme do závorek typ, který si přejeme.

        byte b = 5;
        int i = b; //automaticka konverze, int ma vetsi rozsah
        
        long l = 150000L;
        i = (int) l; //hrozi preteceni, musime sami o zmenu zazadat

        double d = 1.5;
        i = (int) d; //hrozi ztrata presnosti, o zmenu musime zazadat
        System.out.println(i); //vypise 1

        d = i; //v poradku, double ma vetsi rozsah nez integer

Pokud si seřadíme jednotlivé typy do řady

byte \\rightarrow short \\rightarrow int \\rightarrow long \\rightarrow float \\rightarrow double

tak konverze proběhne vždy automaticky tehdy, je-li výchozí typ nalevo od cílového, v opačném případě musíme o konverzi zažádat (všimněte si, že typ boolean nelze přetypovat).

Operace

Operace přiřazení

Operace přiřazení do proměnné (operátor =) pro nás není nic nového, už ji totiž nějakou dobu používáme.

Aritmetické operátory

Pro aritmetické výpočty můžeme použít operátory +, -, *, /. Všechny tyto operátory mají očekávatelnou prioritu (tj. nejprve násobíme a dělíme, teprve až poté sčítáme a odčítáme) a lze při jejich použití využít uzávorkování.

Je důležité vědět, že pokud má některý operand typ double, tak je i druhý operand před provedením operace převeden na double, obdobně na float a long.

Velmi oblíbeným chytákem aritmetických operací je následující kód:

        int a = 1;
        int b = 1;
        double c = (a + b)/4;
        System.out.println(c); //0.0

Jak je možné, že je výsledek 0.0 a ne 0.5? Je třeba si uvědomit pořadí, ve kterém dochází k vyhodnocení. Nejprve jsou sečteny dvě celá čísla, výsledek je celé číslo 2. Nyní dojde k dělení dvou celých čísel 2/4, což je ovšem celočíselně 0. Teprve v tento okamžik dojde k automatickému přetypování na double. Pokud tomuto chování chceme zabránit, tak musíme explicitně libovolný operand přetypovat na double a automatická konverze se dle předchozí poučky postará o zbytek práce.

        int a = 1;
        int b = 1;
        double c = ((double) a + b)/4;
        System.out.println(c); //0.5

Implicitní typ

Protože je při celočíselných výpočtech vždy implicitně používán typ int, tak je zapotřebí výsledek před přiřazením do kratší proměnné (short, byte) vždy přetypovat.

Operátory op=

Velmi často se v programování dosatneme do situace, kdy je zapotřebí nad danou proměnnou vykonat aritmetickou operaci a výsledek opět uložit do původní proměnné. V kódu tím dochází k lehké redundanci. Z tohoto důvodu existují pro zkrácení zápisu operátory op= (kde op nahrazujeme +, -, *, /).

        int a = 5;
        a = a + 3;
        System.out.println(a); //8

        int a2 = 5; 
        a2 += 3; //alternativni zapis predchoziho (a2 = a2 + 3)
        System.out.println(a2); //8

        a2 /= 4; //deleni (a2 = a2 / 4;)
        System.out.println(a2); //2

        a2 -= 1; //odcitani (a2 = a2 - 1;)
        System.out.println(a2); //1

        a2 *= 3; //nasobeni (a2 = a2 * 3)
        System.out.println(a2); //3

Inkrementace a dekrementace

Pro zvyšování (inkrementace) a snižování (dekrementace) hodnoty proměnné o 1 existuje zvláštní konstrukt (++ a -- zapsané buď před nebo za název proměnné). Tímto se jednak ušetří místo, ale hlavně je možné tuto operaci použít uvnitř jiného aritmeticného výrazu.

Pokud zapíšeme znaménka před proměnnou hovoříme o preinkrementaci (predekrementaci) – při vyhodnocování výrazu se nejprve provede změna hodnoty proměnné a až posléze se vyhodnotí výraz. Při opačném zápisu (promenna++) – postinrekementaci (postdekrementaci) – se nejprve vyhodnotí výraz a až posléze dojde k přiřazení nové hodnoty.

        int i = 1;
        i++; //i = 2
        ++i; //i = 3
        i--; //i = 2
        --i; //i = 1

        int c = i++ * 3; //c = 3, i = 2 (nejprve c = i * 3, pote i = i + 1)
        int d = --i * 3; //d = 3, i = 1 (neprve i = i - 1, pote d = i * 3)  

Operátor modulo

Pro práci s celými čísly existuje také operátor modulo (zbytek po celočíselném dělení). Každé celé číslo lze vyjádřit jako

a = b \\cdot k + c

kde c je zbytek po vydělení čísla a číslem b.

Příklad

Mějme například krabičku nábojů, ve které je 50 kusů munice. Dále víme, že zásobník zbraně má kapacitu 9 nábojů. Ptáme se, kolik kusů nám zůstane v krabičce po vystřílení celých zásobníků.

pocetKusu = 9*5 + 5

alternativně bychom napsali, že

50/9 = 5\\;(zbytek\\;5)

V Javě pomocí operátoru modulo (%) napíšeme:

        int munice = 50;
        int kapacitaZasobniku = 9;
        int vysledek = munice % kapacitaZasobniku;
        System.out.println(vysledek); //5

Operace se znaky

Protože jsou znaky reprezentovány jako čísla, tak s nimi můžeme také tak zacházet (a občas se to také hodí).

        char ch = 'A';
        ch++;
        System.out.println(ch); //B

        ch = (char) (ch + 2);
        System.out.println(ch); //D

Binární operace

Pro úplnost operací si ještě uvedeme binární operace. Tyto neoperují s čísly v desítkové soustavě, jak jsme zvyklí, ale nad jednotlivými bity jejich dvojkového zápisu. Pro začátečníka není jejich přesná znalost důležitá. Důležitá je především znalost jejich existence, protože se čas od času hodí zejména tehdy zabrousí-li člověk do něčeho nízkoúrovňovějšího.

OperátorVysvětlivka
&Binární konjunkce
|Binární disjunkce
^Nonekvivalence (XOR)
~Bitový doplněk (otočí všechny bity)
<<Posuv vlevo, zprava doplňováno nulami
>>Posuv pravo, znaménkový bit je kopírován
>>>Posuv pravo, zleva doplňováno nulami

Třída Math

Třída Math je první třídou na kterou jsme v tomto seriálu narazili. V tomto díle ještě nebudeme rozebírat, co to vlastně třída je, ale spokojíme se pouze s důsledkem, že nad ní můžeme volat operace. V případě třídy Math se jedná o operace matematického charakteru, které nám neposkytují zde uvedené operátory.

Pokud používáte vývojové prostředí, pak stačí napsat Math. a po napsání oné tečky vám IDE samo nabídne operace, kterých je tato třída schopná, informuje vás o parametrech, které operace vyžaduje a v neposlední řadě řekne, jaký návratový typ máte očekávat.

Odbočka: JavaDoc

Další možností, kde tyto (a mnohé jiné) informace načerpat, je dokumentace Javy (JavaDoc), ve které jsou informace o všech třídách a operacích (je generovaná z dokumentačních komentářů, o kterých jsme hovořili v druhém dílu). Pro začátečníka se může zdát JavaDoc matoucí a nevhodně udělaný (také já jsem si to myslel), ale je to pouze otázkou zvyku. Každý programátor potvrdí, že dobře zpracovaný JavaDoc je jednou z nejvýznamnějších předností Javy.

Volání operací

Po této odbočce si ukážeme několik volání operací nad třídou Math. Nesmíme při předávání parametrů zapomenout na to, že některé operace přetypování se provedou automaticky a jiné si musíme vyžádat. Technickým dovětkem je, že pokud operace vyžaduje více parametrů, tak je oddělujeme čárkou (a před jména proměnných nedáváme dle konvence znak $ ani _ (tato poznámka slouží především pro programátory přecházející z jazyka PHP)).

        int a = 2;
        double b = Math.pow(a, 3); //2^3 = 8
        System.out.println(b);

        double e = Math.E; //Eulerovo cislo (konstanta ve tride Math)
        System.out.println(e);

        int i = (int) Math.sqrt(4); //druha odmocnina ze 4, vraci double, musime pretypovat na int
        System.out.println(i);

Literatura

  • HORTON, Ivor. Java 5. Praha : Neocortex spol s.r.o., 2005. 1443 s. ISBN 80-86330-12-5.







Doporučujeme