Operátorok - 1. java bevezető

|
1. java bevezető
|
bet | 5/51 | Sana | 07.04.2017 | Hajmi | 1,08 Mb. | | #3295 |
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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 aszá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ám vá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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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):
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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):
view plaincopy to clipboardprint?
-
/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:
view plaincopy to clipboardprint?
-
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 VAGY művelettel:
view plaincopy to clipboardprint?
-
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 vagyhá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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
00001010
-
00111001
-
00001000
Bitenkénti VAGY művelet
A bitenkénti vagy művelethez is kettő operandus kell:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
byte szám = 10;
-
byte másikSzám = 57;
-
System.out.println(szám ^ másikSzám);
Amelynek eredménye 51, hiszen:
view plaincopy to clipboardprint?
-
00001010
-
00111001
-
00110011
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:
view plaincopy to clipboardprint?
-
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észe jellegű kifejezéseket rövidíteni tudjuk:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
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:
view plaincopy to clipboardprint?
-
String egy= "egy";
-
String kettő = "kettő";
-
String egykettő = egy + kettő;
-
System.out.println(egykettő.length());
Az eredmény természetesen 8.
|
| |