Child pages
  • 3. Egy kis szárazanyag

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Helyes azonosítók:

Code Block
titleHelyes azonosítók
sor  
Sör  
sÖr  
ser  
_sör  
sör2  
egy_sör  
$sör  

Hibás azonosítók:

Code Block
titleHibás azonosítók
2sör
egy sör
kis-sör
super sör
sör:
Sört!

A Java nyelv kulcsszavait nem használhatjuk azonosítóként, ezek a következők:

Code Block
titleFoglalt kulcsszavak
abstract        boolean         break           byte            case              
catch           char            class           const           continue  
default         do              double          else            enum  
extends         false           final           finally         float  
for             goto            if              implements      import  
instanceof      int             interface       long            native  
new             package         private         protected       public  
return          short           static          super           switch  
synchronized    this            throw           throws          transient  
true            try             void            volatile        while  

...

Vegyük elő a NetBeans környezetben a már létrehozott Kocsma projektet, és keressük meg benne a kocsma csomagot, majd azon belül a Mainosztályt, majd az alábbi programot írjuk bele:

Code Block
languagejava
titleMain.java
linenumberstrue
package kocsma;  
  
public class Main  
{  
  
  public static void main(String[] args)  
  {  
    // Ide fogjuk írni az alábbi programrészleteket  
  }  
}

A // kezdetű sor helyére kell írni az alábbiakban megemlített programrészleteket, majd az F6 gomb megnyomásával futtatni tudjul a (helyesen megírt) programot.

...

A boolean típust akkor használjuk, ha egy eldönthető kérdésekre adott válasz csak igen/igaz vagy nem/hamis lehet, a boolean ugyanis nem képes a talán vagy a nem tudom válaszokat értelmezni. A C/C++ nyelvektől eltérően egy boolean típusú változó értéke csak a true vagy a falseértéket veheti fel, a számszerűen jelzett értékeket nem képes értelmezni.

...

Code Block
languagejava
titleJava
linenumberstrue
boolean igaz = true;
boolean hamis = false;
boolean válasz;
válasz = igaz;

Vannak olyan műveletek, amelyek természetszerűleg booleanértéket adnak eredményül:

...

...

Code Block
languagejava
titleJava
linenumberstrue
válasz = 9 < 3;
System.out.println(válasz);

...


válasz = 3 < 10;
System.out.println(válasz);

...

Az első esetben false (hamis) eredményt kapunk, hiszen a kilenc nem kisebb, mint a három; a második esetben az eredmény true (igaz), hiszen a három kisebb, mint a tíz.

A példában említett true és false literál, vagyis a nyelvbe épített és értékkel bíró fogalom. Láthatunk továbbá több deklarációt és értékadásokat is - ezekről később több szót ejtek.

...

A byte típust akkor célszerű használnunk, ha nulla közeli egész számokkal számolunk, hiszen értéktartománya mindössze a -128 és a 127 közötti számokra érvényes:

...

Code Block
languagejava
titleJava
linenumberstrue
byte szám;
szám = 12;
szám = -12;
szám = -128;
szám = 127;

A példában láthatunk egy deklarációt és négy értékadást, ahol a számnevű változónak adunk más-más értéket, s itt már szám literálokat használunk. Fontos tudni, hogy a primitív típusok képesek a csöndes túlcsordulásra:

...

Code Block
languagejava
titleJava
linenumberstrue
byte szám;
szám = 127;
szám++;
System.out.println(szám);

...

A rövidke programrészlet eredménye -128 lesz, nem pedig a matematikailag várható 128. Ennek oka, hogy a változó túlcsordult, túllépte az értékkészlete egyik határát, és ezért értékül az értékkészletének másik határértékét veszi fel. Nagyon oda kell figyelnünk erre a tulajdonságra, mivel a programunk mindezt csöndben teszi, legtöbbször igen keserves és hosszú munkával tudjuk csak megkeresni a hiba okát.

...

A többi nyelvhez hasonlóan a char egy öszvér adattípus, alapvetően számokat tartalmaz, de ha az értékét kiírjuk, akkor karaktereket kapunk eredményül. A Java nyelv úttörő volt a tekintetben, hogy a char típus alapja nem a 8 bites byte, hanem az 32 bites integer, hiszen a Java nem ASCII alapú, hanem UTF-8 az alapértelmezett karakter kódolása, mivel ismert világ összes karaktere nem fér el 8 biten.
Nézzük meg ezt a gyakorlatban:

...

Code Block
languagejava
titleJava
linenumberstrue
char betű = 64;
System.out.print(betű);

...


betű = '\n';
System.out.print(betű);

...


betű = 'a';
System.out.print(betű);

...


betű = '\t';
System.out.print(betű);

...


betű = '\\

...

';
System.out.print(betű);

...


betű = '\'';
System.out.print(betű);

...


betű = '"';
System.out.print(betű);

...


betű = '\070

...

';
System.out.print(betű);

...


betű = '\u003F';
System.out.print(betű);

...

Nézzük meg ezt a gyakorlatban: 

Eredményül az alábbi (ránézésre értelmetlen) karakter halmazt kapjuk:

  1. @  
  2. a       \’"8?  

Lássuk a dekódolást:

Code Block
titleEredmény
@
a       \'"8?

Lássuk a dekódolást:

  • A @ karakter UTF-8 (és ASCII) kódja a 64 szám, ezért a @ az első kiírt karakter.

  • A \n karakter az

    újsor

    új sor kódja, ez nem látható karakter, viszont a (szintén nem látható) kurzort a következő sorba teszi.

  • A következő sor elején kiírt a betű egyértelmű kell legyen, hiszen ezt adtuk értékül a betű nevű változónak.
  • A negyedik kiírt karakter ismét egy nem látható karakter (\t), amely egy tabulátor pozícióval jobbra mozgatja a kurzort.
  • Biztos felmerült, hogy a \ karaktert hogy tudjuk kiírni: egyszerűen a \\ karaktert kell használnunk. A \ (backslash vagy visszaper vissza-per jel) egy speciális karakter, amely az őt követő karakternek is speciális jelentést ad.
  • A szimpla idézőjel kiírásához a \’ karaktereket kell használnunk.
  • A dupla idézőjel kiírható, ha szimpla idézőjelek között van.
  • A \070 kódolás oktális formátumú számot hordoz, a 070 oktális szám azonos az 56 decimális számmal, amely az UTF-8 kódrendszerben a ’8’ karakternek felel meg.
  • A \u003F kódolás hexadecimális formátumú számot jelent, a 003F szám azonos a 63 decimális számmal, amelynek a ’?’ karakter felel meg.

Mint láthatjuk, eléggé változatos módon tudunk karaktereket megadni, azonban a char kettős természetét az is meghatározza, hogy tudunk vele műveleteket végezni:

...

Code Block
languagejava
titleJava
linenumberstrue
char betű = 64;
betű++;

...


System.out.print(betű);

...


betű +=

...

 0;

...


System.out.print(betű);

...


betű +=

...

 '0

...

';

...


System.out.print(betű);

...

Az eredmény az AAq karaktersorozat lesz, hiszen a 64 az ’@’ karaktert kódolja, amihez ha hozzáadunk egyet, akkor ’A’ betű lesz, amit a 65 kódol. Ha ehhez hozzáadunk nullát (0), akkor az eredmény továbbra is 65 marad, de ha karakteresen adunk hozzá nullát (’0’), amelynek a számszerű értéke 48, akkor az eredmény 113 lesz (mivel 65+48 az 113), amely szám a ’q’ karaktert kódolja.

A karakter literálok két szimpla idézőjel közötti karakterek. Általában egy karakter, de ha az első karakter visszaper jel (\), akkor több karakter is lehet a két idézőjel között. Érdemes megtanulni a speciális karakter literálok használatát, mivel használatuk sok esetben szükséges a szövegfeldolgozáshoz.

...

A valós számok használata akkor kerül előtérbe, amikor olyan számolásokat végzünk, amelyek nem végezhetők el könnyedén egész számokon. A valós számok használata lassíthatja a program működését, mivel ezek kezelése néhány processzoron nincsen kellően gyorsítva, ezért csak akkor használjunk valós számokat, amikor feltétlenül szükséges. Nézzük a float típus használatát:

...

Code Block
languagejava
titleJava
linenumberstrue
float szám = 0;
System.out.println(szám);

...


szám = 1/3;

...


System.out.println(szám);

...


szám = 1f/3f;

...


System.out.println(szám);

...


szám = -1*0f;

...


System.out.println(szám);

...


System.out.println(

...

szám ==

...

 0f);

...


szám = 100000000000000000000000000000000000000f;
System.out.println(szám);

...


szám = 1.0E38f;

...


System.out.println(szám);

...

Eredményül nem pont azt kapjuk, amit várnánk:

...

Code Block
titleEredmény
0.

...

0
0.

...

0
0.

...

33333334
-0.

...

0
true
1.

...

0E38
1.

...

0E38

Az első 0.0 érthető, hiszen ezt adtuk értékül a szám nevű változónak. A második 0.0 azonban elgondolkodtató: az egyharmad értéke nem szabadna nulla legyen. Ennek oka az, hogy a Java nyelv két egész számot lát: elosztja az egyet hárommal: hányszor van meg egyben a három? Ugye egyszer sem, ezért kaptunk eredményül nullát. A problémát úgy tudjuk kikerülni, hogy a szám mögé írt f betűvel mondjuk meg, hogy ez a szám nem egész szám, hanem float. A 1f/3f művelet eredménye már 0.33333334, mivel a float csak nyolc számjegy pontosságú, azt követően nincs több értékes számjegy. A -0.0 eredmény a számábrázolás érdekessége, ugyanis van plusz nulla és mínusz nulla is, és ahogy a következő sorban látjuk: a kettő egyenlő egymással. A nagy számokat megadhatjuk a számjegyekkel is, de rövidebb a normálforma: 1.0·1038, amely a program forrásában 1.0E38 formán kódolódik.

A double használata annyiban tér el a float használatától, hogy az f karakter helyett d karaktert kell használnunk a literál megadásakor (amelyet akár el is hagyhatunk, hiszen a doubletípus az alapértelmezett lebegőpontos típus).

...

A boolean típushoz tartozó burkoló osztály, amelynek leginkább azt a tudását használjuk fel, hogy szövegből képes önmagát legyártani:

...

Code Block
languagejava
titleJava
linenumberstrue
Boolean válasz= new Boolean("tRuE");

...


System.out.println(válasz);

...

A paraméterben átadott szöveg hatására a válasz nevű változó értéke true lesz. Akkor és csak akkor lesz az eredmény true, ha az átadott szöveg karakterhelyesen "true", azonban a kis és nagybetű nincs megkülönböztetve (case insensitive). Ugyanígy használható a valueOf metódus is, amely egy picit gyorsabb is:

...

Code Block
languagejava
titleJava
linenumberstrue
Boolean válasz= Boolean.valueOf("tRuE");

...


System.out.println(válasz);

...

Az eredmény jelen esetben is truelesz. Az 1.5 Java verziótól használhatjuk az automatikus konverziót is:

...

Code Block
languagejava
titleJava
linenumberstrue
Boolean válasz = true;
boolean érték = válasz;

Az 1.5 verzió előtt ezt csak hosszabban tudtuk leírni:

...

Code Block
languagejava
titleJava
linenumberstrue
Boolean válasz = Boolean.valueOf(true);

...


boolean érték = válasz.booleanValue();

...

A Byte, a Short, az Integer, a Long, a Float és a Double osztály

Ezen osztályok mind a Number osztályból származnak, amely a számokat kezelő osztályok őse. A Numberőstől örökölt kényszer szerint van hat metódusuk, amely a burkoló osztály által hordozott szám primitív típusát adja vissza:

...

Code Block
languagejava
titleJava
linenumberstrue
Double szám = new Double(3.141592653589793);

...


System.out.println(szám.doubleValue());

...


System.out.println(szám.floatValue());

...


System.out.println(szám.longValue());

...


System.out.println(szám.intValue());

...


System.out.println(szám.shortValue());

...


System.out.println(szám.byteValue());

...



szám = Double.parseDouble("2.718281828459045");

...


System.out.println(szám.doubleValue());

...


System.out.println(szám.floatValue());

...


System.out.println(szám.longValue());

...


System.out.println(szám.intValue());

...


System.out.println(szám.shortValue());

...


System.out.println(szám.byteValue());

...

A fenti programrészlet eredménye:

...

Code Block
titleEredmény
3.

...

141592653589793
3.1415927
3
3
3
3
2.718281828459045
2.7182817
2
2
2
2

Mint látható, a valós számot hordozó Double esetén az egész számra való alakítás is megtörténik, ha egész típusú primitív típust kérek el, azonban az átalakítás során csonkolás történik (eltűnik a tizedespont mögötti számsor), nem pedig kerekítés!

Ezek az osztályok már több műveletet is lehetővé tesznek, nekünk azonban egyelőre elég a valueOfismerete, amely szöveges formából alakít számmá, akárcsak a Boolean esetén:

...

Code Block
languagejava
titleJava
linenumberstrue
szám = Double.valueOf("-2");

...


System.out.println(szám);

...


szám = Double.valueOf("-2.2E3");

...


System.out.println(szám);

...


szám = Double.valueOf("-2.2E3000");

...


System.out.println(szám);

...


System.out.println(szám.isInfinite());

...

Ennek eredménye:

...

Code Block
titleEredmény
-2.

...

0
-2200.

...

0
-Infinity
true

Fontos, hogy a valós típusoknak lehet negatív és pozitív végtelen értéke - ha túl nagy számot szeretnénk szöveges formából átalakítani vagy a művelet eredménye túl nagy, ezt lekérdezhetjük az isInfinite metódussal.

...

A karakter ismét kilóg a sorból, hiszen a célja alapvetően nem a számolás, hanem karakterek ábrázolása.

...

Code Block
languagejava
titleJava
linenumberstrue
Character karakter = new Character('a');
System.out.println(karakter);

...


System.out.println(Character.isDigit(

...

'0

...

'));

...


System.out.println(Character.isDigit(

...

'a'));

...


System.out.println(Character.isWhitespace(

...

'\

...

t'));

...


System.out.println(Character.isWhitespace(

...

'a'));

...


System.out.println(Character.isISOControl(

...

'\

...

t'));

...


System.out.println(Character.isISOControl(

...

'a'));

...


System.out.println(Character.toLowerCase(

...

'A'));

...


System.out.println(Character.toUpperCase(

...

'a'));

...

A futás eredménye:

...

Code Block
titleEredmény
a
true
false
true
false
true
false
a
A

A Character osztálynak van egy rakás statikus metódusa, amely a megadott karakterről döntést hoz. A példában rákérdeztünk párosával arra, hogy az átadott karakter szám-e, helykitöltő karakter-e, valamit ISO vezérlőkarakter-e. Az utolsó két metódus pedig konvertálta az átadott karaktert kis-, illetve nagybetűsre. Ezen túl sok egyéb metódust megtalálunk a Character osztályban (írásirány, tükörírás, stb.), ezeket nem részletezném.

...

  • TYPE, amely a primitív típust adja vissza
  • SIZE, amely a primitív típus által elfoglalt bitek számát adja vissza
  • MAX_VALUE, amely a legnagyobb ábrázolható értéket hordozza
  • MIN_VALUE, amely a legkisebb ábrázolható értéket hordozza, lebegőpontos típus esetén a legkisebb ábrázolható pozitív számot

Lássunk rá példát:

...

Code Block
languagejava
titleJava
linenumberstrue
System.out.println(Byte.TYPE);

...


System.out.println(Byte.MAX_VALUE);

...


System.out.println(Byte.MIN_VALUE);

...


System.out.println(Byte.SIZE);

...



System.out.println(Short.TYPE);

...


System.out.println(Short.MAX_VALUE);

...


System.out.println(Short.MIN_VALUE);

...


System.out.println(Short.SIZE);

...



System.out.println(Integer.TYPE);

...


System.out.println(Integer.MAX_VALUE);

...


System.out.println(Integer.MIN_VALUE);

...


System.out.println(Integer.SIZE);

...



System.out.println(Long.TYPE);

...


System.out.println(Long.MAX_VALUE);

...


System.out.println(Long.MIN_VALUE);

...


System.out.println(Long.SIZE);

...



System.out.println(Float.TYPE);

...


System.out.println(Float.MAX_VALUE);

...


System.out.println(Float.MIN_VALUE);

...


System.out.println(Float.SIZE);

...



System.out.println(Double.TYPE);

...


System.out.println(Double.MAX_VALUE);

...


System.out.println(Double.MIN_VALUE);

...


System.out.println(Double.SIZE);

...



System.out.println(Character.TYPE);

...


System.out.println(Character.MAX_VALUE);

...


System.out.println(Character.MIN_VALUE);

...


System.out.println(Character.SIZE);

...

Az eredményt mindenki nézze meg a saját gépén... :)

3.3. Operátorok

Mit sem ér egy üveg sör, ha nem tudunk vele semmit kezdeni.

A deklarált változóink nem érnek sokat, ha nem tudunk rajtuk műveleteket végezni. Műveletet csak és kizárólag primitív típusokon, illetve típusok között tudunk végezni, és a műveletet az operátor vagy az operátorok határozzák meg. Nem kell megijedni, egyszerűen arról van szó, hogy az összeadás műveletét a + jel, mint operátor határozza meg.

3.3.1. Értékadás

Eddigi programjaink során már találkoztunk az értékadás műveletével:

  1. int szám;  
  2. szám = 2;  

...

Code Block
languagejava
titleJava
linenumberstrue
int szám;
szám = 2;

Ezt úgy kell olvasnunk, hogy legyen egy int típusú és szám nevű változónk, majd a szám nevű változó értéke legyen egyenlő kettővel.

3.3.2. Egyszerű matematikai műveletek

A primitív típusú változóink szinte kivétel számokat tárolnak, ezért mindegyiken képesek vagyunk matematikai műveleteket végezni. Lássuk, miképp tudjuk a matematikai alapműveleteket Java nyelven elvégeztetni.

Előjelváltás

A legegyszerűbb operátor az előjelváltás:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 2;
szám = -szám;
System.out.println(szám);

...


szám = -szám;

...


System.out.println(szám);

...

Az előjelváltás a tipikus példája a prefix típusú operátornak, hiszen az operátort követi az operandus.

Összeadás

A négy alapvető matematikai művelet közül a leginkább használt művelet az összeadás, Java nyelvben is pontosan úgy működik, mintha papírra vetnénk:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám;
szám = 3 + 4;
szám = szám + 5;
szám = szám + 1;
System.out.println(szám);

...

A szám = 3 + 4 utasítás úgy olvasandó, hogy a szám változó értéke legyen egyenlő a három meg a négy értékével, vagyis a szám értéke hét lesz. A szám = szám + 5 utasítás már feltételez előző értéket a szám változóban (ami jelen esetben 7), s a jelentése annyi, hogy a szám változó értéke legyen egyenlő a szám változó előző értéke meg öt értékével, vagyis a szám változóban a 12 lesz eredményképpen. A következő utasítás hasonlóképpen értelmezhető, azt jelenti, hogy a számváltozó értékét megnöveljük egyel. A kiírt eredmény 13 lesz.

Kivonás

Azonos módon értelmezhető, mint az összeadás:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám;
szám = 3 - 4;
szám = szám - 5;
szám = szám - 1;
System.out.println(szám);

...

Az eredmény pedig -7 lesz.

Szorzás

A szorzás is úgy működik, mint az előző két művelet, csak a műveleti jel változik:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám;
szám = 3 * 4;
szám = szám * 5;
szám = szám * 1;
System.out.println(szám);

...

Az eredmény 60 lesz, ahogy az sejthető.

Osztás

Az osztás kilóg az előző három művelet közül, egy kicsit speciális a helyzete. Az egyik buktató - amiről már volt szó, hogy ha egész számok az operandusok, akkor egész osztás fog történni:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám;
szám = 30 / 4;
szám = szám / 5;
szám = szám / 1;
System.out.println(szám);

...

Normál esetben az eredmény másfél lenne, de az egész osztások miatt az 30/4 eredménye 7 lesz, ezt követően a 7/5 eredménye pedig 1, aztán az 1/1 természetesen 1. Ha a valós eredmény érdekel minket, akkor valós számokkal kell számolnunk:

...

...

Code Block
languagejava
titleJava
linenumberstrue
double szám;
szám = 30 / 4;
szám = szám / 5;
szám = szám / 1;
System.out.println(szám);

...

Az eredményül kapott 1.4 egy kissé gyanús lehet matematikában jártas egyéneknek. A probléma gyökere ott van, hogy a 30/4 még mindig egész osztás marad, attól függetlenül, hogy a szám változó típusa valós. Ennek oka, hogy a Java

...

nyelvben – és más nyelvekben

...

is – az egyenlőség jel jobb oldalán kezdődik a kifejezés végrehajtása, mégpedig balról jobbra. Mivel a 30 egy egész szám és a 4 is egy egész szám, ezért a két számon értelmezett osztás művelet egész osztás lesz: a szám változóba eredményül 7 kerül. A következő sorban az utasítás szerint a szám változó értékét el kell osztani öttel. Itt a szám változó típusa okán már valós osztás lesz, és a 7/5 eredménye az 1.4. A hibát úgy tudjuk kikerülni, hogy jelezzük a 30 és a 4 valós voltát (illetve a többi szám valós voltát is):

...

...

Code Block
languagejava
titleJava
linenumberstrue
double szám;
szám = 30.0 / 4.0;
szám = szám / 5.0;
szám = szám / 1.0;
System.out.println(szám);

...

Eredményül most már másfelet fogunk kapni. A nullával való osztásban is vannak különbségek. Ha valós számot osztunk nullával, akkor eredményül végtelent(Infinity) kapunk:

...

...

Code Block
languagejava
titleJava
linenumberstrue
double szám;
szám = 30.0 / 4.0;
szám = szám / 5.0;
szám = szám / 0;
System.out.println(szám);

...

Ellenben egész szám esetén a program futása megszakad:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám;
szám = 30 / 4;
szám = szám / 5;
szám = szám / 0;
System.out.println(szám);

...

Egy kivétel (Exception) keletkezik, hogy nullával próbáltunk meg osztani:

...

Code Block
titleEredmény
Exception in thread "main"

...

 java.lang.ArithmeticException:

...

 / by zero  
        at kocsma.Main.main(Main.java:11)

...

A kivételekről majd később, annyit jegyezzünk meg, hogy ha egész számokkal osztunk, akkor annak súlyos következményei lehetnek.

Maradékképzés

Az egész osztás párja a maradékképzés, amikor nem arra vagyunk kíváncsiak az osztás során, hogy mennyi az eredmény, hanem arra, hogy mennyi a maradék:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám;
szám = 30 % 4;
System.out.println(szám);

...

Az eredményül kapott 2 nem okozhat meglepetést, ha vissza tudunk emlékezni az általános iskola második osztályában tanultakra: harmincban a négy megvan hétszer, maradék kettő. Mivel a maradékképzés is osztás, itt is kaphatunk kivételt, ha nullával szeretnénk osztani: például 30 % 0.

...

Néhány nyelvben a maradékképzés csak egész számokra használható, ám Java nyelvben a művelet elvégezhető valós számokon is:

...

...

Code Block
languagejava
titleJava
linenumberstrue
double szám;
szám = 30.0 % 4.1;

...


System.out.println(szám);

...


szám = 30.0

...

 /

...

 4.1;

...


System.out.println(szám);

...


szám = 7.0*4.1;

...


System.out.println(szám);

...


szám = 30.0

...

 -

...

 szám;

...


System.out.println(szám);

...

Eredményül az alábbi számokat kapjuk:

...

Code Block
titleEredmény
1.

...

3000000000000025
7.

...

317073170731708
28.

...

699999999999996
1.

...

3000000000000043

A megoldás egyszerű: 30.0 / 4.1 az egy valós számot ad eredményül. Ezt csonkolva hetet kapunk, amelyet ha visszaszorzunk a 4.1 számmal, elvileg 28.7 lesz az eredmény (a példában jól látszik a valós számábrázolás pontatlansága!). Ha a 30.0 számból kivonjuk a 28.7-et, akkor kapunk 1.3-at, mint maradék. El nem tudom képzelni, hogy ezt hol lehet kihasználni... :)

Növelés és csökkentés

Gyakori feladat, hogy egy változó értékét növeljük vagy csökkentsük egyel. Ez normál esetben így nézne ki:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 2;
szám = szám + 1;
System.out.println(szám);

...


szám = szám - 1;
System.out.println(szám);

...

Mivel ez a forma hosszú és összetett, a C nyelvből kölcsönzött ++ és -- operátort tudjuk használni, azonban ezek lehetnek prefix és postfix operátorok is:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 2;
System.out.println(szám++);

...


System.out.println(++szám);

...


System.out.println(szám--);

...


System.out.println(--szám);

...

Az eredmény:

...

Code Block
titleEredmény
2
4
4
2

Ami nem meglepő, hiszen az első esetben a kiírás után növekedett a változó értéke, a második esetben a kiírás előtt, aztán a harmadik esetben a kiírás után csökkentettük a változó értékét, majd pedig a kiírás előtt.

3.3.3. Relációs műveletek

Két érték összehasonlítása relációs jelekkel történik, s eredményképpen boolean típust kapunk, amely lehet igaz vagy hamis. Szaladjunk gyorsan át ezeken a műveleteken:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
int másikszám = 20;
System.out.println(

...

szám < másikszám);

...


System.out.println(

...

szám <= másikszám);

...


System.out.println(

...

szám > másikszám);

...


System.out.println(

...

szám >= másikszám);

...


System.out.println(

...

szám ==

...

 másikszám);

...


System.out.println(

...

szám !=

...

 másikszám);

...

A relációs jelek jelentése sorban:

  • a szám kisebb, mint a másikszám? Igaz, kisebb
  • a szám kisebb vagy egyenlő, mint a másikszám? Igaz, kisebb vagy egyenlő
  • a szám nagyobb, mint a másikszám? Hamis, nem nagyobb
  • a szám nagyobb vagy egyenlő, mint a másikszám? Hamis, nem nagyobb vagy egyenlő
  • a szám egyenlő a másikszámmal? Hamis, nem egyenlő
  • a szám nem egyenlő a másikszámmal? Igaz, nem egyenlő

Fontos, hogy csak ebben a formában tudjuk használni a relációs jeleket, a ’<=’ helyett a ’=<’ nem használható, illetve a ’!=’ helyett se tudjuk használni a ’<>’ jelet.

3.3.4. Logikai műveletek

A relációs műveletekkel nem tudjuk kifejezni azt az egyszerű matematikai képletet, hogy 4 < szám < 10, amely akkor igaz, ha a számértéke nagyobb, mint négy, és kisebb, mint tíz:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
System.out.println(4

...

 < szám < 10);

...

Ha mégis megpróbáljuk, akkor fordítási hibát kapunk eredményül (a fordítási hibákról később):

...

Code Block
titleEredmény
/home/work/JavaSuli/Kocsma/src/kocsma/Main.java:9:

...

 operator <

...

 cannot be applied to boolean,int  
    System.out.println(

...

4 < szám < 10);

...

ÉS művelet

A megoldáshoz a matematikai képletet szét kell választanunk két részre: 4 < szám ÉS szám < 10, vagyis a szám értéke legyen nagyobb, mint négy és legyen kisebb, mint tíz:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
System.out.println(4

...

 < szám &&

...

 szám < 10);

...

Mint látható, az && jel helyettesíti az ÉS szót, a futás eredménye pedig false, mivel a 10 ugyan nagyobb, mint 4, de nem kisebb, mint 10.

VAGY művelet

Ha két relációs művelet közül elég, ha az egyik teljesül, akkor össze tudjuk kapcsolni őket egy VAGYművelettel:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 4;
System.out.println(

...

szám % 2 ==

...

 0);

...


System.out.println(

...

szám % 3 ==

...

 0);

...


System.out.println(

...

szám % 2 ==

...

 0

...

 ||

...

 szám % 3 ==

...

 0);

...

Az első esetben a kifejezés akkor lesz igaz, ha a szám változó értéke maradék nélkül osztható kettővel. A második esetben hárommal kell oszthatónak lennie, a harmadik esetben a kifejezés akkor lesz igaz, ha a szám változó értéke maradék nélkül osztható kettővel vagy hárommal. A VAGY műveletet a ||jellel tudjuk jelölni.

NEM művelet

Sokszor előfordul, hogy a kiszámolt boolean eredmény ellentéte kell valamilyen okból kifolyólag, ekkor a NEM(más néven tagadás) műveletet kell használnunk:

...

...

Code Block
languagejava
titleJava
linenumberstrue
boolean válasz = true;
System.out.println(!válasz);

...

A tagadást a logikai változó elé tett felkiáltó jellel tudjuk megejteni, a példában a tagadásból következik, hogy a false kerül kiírásra.

3.3.5. Bitműveletek

Mivel számítógépeink egyelőre bitek alapján működnek, ezért célszerű beépíteni egy programnyelvbe a bitműveleteket. A bitműveletek alapja a kettes számrendszer, és minden primitív típus alapvetően kettes számrendszerben tárolt szám, ezért - a valós számokat leszámítva - értelmezhető rajtuk az összes bitművelet.

...

Induljunk ki egy szép kerek számból, azaz nézzük meg, hogy a decimális 10 hogy néz ki kettes számrendszerben 8 biten:

...

...

Code Block
titleBitek
00001010

Keressünk egy másik számot is, például nézzük meg a 57-es számot kettes számrendszerben, szintén 8 biten:

...

Code Block
titleBitek
00111001

Ezzel a két számmal fogunk bitműveleteket végezni.

Bitléptetés

A bitléptetés egy nagyon alacsony szintű művelet, a legtöbb CPU támogatja, ritkán szükség is van rá, ezért nem lehetett kihagyni a Java nyelvből. A bitek léptetése során a bináris számban lévő bitek sorrendje azonos marad, azonban a pozíciójuk megváltozik, jobbra vagy balra tolódnak el.

...

Fontos tudni, hogy a bitléptetés mindig 32 bites egész számon történő művelet, ha más adattípuson végeznénk el, akkor is 32 bites eredményt kapunk!

Bitléptetés balra

A balra léptetés során a bitek balra mozognak el, és jobb oldalon 0 értékek jönnek be, a bal oldalon kieső bitek pedig elvesznek:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
System.out.println(

...

 Integer.toBinaryString(

...

 szám << 0 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám << 1 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám << 2 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám << 3 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám << 28 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám << 29 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám << 30 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám << 31 ));

...

Az eredmény magáért beszél, a bitek elkezdenek balra mozogni, jobb oldalon pedig 0 értékek jönnek be:

...

Code Block
titleEredmény
1010
10100
101000
1010000
10100000000000000000000000000000
1000000000000000000000000000000
10000000000000000000000000000000
Bitléptetés jobbra

A jobbra léptetés azonos módon működik, mint a balra léptetés:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 0 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 1 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 2 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 3 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 28 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 29 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 30 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >>> 31 ));

...

Az eredmény itt is magáért beszél:

  1. 1010  
  2. 101  
  3. 10  
  4. 1  
  5. 0  
  6. 0  
  7. 0  
  8. 0  
Code Block
titleEredmény
1010
101
10
1
0
0
0
0
Előjeles bitléptetés jobbra

A jobbra léptetés esetén létezik előjeles léptetés, amikor a bináris szám bal szélén nem 0 érték jön be, hanem az előjelbit ismétlődik:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = -10;
System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 0 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 1 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 2 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 3 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 28 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 29 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 30 ));

...


System.out.println(

...

 Integer.toBinaryString(

...

 szám >> 31 ));

...

Mint látható, bal oldalon alapból egy egyes érték van, és ezzel töltődik fel a bithalmaz:

...

Code Block
titleEredmény
11111111111111111111111111110110
11111111111111111111111111111011
11111111111111111111111111111101
11111111111111111111111111111110
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111

Bitenkénti tagadás - negáció

Ha a kapott bitek mindegyikét negálni szeretnénk, akkor a ~ operátort kell használnunk:

...

...

Code Block
languagejava
titleJava
linenumberstrue
byte szám = 10;
System.out.println(~szám);

...

A kiírt eredmény -11, amely binárisan 11110101, ugyanis a negatív számokat kettes komplemens alapon kezelik az elterjedt számítógépek. A kettes komplemens egy bitenkénti tagadás, majd az eredményhez hozzáadunk egyet - így lesz a 10 kettes komplemense -10.

Bitenkénti ÉS művelet

A bitenkénti és művelethez már kettő operandus kell:

...

...

Code Block
languagejava
titleJava
linenumberstrue
byte szám = 10;
byte másikSzám = 57;
System.out.println(

...

szám &

...

 másikSzám);

...

Az eredmény 8 lesz, amelynek az oka, hogy a két számnak csak a negyedik pozícióban van azonosan 1 értéke:

...

Code Block
titleEredmény
00001010
00111001
00001000

Bitenkénti VAGY művelet

A bitenkénti vagy művelethez is kettő operandus kell:

...

...

Code Block
languagejava
titleJava
linenumberstrue
byte szám = 10;
byte másikSzám = 57;
System.out.println(

...

szám |

...

 másikSzám);

...

Az eredmény 59, ami binárisan 00111011, mivel ott tartalmaz 1 értéket, ahol a megadott két operandusnál legalább egy darab 1 érték volt:

...

Code Block
titleEredmény
00001010
00111001
00111011

Bitenkénti KIZÁRÓ VAGY művelet

A kizáró vagy hasonlít a vagy művelethez, viszont csak akkor lesz az eredmény is 1 érték, ha a megadott két operandusban azonos pozíción csak egy 1 érték van:

...

...

Code Block
languagejava
titleJava
linenumberstrue
byte szám = 10;
byte másikSzám = 57;
System.out.println(

...

szám ^ másikSzám);

...

Amelynek eredménye 51, hiszen:

...

Code Block
titleEredmény
00001010
00111001
00110011

Bitműveletek a gyakorlatban

Rikán találkozunk a programozás során bitműveletekkel, szinte kizárólag csak az ÉS művelet fordul elő, amikor olyan adatokon kell dolgoznunk, amelyek egymás mellé zsúfolt bitekből állnak.

3.3.6. Egyéb műveletek

A fentieken túl maradt néhány művelet, amelyeket nem lehet könnyedén csoportba sorolni, ezért kerültek az egyéb műveletek közé.

Művelettel kombinált értékadás

Gyakori eset, hogy egy változó értéke az előző értékéhez képest változik meg:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
szám = szám + 2;
System.out.println(szám);

...

A változó = változó műveleti jel kifejezés további részejellegű kifejezéseket rövidíteni tudjuk:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
szám += 2;
System.out.println(szám);

...

A rövidítés során a műveleti jel az egyenlőség jel elé kerül és az egyenlőség jel után eltűnik a kifejezésből a változó neve: változó műveleti jel= kifejezés további része. Ezt bármilyen műveletnél meg tudjuk tenni, amely két operandussal működik.

Feltételes értékadás

Ha egy eldöntendő kérdés alapján szeretnénk értéket adni egy változónak, akkor ezt a feltétles értékadással tudjuk megtenni. Nézzünk egy példát az abszolút érték képzésére:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = -10;
szám = szám < 0 ? -szám : szám;
System.out.println(szám);

...

A második sorban találjuk a lényeget, amelyet úgy tudunk kiolvasni, hogy a szám nevű változó értéke legyen egyenlő a -szám értékével, ha a szám < 0 feltétel igaz, egyébként legyen egyenlő a számértékével.

Szöveg összefűzése

A + jel használható szövegek összefűzésére is, ekkor két kisebb szövegből egy nagyobb szöveg lesz:

...

...

Code Block
languagejava
titleJava
linenumberstrue
String egy= "egy";

...


String kettő = "kettő";

...


String egykettő = egy + kettő;
System.out.println(egykettő.length());

...

Az eredmény természetesen 8.

3.4. Kifejezések

Az operátorok és operandusok halmazát kifejezésnek nevezzük, egy kifejezés mindig egy értéket ad vissza, amelyet általában értékadással átadunk egy változónak, vagy paraméterként adjuk át egy metódusnak. A cikksorozat első részében is használtunk már kifejezéseket, csak nem nevezetük így a leírt sorokat, amelyek egyszerű kifejezések voltak.

Az összetett kifejezésektöbb operátorból és operandusból állnak, és a megszokott matematikai kiértékelési sorrend szerint kell írnunk a kívánalmainkat:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 1 + 2 + 3;
System.out.println(szám);

...

A kifejezés értéke 6 lesz, ahogy azt várjuk, a kifejezése kiértékelése során a számítógép pont úgy viselkedik, ahogy azt annak idején tanultuk: veszi az első két számot, összeadja őket, majd az eredményt és a harmadik számot újfent összeadja. Ebben az esetben nem számít a kiértékelés sorrendje, hiszen teljesen mindegy, hogy a számokat milyen sorrendben adjuk össze, ettől függetlenül a számítógép mindig balról-jobbra haladvavégzi el az egyes műveleteket.

...

A kiértékelés sorrendje változhat a műveleti jelek függvényében, hiszen a szorzás előnyt élvez az összeadással szemben:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 1 + 2 * 3;
System.out.println(szám);

...

 A számítógép először a szorzás műveletét végzi el, majd a kapott eredményhez hozzáad egyet, így a végső eredmény 7lesz. Zárójelezéssel ez a kiértékelési sorrend felülbírálható:

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = (1 + 2) * 3;
System.out.println(szám);

...

Ebben az esetben a számítógép először a zárójelben lévő műveletet végzi el, majd a kapott eredményt megszorozza hárommal, így kapjuk meg az eredményt, ami 9.

3.4.1. Precedencia - kiértékelési sorrend

A kiértékelési sorrend függ az operátoroktól, így fontos tudni a pontos kiértékelési sorrendet, amelyet vagy megtanulunk, vagy zárójelezünk bizonytalan helyzetben. Lássuk a sorrendet:

  1. unáris operátorok (a kiértékelés jobbról balra történik!):
    1. --szám: a szám értékének előzetes csökkentése
    2. ++szám: a szám értékének előzetes növelése
    3. szám--: a szám értékének utólagos csökkentése
    4. szám++: a szám értékének utólagos növelése
    5. - szám: a szám előjelének megváltoztatása
    6. ~ szám: a szám bináris tagadása (negáció)
    7. ! igazHamis: egy boolean érték tagadása
    8. (type): típuskényszerítés
    9. new: új példány létrehozása
  2. multiplikatív operátorok:
    1. szám * másikSzámszám / másikSzám: a szám elosztása egy másikSzámma: a két szám összeszorzása
    2. szám / másikSzám: a szám elosztása egy másikSzámmal
    3. szám % másikSzám: maradék képzése (szám osztva másikSzámmal)
  3. additív operátorok:
    1. szám + másikSzám: a két szám összeadása
    2. szám - másikSzám: számból kivonjuk a másikSzámot
  4. bitléptetés operátorok:
    1. szám << másikSzám: a szám változóban lévő bitek léptetése balra másikSzám pozícióval
    2. szám >> másikSzám: a szám változóban lévő bitek léptetése jobbra másikSzám pozícióval - az előjel figyelembevételével
    3. szám >>> másikSzám: a szám változóban lévő bitek léptetése jobbra másikSzám pozícióval
  5. relációs operátorok:
    1. szám < másikSzám: a szám kisebb-e, mint a másikSzám
    2. szám <= másikSzám: a szám kisebb vagy egyenlő-e, mint a másikSzám
    3. szám > másikSzám: a szám nagyobb-e, mint a másikSzám
    4. szám >= másikSzám: a szám nagyobb vagy egyenlő-e, mint a másikSzám
    5. instanceof: referencia teszt operátor
  6. egyenlőség operátorok:
    1. szám == másikSzám: a két szám egyenlő-e egymással
    2. szám != másikSzám: a két szám nem egyenlő-e egymással
  7. bitenkénti ÉS operátor:
    1. szám & másikSzám: a szám és a másikSzám között bitenkénti ÉS művelet
    2. igazHamis & másikIgazHamis: az igazHamis és a másikIgazHamis közötti ÉS művelet
  8. bitenkénti KIZÁRÓ VAGY operátor:
    1. szám ^ másikSzám: a szám és a másikSzám között bitenkénti KIZÁRÓ VAGY művelet
    2. igazHamis ^ másikIgazHamis: az igazHamis és a másikIgazHamis közötti KIZÁRÓ VAGY művelet
  9. bitenkénti VAGY operátor:
    1. szám | másikSzám: a szám és a másikSzám között bitenkénti VAGY művelet
    2. igazHamis | másikIgazHamis: az igazHamis és a másikIgazHamis közötti VAGY művelet
  10. boolean ÉS operátor:
    1. igazHamis && másikIgazHamis: az igazHamis és a másikIgazHamis közötti ÉS művelet
  11. boolean VAGY operátor:
    1. igazHamis || másikIgazHamis: az igazHamis és a másikIgazHamis közötti VAGY művelet
  12. feltételes értékadás operátor:
    1. szám == másikSzám ? szám : másikSzám: feltételes értékadás (lásd fent bővebben)
  13. értékadás operátor:
    1. szám = másikSzám: a szám változó értéke felveszi a másikSzám értékét
  14. értékadás műveletteloperátorok:
    1. szám += másikSzám: a szám változó értéke a szám előző értéke és a másikSzám összege lesz
    2. szám -= másikSzám: a szám változó értéke a szám előző értéke és a másikSzám különbsége lesz
    3. szám *= másikSzám: a szám változó értéke a szám előző értéke és a másikSzám szorzata lesz
    4. szám /= másikSzám: a szám változó értéke a szám előző értéke és a másikSzám hányadosa lesz
    5. szám %= másikSzám: a szám változó értéke a szám előző értéke és a másikSzám maradéke lesz
    6. szám &= másikSzám: a szám változó értéke a szám előző értéke és a másikSzám változó közötti bitenkénti ÉS eredménye lesz
    7. szám ^= másikSzám: a szám változó értéke a szám előző értéke és a másikSzám változó közötti bitenkénti KIZÁRÓ VAGY eredménye lesz
    8. szám |= másikSzám: a szám változó értéke a szám előző értéke és a másikSzám változó közötti bitenkénti VAGY eredménye lesz
    9. szám <<= másikSzám: a szám változó értéke a szám előző értéke balra léptetve másikSzám pozícióval lesz
    10. szám >>= másikSzám: a szám változó értéke a szám előző értéke előjellel jobbra léptetve másikSzám pozícióval lesz
    11. szám >>>= másikSzám: a szám változó értéke a szám előző értéke jobbra léptetve másikSzám pozícióval lesz

A prefix (++szám vagy ++szám) és a postfix (szám++ vagy szám--) operátorok használata mindig kockázatos, mivel a kifejezés kiértékelés során változik a változó értéke, vessünk egy pillantást az alábbi programrészletre és próbáljuk meghatározni az eredményt:

...

...

Code Block
languagejava
titleJava
linenumberstrue
int szám = 10;
System.out.println(szám++

...

 +

...

 ++

...

szám *

...

 ++

...

szám +

...

 szám++);

...

Nos, az eredmény 179, mégpedig azért, mert az unáris operátorok az elsők a precedencia táblázatban, és kiértékelésük az elsők között történik, ebből adódóan a kifejezés a következő lesz az unáris operátorok feloldása után:

...

Code Block
languagejava
titleJava
linenumberstrue
System.out.println(10

...

 +

...

 12

...

 *

...

 13

...

 +

...

 13);

...

Ha végigkövetjük az értékadásokat, akkor láthatjuk, hogy az eredmény valóban 179.

3.5. Blokkok

A nyelvek fejlődése során viszonylag korán megjelentek a blokkok, amelyek utasításokat fognak közre. Az eddigiek során láttunk már több blokkot is, amelyek összefogták az eddig beírt utasításainkat:

  • {  
  • }  
    Code Block
    languagejava
    titleJava
    linenumberstrue
    {
    }

    Ugye ismerős? :)

    A blokkok hasznos társaink lesznek a programozás során, hiszen utasítások kötegelt végrehajtása gyakori feladat. További hasznuk, hogy a deklarált változóknak hatókört adnak: egy változót mindig csak az őt tartalmazó blokkon belül tudjuk elérni:

  • int i = 10;  
  • {  
  •   int j = 10;  
  • }  
  • Code Block
    languagejava
    titleJava
    linenumberstrue
    int i = 10;
    {
      int j = 10;
    }
    System.out.println(j);
        System

    A program nem fordítható le, mivel a jváltozó csak a blokkon belül érhető el. A blokkok lehetővé teszik, hogy egy változónevet többször felhasználhassunk, ha azok olyan blokkban vannak deklarálva, ahol egymást nem látják:

  • int j = 10;  
  • {  
  •   int i = 10;  
  • Code Block
    languagejava
    titleJava
    linenumberstrue
    int j = 10;
    {
      int i = 10;
      System.out.println(i);
        System
    
      System.out.println(j);
      
    
    }
      
  • {  
  •   int i = 20;  
  •   System
    
    {
      int i = 20;
      System.out.println(i);
        System
    
      System.out.println(j);
      
    
    }
      
    
    System.out.println(j);
      

    A két i nevű változó egymásról nem tud, tehát gond nélkül tudjuk használni a program különböző részeiben.

    Fontos tudni, hogy változókat bármely blokkon belül tudunk deklarálni, s célszerű mindig a blokk elején megejteni azokat a deklarációkat, amelyeknek kezdőértéket is adunk, ezzel a programunk átláthatóbb lesz. A programunk írása során tucatnyi változót fogunk létrehozni, amelyeket folyamatosan hozunk létre, ezek is az adott blokkban lesznek csak elérhetők. Ha megnézünk egy Java osztályt, akkor láthatjuk, hogy az is egy nagy blokkban helyezkedik el, ezért rögtön a kezdő kapcsos zárójel után létrehozhatunk változókat, amelyeknek a neve osztályváltozó vagy példányváltozó, attól függően, hogy a módosítója szerint statikus vagy sem. Ezek a változók elfedhetők lokális (metódusokon belüli) változókkal, amelyekre oda kell figyelnünk, mivel aljas hibákat tudnak okozni

    .

    ...

    .

    ...

    Az előzőekben említett program-alkotórészek fabatkát se érnek vezérlő szerkezetek nélkül, amelyek alapvetően döntésképessé és ciklikussá teszik a programjainkat, ezért kétféle vezérlő szerkezettel találkozhatunk általában:

    • elágazások, amelyek egy döntés eredményeképpen végrehajtanak programrészeket
    • ismétlések, amelyek egy újra-és-újra kiértékelt döntés eredményeképpen újra-és-újra végrehajtanak programrészeket

    Láthatjuk, hogy mindkét fajta vezérlő szerkezet függ egy feltételtől, amely szinte kivétel nélkül egy eldöntendő állítás, amelyre egyértelműen igazat vagy hamisat kell eredményül adnunk.

    3.6.1. Egyágú elágazás (if)

    Az egyik legegyszerűbb vezérlő szerkezet, amely a feltételtől függően végrehajtja az őt követő utasítást:

    1. int pénz = 200;  
    2. int sörÁra = 120;  
    3. if (pénz >= sörÁra)  
    4. System.out.println("Vegyünk egy sört és igyuk meg!");  

    ...

    1. int pénz = 200;  
    2. int sörÁra = 120;  
    3. if (pénz >= sörÁra)  
    4. System.out.println("Vegyünk egy sört...");  
    5. System.out.println("...és igyuk meg!");  

    A várt eredmény nem marad el, hiszen kikerül a képernyőre az ismert szöveg, amely abban a hitben hagy minket: a program megfelelően működik, ám egy tesztelés nem tesztelés, nézzük meg, mi történik, ha nincs elég pénzünk sörre:

    1. int pénz = 100;  
    2. int sörÁra = 120;  
    3. if (pénz >= sörÁra)  
    4. System.out.println("Vegyünk egy sört...");  
    5. System.out.println("...és igyuk meg!");  

    Az eredmény egy árva "...és igyuk meg!", mert sörre bizony nem volt pénzünk. A megoldás egyszerű, minden if szerkezetet blokkutasítással kövessünk, és a blokkon belül írjuk meg a feltételtől függő programrészt - ha egy utasításról van szó, akkor is, inkább legyen hosszabb a program, mint hibás:

    1. int pénz = 100;  
    2. int sörÁra = 120;  
    3. if (pénz >= sörÁra)  
    4. {  
    5.   System.out.println("Vegyünk egy sört...");  
    6.   System.out.println("...és igyuk meg!");  
    7. }  

    A várakozásainknak megfelelően ez a program már nem ír ki semmit, hiszen nincs pénzünk sörre, ezért bővítsük ki a programot egy olyan feltételes szerkezettel, ahol a feltétel pont a fenti ellentéte:

    1. int pénz = 100;  
    2. int sörÁra = 120;  
    3. if (pénz >= sörÁra)  
    4. {  
    5.   System.out.println("Vegyünk egy sört...");  
    6.   System.out.println("...és igyuk meg!");  
    7. }  
    8. if (pénz < sörÁra)  
    9. {  
    10.   System.out.println("Sajnos nincs pénzünk sörre...");  
    11. }  

    Ebben az esetben a program kimentén a "Sajnos nincs pénzünk sörre..."szöveg olvasható.

    3.6.2. Kétágú elágazás (if-else)

    A hibalehetőségek csökkentése a programozók elemi érdeke, ezért találták ki régesrég az if-else szerkezetet, amely lehetővé teszi, hogy a programunk tegyen valamit a feltétel fennállása esetén (igaz ág), illetve tegyen másvalamit akkor, ha a feltétel nem teljesül (hamis ág), így nem kell két feltételt karbantartani, s a program is rövidebb lesz:

    1. int pénz = 100;  
    2. int sörÁra = 120;  
    3. if (pénz >= sörÁra)  
    4. {  
    5.   System.out.println("Vegyünk egy sört...");  
    6.   System.out.println("...és igyuk meg!");  
    7. else  
    8. {  
    9.   System.out.println("Sajnos nincs pénzünk sörre...");  
    10. }  

    Mint láthatjuk, a módosítás mindössze annyi, hogy a második if és a feltétel helyére egy elsekerült.

    3.6.3. Többágú elágazások

    Sok esetben szükség van többágú elágazásra, mivel a való életben is gyakran kell egy bekövetkezett tényre több lehetőség közül választani, gondoljunk csak arra az esetre, amikor sört akarunk venni a sarki kisboltban, de nincs mindig tele a pénztálcánk. Ekkor az éppen aktuális anyagi lehetőségeink határozzák meg, hogy milyen sört tudunk megvásárolni.

    3.6.3.1. Egymásba ágyazott if-else

    Egymásba ágyazott kétágú elágazásokból tudunk építeni többágú elágazást, ekkor a hamis ágba újabb elágazást tudunk tenni, amely sok ág esetén kellően átláthatatanná teheti a programunkat:

    1.     int pénz = 100;  
    2.     if (pénz >= 500)  
    3.     {  
    4.       System.out.println("Igyunk egy Guinness sört!");  
    5.     } else  
    6.     {  
    7.       if (pénz >= 300)  
    8.       {  
    9.         System.out.println("Igyunk egy Leffe sört!");  
    10.       } else  
    11.       {  
    12.         if (pénz >= 100)  
    13.         {  
    14.           System.out.println("Igyunk egy Soproni sört!");  
    15.         } else  
    16.         {  
    17.           System.out.println("Sajnos nincs pénzünk sörre... :(");  
    18.         }  
    19.       }  
    20.     }  
    21.     System.out.println("Menjünk haza...");  

    A program tartalmaz több - egymásba ágyazott - if-else szerkezetet, amelyeknél látnunk kell egy döntési sorozatot. Ha a fenti feltételek szerint 100 forintból akarunk sört inni, akkor a kiértékeljük a pénz >= 500 feltételt, amely nyilvánvalóan hamis lesz, ezért nem tudunk Guinness sört inni, kénytelenek vagyunk a hamis ágon továbblépni. Az első hamis ágban egy újabb feltételt kell kiértékelni: pénz >= 300, amely szintén hamis lesz, ezért Leffe sört sem tudunk inni. Továbbmegyünk a második hamis ágon, ahol meglátjuk az utolsó feltételt, amelynek már megfelel a pénzmagunk, így tudunk inni egy Sopronit. Észre kell vennünk, hogy bármelyik feltétel teljesülése esetén - a hamis ág kihagyása miatt - a program végrehajtása az első hamis ág után folytatódik (menjünk haza...).

    3.6.3.2. Egymásba ágyazott if-else-if

    Az egymásba ágyazott if-else szerkezetek mindig átírhatóak egy if-else-ifszerkezetre, amely sokkal áttekinthetőbb, mivel látszólag mellőzi az egymásba ágyazást:

    1.     int pénz = 100;  
    2.     if (pénz >= 500)  
    3.     {  
    4.       System.out.println("Igyunk egy Guinness sört!");  
    5.     } else if (pénz >= 300)  
    6.     {  
    7.       System.out.println("Igyunk egy Leffe sört!");  
    8.     } else if (pénz >= 100)  
    9.     {  
    10.       System.out.println("Igyunk egy Soproni sört!");  
    11.     } else  
    12.     {  
    13.       System.out.println("Sajnos nincs pénzünk sörre... :(");  
    14.     }  
    15.     System.out.println("Menjünk haza...");  

    Észre kell vennünk, hogy az else utasítások után lespóroltunk egy blokk utasítást, mivel a blokkban csak egy if utasítás volt. Ezzel az apró módosítással átláthatóbbá tettük a program működését, hiszen fentről lefelé olvashatjuk a feltételeket és a feltételekhez tartozó utasításokat, illetve az utolsó else után azt az utasítást, amely akkor hajtódik végre, ha egyik feltétel se teljesült. Ez az utolsó else ág egyébként elhagyható, ha nincs rá szükségünk.

    3.6.3.3. Kapcsoló (switch-case-default)

    Ha primitív típus meghatározott értéke alapján szeretnénk különféle dolgokat végezni, akkor egy hosszabb if-else-if szerkezet helyett használjuk inkább a switch utasítást:

    1.     int pénz = 300;  
    2.     int sörÁra = 120;  
    3.     int sörökSzáma = pénz / sörÁra;  
    4.     switch (sörökSzáma)  
    5.     {  
    6.       case 0:  
    7.         System.out.println("Nincs sör, nincs mit inni.");  
    8.         break;  
    9.       case 1:  
    10.         System.out.println("Egy sör nem sör.");  
    11.         break;  
    12.       case 2:  
    13.         System.out.println("Két sör fél egészség.");  
    14.         break;  
    15.       case 3:  
    16.         System.out.println("Három sör jó kezdés.");  
    17.         break;  
    18.       case 4:  
    19.         System.out.println("Négy sör jó, két sör rossz.");  
    20.         break;  
    21.       default:  
    22.         System.out.println("Sok sör soha nem árt.");  
    23.     }  

    Ahogy a példában látjuk, döntés a sörökSzáma változó értékétől függ, ha a változó értéke megegyezik valamelyik caseág értékével, akkor az az ág végrehajtásra kerül. A várt működés szerint a program az alábbit írja ki:

    1. Két sör fél egészség.  

    Ha egyik ág se hajtódna végre, akkor a default ágra kerül a vezérlés, ha nincs default ág, akkor a program végrehajtása a switch utasítás végétől folytatódik. A switch működési sajátossága, hogy az első egyezőségtől kezdve az összes utasítást végrehajtja a blokk végéig, ezért minden ágat egy break utasítás zár, amely hatására a program végrehajtása a switch utasítás után folytatódik. Gyakori programozói hiba a break elhagyása, amely okán másképp működik a programunk, próbáljuk ki a fenti programot brakeutasítások nélkül:

    1. Két sör fél egészség.  
    2. Három sör jó kezdés.  
    3. Négy sör jó, két sör rossz.  
    4. Sok sör soha nem árt.  

    Mivel két sörre volt pénzünk, a két sört tartalmazó ágtól kezdve az összes utasítás végrehajtódik.

    3.6.4. Előltesztelő ciklus (while)

    Sok esetben szükséges egy-egy programrészletet megismételni, gondoljunk csak arra, ha bemegyünk egy kocsmába egy ezressel és addig szeretnénk sörözni, amíg el nem fogy a pénzünk:

    1. int pénz = 1000;  
    2. int sörÁra = 400;  
    3. while (pénz > sörÁra)  
    4. {  
    5.   System.out.println("Kérjünk egy korsó sört, majd igyuk meg.");  
    6.   pénz -= sörÁra; // Vonjuk le a sör árát a pénzünkből  
    7. }  

    ...

    3.6.5. Hátultesztelő ciklus (do-while)

    A hátultesztlő ciklus működése hasonlít az előltesztelő ciklus működésére, egyedüli különbség, hogy a feltétel kiértékelése az első ciklusmag lefutása után történik meg, tehát a hátultesztelő ciklus egyszer mindenképpenvégrehajtja a ciklusmagot:

    1.     int pénz = 1000;  
    2.     int sörÁra = 400;  
    3.     do  
    4.     {  
    5.       System.out.println("Kérjünk egy korsó sört, majd igyuk meg.");  
    6.       pénz -= sörÁra; // Vonjuk le a sör árát a pénzünkből  
    7.     }  
    8.     while (pénz > sörÁra);  

    A hátultesztelő ciklus tipikus felhasználási területe a beolvasott érték alapján történő döntés, a beolvasást a ciklus addig ismétli, amíg a várt értéket sikerül beolvasni.

    3.6.6. Számláló ciklus (for)

     

    3.6.7. Léptető ciklus (for each)

    ...