[[:oktatas:programozás:java|< Java]] ====== A Java nyelv ====== * **Szerző:** Sallai András * Copyright (c) 2009, Sallai András * Szerkesztve: 2009-2021 * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC BY-SA 4.0]] * Web: https://szit.hu ===== Bevezetés ===== A Java-át **James Gosling, Patrick Naughton, Chris Warth, Ed Frank, és Mike Sheridan** hozta létre a **Sun Microsystems, Inc.** cégnél 1991-ben. 18 hónap telt el az első verzió megjelenéséig. Ennek az első nyelvnek a neve Oak volt, később 1995-ben lett átnevezve Java-ra. 2009-ben a Sun Microsystems-t felvásárolta az Oracle, így a Java rendszert ők viszik tovább. Java-át úgy tervezték, hogy az így megírt programok minden operációs rendszeren fussanak minden változtatás nélkül. Ez úgy lehetséges, hogy a Java program nem az operációs rendszeren fut natív módon, azt egy Java környezetben futtatjuk. A Java nyelven írt programokat java fordítóval fordítjuk le, és Java futtató környezettel futtatjuk. Ez utóbbi azt jelenti, hogy egy operációs rendszeren önállóan futni nem képes. A futtató környezet általánosan keretrendszernek is hívjuk, de az Oracle keretrendszerét **Java Runtime Environment** néven használjuk, röviden JRE. A fejlesztői környezet pedig a JDK, azaz a **Java Development Kit**. A fejlesztői környezet tartalmazza többek között a java fordítót, amely parancs a "javac". A Java nyelv szigorúan osztályok halmaza, kis és nagybetű érzékeny, minden utasítást pontosvesszővel zárunk. A Java nyelven írt programokból bájtkódot szokás létrehozni. ^ Java forráskód ^ Java fordító ^ Java bájtkód ^ Java futtató ^ Gépi kód | | Program.java | javac ^ Program.class | java | 1 és 0 sorozata | Azonban vannak fordítók, amelyek gépi kód létrehozására is alkalmasak. ^ Java forráskód ^ Java fordító ^ Gépi kód | | Program.java | javac | Program.exe | A bájtkód futtatását a Java keretrendszer, vagy futtató környezet, angolosan Java Runtime Environment, röviden JRE biztosítja. ^ Java bájtkód | | Java keretrendszer | | Operációs rendszer | | Hardver | ===== Helló Világ ===== Készítse el a következő forráskódot a megadott néven, majd mentse, fordítsa és futtassa: class Test { public static void main(String[] args) { System.out.println("Java működik a gépeden"); } } Fordítás: javac test.java Futtatás: java test Előfordul, hogy a futtató keretrendszer nem találja a keretrendszer osztályait. Ekkor a következő kapcsoló megadása szükséges: java -cp . test ==== A program elemzése ==== A programban megfigyelhetjük, hogy az összetartozó részeket, továbbiakban blokkokat kapcsos zárójelek határolják: { ez a blokk } { egyik sor másik sor } A példa alapján azt is észrevehetjük, hogy a blokkok egymásba ágyazhatók, és minden blokknak van egy fejrésze. A blokk fejrészében írjuk le mire is való az adott blokk. A Javaban mindig osztályokkal dolgozunk, angolul class. Osztályokba szervezzük a megvalósítandó programjainkat. Ennek valamilyen nevet kell adni. Fenti példánkban a név "test". Ennek a névnek meg kell egyeznie az állomány nevével. Ez lesz a kiindulási osztályunk, a program végrehajtása ebben az osztályban kezdődik majd. A Javaban az egyes tevékenységeket függvényekben valósítjuk meg és szokásos módon **metódus**nak nevezzük. Minden Java program kell tartalmazzon egy "main" nevű metódust. A programnak ez lesz kiindulási pontja, innen indul, amit úgy mondunk: a program "belépési pontja". A main metódust a kiinduló osztályunkban hozzuk létre. A neve előtt és után egy pár dolgot meg kell adnunk. A main előtt módosítókat adunk meg. A main kötelező módosítói a public és static. A **public** biztosítja, hogy a program indításakor a main metódus elérhető legyen az operációs rendszerből. A **static** módosító biztosítja, hogy a main metódust a nélkül is elérhessük, hogy példányosítanánk a test osztályt (Később látni fogjuk, hogy az osztályokkal sokszor úgy dolgozunk, hogy létrehozunk belőle egy példányt). A **void** egy speciális típus, azt jelenti nincs típus. Esetünkben ezzel azt mondjuk, hogy a program visszatérési értékkel nem rendelkezik a futtató környezet felé. A main név után zárójelekben adjuk meg a program bemenő paramétereinek leírását. Ez "String[] args" A bemenő paraméterek leírását akkor is meg kell adnunk ha nem használjuk őket. Fordításkor nem is de futtatáskor hibát kapunk, ha hiányzik. A példában azt látjuk, hogy egy String típusú tömbben amelynek neve "args" tároljuk el a bemenő paramétereket. A String típusról és a tömbökről később lesz szó. {{:oktatas:programozás:java:argumentumok.png?400|}} {{:oktatas:programozás:java:osztalyleiras.png?400|}} {{:oktatas:programozás:java:mainmetodus.png?400|}} ==== Fordítás ==== A példában szereplő forrást a javac paranccsal fordítjuk. Alap esetben persze ez nem áll rendelkezésére. Telepítenünk kell a Java SDK valamely verzióját. A telepített SDK könyvtárában lesz egy "bin" nevű könyvtár, ezt útvonalba tesszük. Itt található a javac fordító is. A java futtató parancs általában működni szokott, ha böngészőnk miatt már telepítettünk egy Java JRE csomagot. ==== System osztály ==== A Java nyelvben osztályokkal dolgozunk. Mivel sok osztály létezik szükséges azok csoportosítása. Az összetartozó osztályokat csomagokban tároljuk. Egy csomag a háttértárolón egy könyvtárnak felel meg. A System osztály a java.lang csomagból (wrapper) való. Ha egy osztályt a Java nyelvben használni szeretnénk, akkor importálni kell azt a csomagot, amely azt tartalmazza. A java.lang egy olyan alaposztály, amelyet a Javaban nem kötelező importálni, ez biztosítja a Java program alapszerkezetét. ==== Gyakorlás ==== * Milyen kiterjesztése van egy Java forráskódnak? * Milyen kiterjesztése van egy lefordított Java programnak? * Eredetileg hány ember hozta létre a Java-át? * Milyen paranccsal fordítjuk le a Java nyelven írt programunkat? * Milyen paranccsal tudjuk futtatni a Java programot? * Egy Java program futtatásakor meg kell adni a program kiterjesztését? * Mit kell tudni a main() metódusról? * Milyen karakterrel jelezzük egy blokk kezdetét és végét? * A main() metódusnak milyen kötelező módosítói vannak? * A main() metódusnak milyen kötelező bemenő paramétere van? * A System osztály melyik csomagban található? * Mi az a void? * Írasson ki karaktersorozat helyett számokat a képernyőre. * Oldjon meg feladatokat az [[oktatas:programozas:feladatok:altalanos|általános feladatgyűjteményből]]. Önnek jelenleg körülbelül az első 20 feladat megoldása jöhet szóba. * Melyik csomag van alapértelmezetten importálva? * A Java nyelv kisbetű-nagybetű érzékeny? * Mi a JDK? * Mi a JRE? * A következő programban 3 hiba van. Keresse meg őket. {{:oktatas:programozas:java:prog01.png?400|}} * A következő programban 2 hiba van. Keresse meg őket. {{:oktatas:programozas:java:prog01_02.png?400|}} * A következő programban 2 hiba van. Keresse meg. {{:oktatas:programozas:java:prog01_03.png?400|}} * A következő programban 2 hiba van. Keresse meg. {{:oktatas:programozas:java:prog01_04.png?400|}} * A következő programban 2 hiba van. Keresse meg. {{:oktatas:programozas:java:prog01_05.png?400|}} * A következő programban 2 hiba van. Keresse meg. class Prog01 { public static void main(String[]) { System.println("Valami"); } } * A következő programban 2 hiba van. Keresse meg. class Prog01 { public static void min(String[] args) { System.out.pritln("Valami"); } } * A következő programban 2 hiba van. Keresse meg. public Prog01 { public static void main(String[] arg) { System.out.println"Valami"); } } * A következő programban 2 hiba van. Keresse meg. class Prog01 { public static oid Main(String[] args) { System.out.println("Valami"); } } * A következő programban 2 hiba van. Keresse meg. class Prog01 { Public static void main(String[] args) System.out.println("Valami"); } } * A következő programban 2 hiba van. Keresse meg. class Prog01 { public static void main(String[ args) { System.out.println("alma"); System.out.println("körte") System.out.println("barack"); System.out.println("szilva"); } } ===== Megjegyzések ===== A Java nyelvben egy és kétsoros megjegyzések használhatók. Az egysoros megjegyzést a kettőd darab perjel valósítja meg: // egy soros megjegyzés Több soros megjegyzést a /* és */ karakterek közzé írhatunk: /* ez egy több soros megjegyzés */ ==== Gyakorlat ==== * A következő programban van egy szintaktikai hiba. Keresse meg. {{:oktatas:programozas:java:prog01_megjegyzes01.png?400|}} * A következő programban van egy szintaktikai hiba. Keresse meg. {{:oktatas:programozas:java:prog01_megjegyzes02.png?400|}} ===== Kivitel ===== A kivitel alapesetben azt jelenti írok a képernyőre. Ezt megtehetjük a következő két metódussal a System osztályból: * print() * println() A következőkben összehasonlítjuk a két metódust, megnézzük a különbségeket. Írjunk programot, amely az "Első" és a "Második" szavakat írja a képernyőre. Használjunk println() metódust: System.out.println("Első"); System.out.println("Második"); Most írassuk ki a két szót print() metódussal. System.out.print("Első"); System.out.print("Második"); Nemcsak karaktersorozatokat írathatunk ki, lehet számok és más karakterek is: System.out.println("ElsőMásodik"); System.out.println("1234"); System.out.println("@!+="); Ha számokat szeretnénk kiíratni, akkor azokat nem kötelező idézőjelek közzé tenni: System.out.println(1234); Ha a számokat idézőjelek nélkül adjuk meg paraméterként, akkor számításokat is végezhetünk vele. A következő példában beszorozzuk az 1234-es értéket 2-vel. System.out.println(1234 * 2); Esetleg összeadásokat végezhetünk vele: System.out.println(3 + 2); A kimenet: 5 Ügyeljünk arra, hogy ha az előbbi kifejezést idézőjelbe tesszük, akkor nem az összeadás eredménye íródik ki, hanem a kifejezés karakterről karakterre: System.out.println("3 + 2"); Kimenet: 3 + 2 Statikus import: import static java.lang.System.*; class Program01 { public static void main(String[] args) { out.println("Hi"); } } ===== Különleges karakterek ===== A különleges karakterek másként escape szekvenciák. Néhány karakternek speciális értelmezése is lehet. Ha így akarjuk használni, akkor ezt valahogy jelezni kell. Ilyen speciális értelmezés lehet, amikor egy sortörést akarunk kiíratni. Ezt az "n" karakterrel tehetjük meg, ha a speciális jelentését használjuk. A speciális jelentést egy visszaperjellel (\) jelezzük: \n Ilyen speciális kérés lehet egy tabulátorjel kiíratása. A tabulátorjelet a "t" karakter jelképezi. A használatához itt is a visszaperjelet tesszük elé: \t Az ilyen karaktereket Escape szekvenciának hívjuk. Gyakorlásként írjuk a képernyőre a "Helló Világ" nevű programot a következő formában: class Program { public static void main(String[] args) { System.out.println("Helló\nVilág"); } } A példafeladatban a (\n) escape szekvenciát használjuk. class Program { public static void main(String[] args) { System.out.println("Helló\tVilág"); } } Vannak olyan karakterek is, amelyeknek a Java nyelven eleve speciális jelentésük van. Ilyen az idézőjel ("), amely egy szöveg elejét és végét jelzi. Ha egy karaktersorozatban szeretnénk kiíratni, nehézségekbe ütközünk. Ehhez is tartozik persze escape szekvencia: \" class Program { public static void main(String[] args) { System.out.println("Helló\"Világ"); } } Az escape szekvenciák tehát egy-egy betű, amelyet ha alkalmazunk visszaperjellel vezetjük be. Alkalmazhatjuk őket karakterek helyén is. char sortores = '\n'; A Java nyelv Escape karakterei az alábbi táblázatban láthatók. ^ Escape szekvencia ^ Leírás ^ | \uxxxx | Hexadecimális UNICODE karakter (xxxx) | | \' | Felső vessző | | \" | Idézőjel | | \\ | Visszaperjel | | \r | Kocsi vissza (A kiírás a sor elején folytatódik) | | \n | Új sor | | \f | Lapdobás | | \t | Tabulátor | | \b | Visszatörlés (Előtte lévő karaktert törli) | Escape szekvenciával megadhatunk Unicode karakter is ha tudjuk annak kódját. Az alábbi táblázatban a Copyright és negáció jelek unicode-ját látjuk. ^ Karakter ^ Kód ^ | © | 00a9 | | ¬ | 00ac | A példa kedvéért így íratjuk kia copyright karaktert: System.out.println("\u00a9"); Még több unicode karakter: http://www.unicode.org/charts/PDF/U0080.pdf Karakter típusú változók létrehozása és értékadás így a következő módon néz ki: char ch; char idezojel; ch = 'a'; idezojel = '\"'; W7 alatt fok: \u0159 ===== Adattípusok ===== A memóriában adatokat tárolunk, amelyek lehetnek **egész** számok, **valós** számok, **karakterek**, esetleg **karaktersorozatok**. Az ilyen memóriahelyeket a programozás során mint **változó**kat emlegetjük. A változókat használatuk előtt **deklarál**ni kell. Ez azt jelenti, meg kell mondanunk milyen típusú adatot szeretnénk tárolni az adott memória helyen. Ez azért fontos, mert a rendszer így tudja mekkora helyet kell az adatnak lefoglalni. Az alábbiakban megnézzük hogyan foglalhatunk helyet egész, valós, karakteres, stb., típusok számára. Példa egy változó deklarációra: int szam; A különböző primitív adattípusok számára a memóriában helyet foglalunk, használat előtt. Azonban nem mindegy mekkora helyet kell lefoglalni. Más méretet foglalunk le egy egész típusú számnak vagy más méretet egy valóst típusú számnak. A memóriában lefoglalt helyre értéket helyezhetünk el a következő utasítással: szam = 35; A "szam" nevű memóriahelyre 35 értéket tettük. Akármekkora számot nem tehetünk a memóriahelyre. Ha deklaráláskor az "int" kulcsszót tettük a deklarációba, akkor a legnagyobb beírható szám: 2147483647. A legkisebb: -2147483648. Az int helyett megadható még egy pár típus. A következő táblázatokban azt látjuk, melyik mekkora helyet foglalhat a memóriában és így mekkora számot tárolhatunk benne, maximum és minimum értékekkel. ==== Egész típusok ==== | byte | 1 byte | -128 -- 127 | | short | 2 bytes | -32 768 -- 32 767 | | int | 4 bytes | -2 147 483 648 -- 2 147 483 647 | | long | 8 bytes | -9 223 372 036 854 775 808 -- 9 223 372 036 854 775 807 | Ha nagyobb értéket akarunk elhelyezni egy változóban, mint amire névlegesen megengedett: short a = 32768; Fordításkor a következő hibaüzenetet kapjuk: javac -cp Program.java Program.java:6: possible loss of precision found : int required: short short a = 32768; ^ 1 error >Exit code: 1 Az int típus esetén: integer number too large: 2147483648 int c = 2147483648; ^ ==== Valós típusok ==== Valós típusok tárolására a float és a double típusok használhatók. Tartományuk az alábbi táblázatban látható: | double | 8 bytes | 4.9e-324 -- 1.7976931348623157e+308 | | float | 4 bytes | 1.4e-45 -- 3.4028235e+38 | A float egyszeres pontosságú számokat képres tárolni, míg a double dupla pontosságú számokat képes tárolni. A valós típusok használata: double a = 3.4d; double a = 3.4f; A double esetén elhagyható a szám végéről a "d" betűt: double a = 3.4; ==== Java karakterek ==== | char | 2 byte | A karaktereket a char segítségével definiálhatunk, amely egy darab karaktert szimbolizál, ami lehet egy betű, egy szám vagy valamilyen írásjel. Például: a vagy b vagy @ Az "a", "b" és "et" jel karaktereket jelentik. Ha meg akarok adni egy karaktert a Java nyelvben azt mindig aposztrófok között adjuk meg. Például: 'a' vagy: 'b' vagy: '@' Ezek után egy változót a következő módon tárolunk változóban: char ch; ch = 'a'; Gyakorlásként írjunk egy programot, amely egy-egy változóban eltárolja a következő betűket: "a", "l", "m", "a". Majd írassuk a képernyőre egy sorba: class Program { public static void main(String[] args) { char a = 'a'; char b = 'l'; char c = 'm'; char d = 'a'; System.out.print(a); System.out.print(b); System.out.print(c); System.out.print(d); } } ==== Logikai típus ==== A logikai változóknak két értéke lehet true és false. Deklarálásra a következő szót használom: boolean | boolean | 1 byte | Használata például: boolean van; van = true; A szelekciós vagy iterációs kifejezésekben hasznunkra lehetnek, lásd később a szelekciónál. ==== A float típus ==== float a = 3.87; Ebben a formában hibaüzenetet ad, mi szerint elveszítjük a pontosságot. Ezért egy "f" betűt kell a végére tenni. float a = 3.87f; ==== A primitív típusok csomagolóosztályai ==== A Java nyelvben nem minden objektum. Az adattípusok egy ilyen speciális csoportot alkotnak. Ezeket primitív típusoknak is szoktuk nevezni. ^ Primitív típus ^ Érték ^ Csomagoló osztály ^ Tartomány ^ | boolean | true, false | Boolean | true vagy false | | char | 16 bit-es Unicode | Character | \u0000 -- \uFFFF | | byte | 8 bit-es előjeles egész | Byte | -128 -- 127 | | short | 16 bit-es előjeles egész | Short | -32768 -- 32767 | | int | 32 bit-es előjeles egész | Integer | -2147483648 -- 2147483647 | | long | 64 bit-es előjeles egész | Long | -9223372036854775808 -- 9223372036854775807 | | float | 32 bit-es lebegőpontos | Float | 1.4E-45 -- 3.4028235E+38 | | double | 64 bit-es lebegőpontos | Double | 439E-324 -- 1.7976931348623157E+308 | A Java nyelvben minden típus előjeles (signed), azaz nincs előjel nélküli (unsigned) típus. A primitív típusok rendelkeznek egy nekik megfelelő csomagolóosztállyal (vagy burkoló osztály). ==== Egyenlőség ==== A következő program true értéket ír a képernyőre, mivel a két változó értéke egyenlő: double a = 3.0; double b = 3.0; System.out.println(a == b); Ha burkoló osztállyal hozom létre a változókat, az egyenlőség nem igaz: Double a = 3.0; Double b = 3.0; System.out.println(a == b); Az egyenlőség nem igaz, mert osztályok között az "==" operátor a két osztály hivatkozását hasonítja össze, nem az tartalmát. Burkoló osztály esetén használjuk az osztály equals() metódusát: Double a = 3.0; Double b = 3.0; System.out.println(a.equals(b)); ==== Típusok mérete és határa ==== Maximum értékek kiíratása: System.out.println(Byte.MAX_VALUE); System.out.println(Short.MAX_VALUE); System.out.println(Integer.MAX_VALUE); System.out.println(Long.MAX_VALUE); Minimum értékek kiíratása: System.out.println(Byte.MIN_VALUE); System.out.println(Short.MIN_VALUE); System.out.println(Integer.MIN_VALUE); System.out.println(Long.MIN_VALUE); Hány biten tároljuk az adott típust: System.out.println(Byte.SIZE); System.out.println(Short.SIZE); System.out.println(Integer.SIZE); System.out.println(Long.SIZE); A printf metódussal tizedestört formában is kiírhatók a lebegőpontos számok: System.out.printf("%f\n\n", Double.MAX_VALUE); Írjon programot, amelybe a fenti utasításokat helyettesíti be. Például: class Program01 { public static void main(String[] argv) { System.out.println(Byte.MIN_VALUE); } } ==== Típusok konverziója szélesítéssel ==== A típusok konverziója szélesítéssel angolul: **Automatic Type Promotion**. Ha van egy kisebb számokat tárolni képes változónk, annak értéke eltárolható egy nagyobb értékek tárolására képes változóban. Ezt nevezzük szélesítésnek. Ha eltárolom például egy 35-öt egy byte típusú változóban: byte a = 35; Később átadhatom az értéket egy short, int, long, stb. típusú változónak: byte a = 35; int b = a; Ezt azért tehetem, mert "b" változóban nagyobb szám tárolható mint az "a" változóban. Ezt nevezzük szélesítésnek. Fordítva azonban már nem lehetséges. Az alábbiakban az egyes típusokat látjuk milyen szélesítés alkalmazható rajtuk: * byte -> short, int, long, float, double * short -> int, long, float, double * char -> int, long, float, double * int -> long, float, double * long -> float double * float -> double Lássuk újabb példával: byte a = 3; short b = a; A példában 3-s számot az "a" változóban tároljuk először, az után szélesítést alkalmazunk meg "a" értékét egy olyan változóban tároljuk el, amely már nagyobb számok tárolására is képes. Vagyis, egy byte típusú változót tartalmát egy short típusúban tárolhatom, ehhez semmiféle konverzióra nincs szükség. {{:oktatas:programozas:java:tipusok_konverzioja_szelesitessel.png|}} ==== Típusok konverziója szűkítéssel ==== A szűkítés már kényesebb dolog. Az értéket olyan változóban szeretném tárolni amely kisebb számok tárolására alkalmas mint az eredeti. * short -> byte, char * char -> byte, short * int -> byte, short, char * long -> byte, short, char, int * float -> byte, short, char, int, long * double -> byte, short, char, int, long, float Példa: short a = 3; byte b = (byte) a; A példánkban a short nagyobb számok tárolására alkalmas, így nem írhatjuk le: b = a; Helyette típus kényszerítést használunk. A típuskényszerítés során zárójelbe tesszük annak a típusnak a nevét, amelybe szeretnénk átalakítani. Ha az egyenlőségjel baloldalán egy byte típus van, akkor zárójelbe azt írom "byte". A típuskényszerítést "kasztolás" névvel is használjuk. A kasztolás egyébként az angol casting szó magyarosan ejtése: casting [UK: ˈkɑːstɪŋ][US: ˈkæstɪŋ] esés, hajítás, horgászás, kimustrálás, öntés, öntvény, szereposztás, vetemedés, vetés. Eredeti formája: "type casting". A C nyelvben terjedt el használata. Egy újabb példa a kasztingra: double a = 3; int b = (int)a; Az "a" változó értékét kasztoljuk int típussá. ==== Literális ==== A literális egy olyan állandó, aminek nincs neve. Literális például a "3", az "a" betű, a "/" jel, bármi. Amikor leírjuk, hogy int a = 3; a három az egy literális állandó. Állandó, mert a program további részében ezt az adatott nem tudom megváltoztatni, és literális mivel nincs neve. Nem egy névvel hivatkozok rá, hanem beírtam úgy ahogy van. Literális a következő karakter, egyenlőség jel jobboldalán: char ch = 'a'; Literális a következő is: String s = "szilva"; Láthatjuk hogy a szám literálisokat csak úgy leírjuk, a karakterlitárálisokat felsővesszők közé tesszük, a karaktersorozat literálisokat pedig idézőjelek közé tesszük a Java nyelvben. ==== Gyakorlat ==== * Milyen primitív típusok vannak a Java nyelvben? * Lehet-e valós számokat tárolni egy int típusú változóban? * Lehet-e valós számokat tárolni egy double típusú változóban? * Eltárolható-e a 300-as egész érték egy byte típusú változóban? * Milyen értékeket vehet fel egy boolean típusú változó? * Írjon le minimum négy primitív típus, írja mellé milyen burkoló osztály tartozik hozz! ===== Java változók és állandók ===== ==== A változók elnevezése ==== A Java-ban a legkisebb tárolási egység. A változókat használat előtt deklarálni kell. double fizetes; double _fizetes; int fizetes; int $fizetes; long fizetes; boolean kesz; Nem használható változónevek: double 1salary; double %salary; int #holidays; Egy változó nem kezdődhet számmal, nem kezdődhet százalékjellel, nem kezdődhet kettős-kereszttel. A változók deklaráláskor értékét is definiálhatjuk: double fizetes = 70000; ==== A Java állandói ==== Eddig is használtunk állandókat, konkrétan literális állandókat. A következő állandók úgynevezett nevesített állandók. Azt vállaljuk, hogy a memóriaterületen elhelyezett értéket a program további részében nem fogjuk megváltoztatni. Ehhez a //final// kulcsszót fogjuk használni: class Program01 { public static void main(String args[]) { final int a = 5; System.out.println(a); } } A programunkban azt vállaljuk, hogy a program további részében az "a" nevű memóriahely tartalmát többet nem változtatjuk meg. class Program01 { public static void main(String args[]) { final int ALAPFIZETES = 200000; System.out.println(ALAPFIZETES); } } Az állandókat nagybetűvel szokás írni, hogy megkülönböztessük azokat a változóktól. Így a forráskódban azonnal felismerhető. ==== Kérdések és gyakorlat ==== === Kérdések === * Hogyan nevezzük az egyedváltozókat másként? * Hogyan nevezzük a statikus változókat másként? * A helyi változókat hol hozzuk létre? * Hol érvényesek a paraméterként létrehozott változók? * Hogyan deklarálunk egy nevesített állandót? * Mondjon vagy írjon példát literális állandóra. === Gyakorlat === - Készítsen egy programot, amely legalább 3 mezőt tartalmaz. Írja át a mezőneveket úgy, hogy ne legyen szabályos. Milyen hibaüzeneteket kap? - Az előző programban próbáljon meg mezőket úgy létrehozni, hogy nem ad kezdőértéket. ===== Értékadás ===== Értékadást egy darab (=) karater segítségével végzünk. A Java nyelvben előfordul két egyenlőségjel karakter is egymás után, annak azonban más jelentése van. Értékadáshoz csak egy darab karaktert használunk. Az egyenlőségjel baloldalán álló változó felveszi a jobboldalon álló számállandó, változó vagy kifejezés értékét. ==== Számállandók a jobboldalon ==== Float a = 3F; vagy kisbetűvel: Float a = 3f; Primitív típus egész számmal: float b = 3; Valós számmal már szükséges az "f" vagy "F" jelző: float b = 3.0f; Double c = 3.; double d = 3; Használhatjuk a "d" vagy "D" jelzőt: double d = 3.0d; ==== Változó a jobboldalon ==== float a = b; ==== Kifejezés a jobboldalon ==== float a = (b + c) * 3; A kifejezés operátorokat és operandusokat tartalmazó összeállítás. A példában a operandusok az egyenlőség jel jobb oldalán a "b", a "c" és a "3". Operátorok a záró és szorzójel. Értékadás esetén kifejezés nem állhat az egyenlőségjel baloldalán. A következő utasítás teljesen hibás: (b + c) * 3 = a; ==== Egész és valós számok ==== Nézzük meg a következő kifejezés hogyan lesz kiértékelve, mit ír a program a képernyőre: double a = 1 / 2; System.out.println(a); Az eredmény nulla, pedig 0.5 vártunk volna. Pedig egy double típusban tároljuk az eredményt. Mivel az értékadás jobboldalán csak egész számok szerepelnek az értékadás során a tört részek elvesznek. Ha legalább egy számot valós típusúvá teszünk az eredmény 0.5 lesz. double a = 1 / 2.0; System.out.println(a); A 2-es értéket valóssá számmá változtattuk azzal, hogy után írtunk egy pontot (.) és egy nullát (0). A nulla a Java nyelvben elhagyható: double a = 1 / 2.; System.out.println(a); Használhatjuk a számok után a f vagy a d jelzőt: double a = 1 / 2f; System.out.println(a); double b = 1 / 2d; System.out.println(b); ==== Gyakorlat ==== * Lehet-e egy egyenlőség jel baloldalán összeadni? * A Double típus esetén milyen jelzőt használunk a szám literális után? * A Float típus esetén milyen jelzőt használunk a szám literális után? * Float típus esetén kötelező a szám literális után megadni a jelzőt? ===== Formázott kivitel ===== Formázott kivitel esetén, amikor számot vagy egyéb érték használok, az egyszerű képernyőre írás helyett, apróbb formai változtatásokat hajtok végre. Ilyen lehet, hogy a számot, mindenképpen 10 helyen ábrázolom. Az üres helyeken vezető nullákat írok ki. Vagy 3 tizedesjegy pontossággal ábrázolok egy számot. Esetleg mindig ábrázolom az előjelt. Formázott kivitelt például a printf() metódussal lehetséges: System.out.printf("formátumkód", változó_állandó_vagy_kifejezés); Az első argumentum egy formátumszöveg (formátum-karaktersorozat) , amely tartalmaz egy formátumkódot. A második egy változó, egy állandó vagy egy kifejezés. A formátumkód szintaxisa: %[argumentum_index$][jelzők][szélesség][.pontosság]konverziós_karakter A formátumkód mindig százalékjellel (%) kezdődik és egy formátumkarakterrel (konverziós karakter) végződik. A formátumkaraktereket lásd alább. A formátumkód előtt és után bármi állhat a karaktersorozatban. ==== Argumentum index ==== Ha több argumentum is van, akkor megadhatjuk annak sorszámát, amelyet ki szeretnénk íratni. Az indexelés 1-gyel kezdődik. Az alábbi példában nem használjuk az argumentumindexet: System.out.printf("%d %d\n", 3, 4); Így a képernyőre a következő íródik: 3 4 Az argumentumindext használva a megfordításhoz: System.out.printf("%2$d %1$d\n", 3, 4); A következő a kimenet: 4 3 Ehhez persze elég lett volna a két érték felcserélése, ezért a legkevésbé használt lehetőség. ==== Szélesség ==== A kiírás szélessége. Egy egész szám, például: 10 System.out.printf("%10d\n", 35); A kiíratandó szám akárhány számjegyből áll, azt 10 helyen fogjuk ábrázolni, a a maradék hely szóközökkel lesz kitöltve. A tíz helyen a szám jobbra lesz igazítva. ==== Pontosság ==== A tizedes jegyek száma. Mindig egy ponttal (.) kezdődik. Például két tizedes jegy: .2 Valós számok esetén megadhatjuk a tizedesjegyek számát: System.out.printf("%.2f\n", 35.1234567); Egyszerre megadható az szám ábrázolásának szélessége és a tizedesjegyek száma is: System.out.printf("%10.2f\n", 35.1234567); ==== Ezredes elválasztó ==== A könnyebb olvashatóság érdekében nagyobb számok esetén ezredenként elválasztót szoktunk használni a számoknál. Amerikai szokás szerint ez egy vessző (,), de nálunk a magyar nyelvben ezt szóközökkel oldjuk meg. A Java nyelvben egy vessző megadásával vehetjük rá a programunkat az ezredeselválasztó használatára: System.out.printf("%,f\n", 32432344842.52334); ==== Több szám kiíratása ==== class Program { public static void main(String args[]) { int a = 45; int b = 27; System.out.printf("%d %d\n", a , b); } } class Program { public static void main(String args[]) { int a = 5; int b = 4; int c = 3; System.out.printf("%d %d %d\n", a , b, c); } } ==== Változók indexel megadva ==== Az egymás után megadott "a", "b", stb. változók kiíratásának sorrendje megváltoztatható: class Program { public static void main(String args[]) { int a = 45; int b = 27; System.out.printf("%d %d\n", a , b); System.out.printf("%2$d %1$d\n", a , b); } } Egy dollár jel előtt megadjuk, melyik indexű változó kiíratására gondoltunk. Ezzel persze egy változó többször is kiíratható. A következő példában az "a" változó tartalmát kétszer is kiíratom. class Program { public static void main(String args[]) { int a = 45; int b = 27; System.out.printf("%d %d\n", a , b); System.out.printf("%2$d %1$d %1$d\n", a , b); } } A váltózók indexei 1-gyel kezdődnek. ==== Jelzők ==== | + | előjel | | - | balra igazítás (csak szélesség meghatározással, így van értelme) | | 0 | vezető nullák megjelenítése | | , | ezredes tagolás | | # | alternatív formátum megjelenítése (csak o, x és X esetén) | | ' ' | egy vezető szóköz pozitív számok számára (csak: 'd', 'o', 'x', és 'X' esetén) | | '(' | negatív számok zárójelbe kerülnek (csak: 'e', 'E', 'f', 'g', és 'G esetén) | A jelzők sorrendje felcserélhetők. Az összes jelző alkalmazás lehetséges, de előfordul, hogy az egyik jelző használat értelmetlen a másik mellett. Az ezredeselválasztó Linuxon gond nélkül működik, Windowson Unicode fontokat kell beállítani, másként nem működik. ==== Konverziós karakter ==== A formátumkódot mindig egy konverziós karakter zárja . Az alábbi táblázatban láthatjuk a lehetséges formátumkódokat. ^ Konverziós \\ karakter ^ Kategória ^ Leírás ^ | 'b', 'B' | elsődleges | Ha az argumentum null, akkor visszatérés "false". Az argumentum \\ boolden vagy Booldan, akkor a visszatérés String.valueOf(). \\ Ellenkező esetben a vissztérés "false". | | 'h', 'H' | elsődleges | Ha az argumentum null, akkor a visszatérés is null. Egyébként a \\ visszatérés Integer.toHexString(arg.hashCode(). | | 's', 'S' | elsődleges | Ha az argumentum null, akkor a visszatérés is null. Ha az argumentum \\ formázást valósít meg akkor a formázás érvényesül. \\ Minden más esetben az argumentumon karaktersorozattá alakul toString() | | 'c', 'C' | karakter | Visszatér egy Unicode karakterrel | | 'd' | átalakító | Visszatér egy formázott decimális egésszel. | | 'o' | átalakító | Visszatér egy formázott oktális egésszel. | | 'x', 'X' | átalakító | Visszatér egy formázott hexadecimális egésszel. | | 'e', 'E' | lebegőpontos | Visszatér egy formázott decimális számmal \\ tudományos formában. | | 'f' | lebegőpontos | Visszatér egy formázott decimális számmal. | | 'g', 'G' | lebegőpontos | Visszatér egy formázott tudományos formával vagy decimális \\ formával, a kerekítés utáni érték pontosságától függően. | | 'a', 'A' | lebegőpontos | Visszatér egy formázott hexadecimális lebegőpontos számmal, \\ alappal és a kitevővel. | | 't', 'T' | idővel kapcsolatos | Dátum és konverziós karakterek előtagja. \\ Lásd a dátum és idő konverziót. | | '%' | százalék | Visszaad egy '%' literálist '\u0025') | | 'n' | sorelválasztó | Visszatér egy platformspecifikus sortöréssel. | ==== Példák ==== double a = 2,7183; System.out.printf("Szám: %+10.4f", a); // " Szám = +2,7183" System.out.format("Hatvany: %.2f\n", b); ==== Idő kiíratás ==== Az óra, perc, másodperc kiíratása: System.out.printf("%tT\n", java.util.Calendar.getInstance()); Az év kiíratása: System.out.printf("%tY\n", java.util.Calendar.getInstance()); Az óra kiíratása: System.out.printf("%tH\n", java.util.Calendar.getInstance()); import java.util.Calendar; class Program { public static void main(String args[]) { Calendar datum = Calendar.getInstance(); System.out.printf("%tH\n", datum); } } Még több példa: Calendar c = Calendar.getInstance(); // --> "May 29, 2006" System.out.format("%tB %te, %tY%n", c, c, c); // --> "2:34 am" System.out.format("%tl:%tM %tp%n", c, c, c); // --> "05/29/06" System.out.format("%tD%n", c); ==== Sortörés ==== Mint azt fentebb láttuk sortörést lehet kiíratni a println() metódussal, de az '\n' escapeszekvencia is használható erre a célra. Ugyanezt tehetjük meg a "%n" segítségével. Az aktuális operációs rendszer sortörésének kiíratása: System.out.format("%f%n%n", 455.3823); ==== A Formatter osztály használata ==== import java.io.*; import java.util.*; class Forma { public static void main(String args[]) throws IOException { Formatter formazo = new Formatter(); formazo.format("%s %d %f", "Java", 10, 97.5); System.out.println(formazo); System.in.read(); } } A Formatter osztály a java.util csomagban található. ==== DecimalFormat osztály ==== import java.text.DecimalFormat; class Program { public static void main(String args[]) { DecimalFormat sajatForma = new DecimalFormat("###,###.###"); System.out.format(sajatForma.format(123456.789)); } } ==== Console osztály használata ==== import java.io.Console; class Program3 { public static void main(String args[]) { Console konzol = System.console(); konzol.printf("Helló Világ!\n"); } } ==== Gyakorlat ==== * Mikor használjuk a formázott kivitelt? * Mi a formátumkód? * Mi a formátumkarakter? * Milyen formátumkóddal írathatunk ki egész számokat? * Mit jelent a formátumkódban a %? * Milyen formátumkóddal írathatunk ki karaktereket? * Írjon példát, hogyan határozza meg, hogy egy "a" változóban tárolt valós szám, három tizedesjegy pontossággal íródjon ki. * Milyen formátumkóddal írathatunk ki valós számokat? * Milyen formátumkóddal írathatunk ki karaktersorozatokat? ===== Math osztály ===== ==== Használat ==== A Math osztály olyan metódusokat tartalmaz, amelyek megkönnyítik a matematikai feladataink megoldását. Ilyenek az abszolút érték számítása, gyökvonás, hatványozás, trigonometriai függvények számítása, stb. A Math osztály importálás és példányosítás nélkül azonnal rendelkezésünkre áll. A következő példában -15 abszolút értékét számítjuk ki. import java.io.*; class Matek { public static void main(String args[]) throws IOException { System.out.format("%d\n", Math.abs(-15)); System.in.read(); } } ==== Abszolút érték ==== Egy szám abszolút értékét adja vissza. Ha megnézzük a Java API dokumentációt ehhez hasonlókat láthatunk: double abs(double a) float abs(float a) int abs(int a) long abs(long a) Ebből tudhatjuk, hogy az abs metódusnak négy módon használhatjuk. Megadhatunk paraméterként double, float, int vagy long típust. Ha double adunk meg double típust ad vissza. Ezt az első sorból látjuk: double abs(double a) A "double a" mutatja, hogy milyen bemenő paraméter jöhet szóba, az elején a "double" pedig azt mutatja milyen értéket ad vissza a metódus. ==== Hatvány ==== Hatvány számítása: double a = Math.pow(3, 2); Az első szám alap, a második a kitevő. double b = 1; ==== Gyökvonás ==== Adott szám gyökével tér vissza. System.out.println(Math.sqrt(9)); ==== Trigonometria ==== double c = Math.sin(b * Math.PI / 180); double d = Math.sin(Math.toRadians(b)); System.out.printf("Szinusz : %.5f\n", c); System.out.printf("Szinusz : %.5f\n", d); A trigonometriai függvények radiánban várják az értékeket. A bemenő paramétert ezért át kell konvertálni előbb radiánba. ^ Függvények ^ | double sin(double a) | | double tan(double a) | | double cos(double a) | | double asin(double a) | | double acos(double a) | | double atan(double a) | | double atan2(double a) | ==== Pi ==== System.out.println(Math.PI); A PI nem függvény! Tulajdonság! ==== Euler-féle szám ==== Az Euler-féle szám (jele: e) egy matematikai állandó, amit a természetes logaritmus alapja System.out.println(Math.E); Az E nem függvény! Tulajdonság! ==== max ==== Két szám közzül a nagyobbat adja vissza: System.out.println(Math.max(7,4)); ==== min ==== Két szám közül a kisebbet adja vissza: System.out.println(Math.min(7,4)); ==== round ==== A round a tizedes törtet kerekíti. .4-től lefele, .5-től felfele: System.out.println(Math.round(1.5)); Eredménye: 2 System.out.println(Math.round(1.4)); Eredménye: 1 ==== ceil ==== A ceil függvény a tizedes törtet felfelé kerekíti. System.out.println(Math.ceil(1.0)); Eredménye: 1 System.out.println(Math.ceil(1.1)); Eredménye: 2 ==== floor ==== A floor függvény a tizedes törtet lefelé kerekíti. double floor(double a) Két példa: System.out.println(Math.floor(1.1)); Eredménye: 1 System.out.println(Math.floor(1.9)); Eredménye: 1 ==== toDegrees ==== Radiánfok átszámítása szögfokká. Math.toDegrees(85); ==== toRadians ==== Szögfok átszámítása radiánfokká. Math.toRadians(85); ==== Exponenciális ==== Az exponenciális függvény ex vagy exp(x), ahol e egy matematikai állandó, a természetes alapú logaritmus alapja, értéke körülbelül 2,718281828, és Euler-féle szám double exp(double a) ==== Logaritmus ==== A hatványozás egyik megfordított (inverz) művelete === log(a) === double log(double a) A log() a szám természetes logaritmusát adja. A matematikában ln(x) a jelölése. === log10(a) === double log10(double a) A log10() a szám 10 alapú logaritmusát adja. A matematikában a lg(x) a jelölése. === log1p(x) === double log1p(double x) A log1p a szám és 1 összegének logaritmusát adja. ==== Gyakorlás ==== * Milyen értéket várnak a trigonometriai függvények? Radián vagy szög? * Milyen metódussal számítható át szögfok radiánra? * A log(a) melyik logaritmust típust számítja ki? * Melyik metódussal kerekíthetünk a tört részeket felfelé? * Melyik metódussal kerekíthetjük a tört részeket lefelé? * Melyik metódussal tudunk a kerekítés szabályai szerint kerekíteni? * A log(a) függvénynek milyen típusú a bemenőparamétere és a visszatérési értéke? ===== Véletlen szám generálás ===== A véletlenszámok előállítására két osztály áll rendelkezésünkre. A Random és a Math. ==== Random osztály ==== Az eddig használt osztályok a java.lang csomagban voltak, amit nem kellett importálni. A Random osztály az eddigiektől eltérően importálni kell, a java.util csomagban található. Használni sem használhatjuk csak példányosítással. A példányosítás azt jelenti létrehozunk az osztályból egy példányt. //Az osztályok hasonlítanak például a "dolgozó" fogalomhoz. Ha azt mondom "dolgozó" az nem egy konkrét személy, konkrét ember, akár ki lehet. Ha azt mondom a Jóska nevű dolgozó akkor már konkretizáltam. A Jóska tulajdonképpen a dolgozó egy példánya. A Java nyelvben ehhez használjuk az osztályokat. Az osztály egy általános dolog. Ha példányosítom akkor, létrehoztam az adott osztály egy példányát. A létrehozott példányt objektumnak nevezzük. Az előbbi "dolgozó" analógiában az objektum a "Jóska példánynak" felel meg.// A Random osztályt példányosítani kell használat előtt, azt pedig a new utasítással tudjuk megtenni. Lássunk a példányosításra egy példát: Random veletlen = new Random(); A példánkban kitaláltunk egy objektum nevet, ez a "veletlen". A példányosítás utn a "veletlen" egy olyan objektum, amelyet a Random osztályból hoztunk létre a "new Random()" kifejezés segítségével. A háttérben, tulajdonképpen a memóriában egy "veletlen" nevű objektumnak foglaltunk helyet a "new Random()" kifejezéssel. A Random osztály importálása: import java.util.Random; A Random osztály példányosítása veletlen objektum létrehozásával: Random veletlen = new Random(); A veletlen objektum használata: int szam = veletlen.nextInt(3); A Random osztály egyik metódusa a nextInt(). A nextInt() metódus egy véletlen számot generál, ha meghívjuk a veletlen objektumon. A példánkban a generált számot a "szam" nevű változóban tároljuk. A nextInt() metódusnak paraméterként 3-at megadva 0 és 2 közötti értéket kaphatunk. 1 és 6 közötti szám előállítása ezek után: Random veletlen = new Random(); int dobas = veletlen.nextInt(6) + 1; A következő táblázatban a Random osztály további metódusait láthatjuk. A "veletlen" objektum helyett, azonban csak egy "r" nevű objektumot használunk a rövidség miatt. ^ Visszatérés típusa ^ Hívás ^ Leírás ^ | int i = | r.nextInt(int n) | int >= 0 és < n közötti véletlen számot ad vissza | | int i = | r.nextInt() | a teljes int tartományból ad vissza véletlen számot | | long l = | r.nextLong() | a teljes long tartományból ad vissza véletlen számot | | float f = | r.nextFloat() | float >= 0.0 és < 1.0 közötti véletlen számot ad vissza | | double d = | r.nextDouble() | double >= 0.0 és < 1.0 közötti véletlen számot ad vissza | | boolean b = | r.nextBoolean() | true vagy false értékkel tér vissza véletlenszerűen | | double d = | r.nextGaussian() | 0.0 és szabályos eltéréssel 1.0 közötti véletlen eltéréssel tér vissza | ==== Math osztály ==== A Math.random() 0.0...0.999999 között állít elő egy számot. double a = Math.random(); System.out.printf("%.20f\n", a); A következő kimenetet adja: 0,509873801078128200000 Ha négyel szoroztam volna a számot: double a = Math.random(); System.out.printf("%.20f\n", a * 4); Kimenet például: 2,03949520431251270000 A szám egész része egy 0 és 3 közötti szám. Ebből lehet egy egész véletlen számom. Esetleg így is írhatjuk: double a = 4 * Math.random(); System.out.println(a); Ha mindig hozzáadunk 1-t, akkor 1 és 4 közötti számot kapunk: double a = 4 * Math.random() + 1; System.out.println(a); Példa 1 és 10 közötti egész szám előállítására: szam = (int) (10 * Math.random()) + 1; ==== Gyakorlat ==== * Mit állít elő a Math.random() metódus? * Generáljon 10 és 20 között egy számot. * Milyen osztályokkal állíthatunk elő véletlen számokat? * Mondjon két példát a Random osztály metódusaira. * Szükséges-e példányosítani a Random osztályt használatához? ===== Java operátorok ===== ==== Operátorok ==== === Értékadó operátor === | = | Egyszerű értékadás | Az értékadást általánosan így írhatjuk le: = Lássunk néhány konkrét példát a használatára: int a, b; a = 2; // 2 értéket hozzárendeljük az a változóhoz b = 5; // 5 értéket hozzárendeljük a b változóhoz Home home1 = new Home(); // új objektum készítése Home home2 = home1; // home1 referencia home2-be rendelése === Aritmetikai operátorok === | + | összeadás (karaktersorozatok összefűzésére is használjuk | | - | kivonás | | * | szorzás | | / | osztás | | % | maradékképzés | === Egyoperandusú operátorok === | + | Unary plusz operator; az értéket adja | | - | Unary mínusz operator; előjelet vált, vagyis az értéket negálja | | ++ | inkrementáló operátor; az inkremens értéke: 1 | | -- | dekrementáló operátor; a dekremens értéke: 1 | | ! | logikai ellentét; a logikai értéke ellentétes értékét adja | A (+) egyoperandusú operátort a C nyelvben tették szabvánnyá először a (-) operátor ellentéteként csak a szimetria kedvéért. A (+) operátor használata így nem tesz semmit az értékkel, azt kapjuk ami van. A (!) operátor az ellentétére fordít egy logikai értéket. A true értékből false értéket csinál és fordítva. Teszteljük a következő programmal: System.out.println(true); System.out.println(!true); System.out.println(false); System.out.println(!false); === Egyenlőség és összehasonlító operátorok === | == | egyenlő | | != | nem egyenlő | | > | nagyobb mint | | >= | nagyobb vagy egyenlő | | < | kisebb mint | | <= | kisebb vagy egyenlő | Less than or equal to Az egyenlő operátor visszaad egy true vagy false értéket, attól függően igaz-e amit állítunk. int a = 4; System.out.println(a == 3); A következő program ugyanígy true vagy false értéket ír ki, de most az ellentétére kérdezünk: int a = 4; System.out.println(a != 3); A többi logikai operátor is hasonlóan használható. === Feltételes operátorok === | && | feltételes ÉS | | || | Feltételes VAGY | | ?: | Hármas operátor (az if-then-else rövid változata) | Az && operátor feltételes ÉS, amelyet két logikai állítás között szoktunk használni. A következő példában két állítást teszünk. Először azt állítjuk, hogy az "a" értéke 3, majd b értéke 4. Ha mindkettő igaz lenne, akkor kapnánk igaz értéket a teljes kifejezésben: int a = 4; int b = 4; System.out.println(a == 3 && b == 4); A példánkban false értéket kapunk, mert az a változóban nem 3-as érték szerepel. === Típusvizsgáló operátor === | instanceof |Egy objektumot egy megadott típushoz hasonlít | === Bitmozgató és bitenkénti operátorok === | ~ | komplemensképzés bitenként (unary; egyoperandusú) | | << | előjeles balra mozgatás (shift) | | >> | előjeles jobbra mozgatás (shift) | | >>> | előjel nélküli jobbra mozgatás (shift) | | & | bitenkénti ÉS | | | | bitenkénti VAGY | | ^ | bitenkénti Kizáró VAGY | ==== Precedencia ==== Ha egy kifejezésben több operátor is van, akkor el kell dönteni, mi lesz az operátorok végrehajtásának sorrendje. Ezt nevezzük precedenciának. Az alábbiakban a Java nyelv precedencia táblázatát látjuk: | ++ -- \\ ! ~ \\ instanceof | (pre- vagy poszt-) inkremens és dekremens, \\ logikai és bitenkénti negálás, \\ típus ellenőrzés | | * / % | szorzás, osztás, moduló | | + - | összeadás, kivonás | | << >> >>> | bitenkénti léptetések | | < > >= <= | összehasonlítások | | == != | egyenlő, nem egyenlő | | & | bitenkénti AND | | ^ | bitenkénti XOR | | | | bitenkénti OR | | && | logikai AND | | || | logikai OR | | ? : | feltételes kifejezés | | = += -= *= /= %= ^= \\ &= |= <<= >>= >>>= | különböző értékadások | A táblázatban legfelül látjuk azokat amelyek hamarabb végrehajtásra kerülnek. Mi történik akkor, ha azonos precedenciaszintű operátorokból van több? Ebben az esetben azok balról jobbra, sorba egymás után hajtódnak végre. Lássunk egy példát: int szam = 1 + 2 + 3; System.out.println(szam); Az utasítások balról jobbra végrehajtódnak, de nekünk persze mindegy, mert az eredmény ugyanaz, ha először a második összeadás hajtódik végre. A következő példában viszont nem mindegy melyik operátor hajtódik először végre: int szam = 1 + 2 * 3; System.out.println(szam); Ebben az esetben először a szorzás hajtódik végre, majd az összeadás. A zárójelekkel azonban ezen változtathatunk: int szam = (1 + 2) * 3; System.out.println(szam); Először a zárójelen belüli összeadás kerül végrehajtásra, majd a szorzás. ==== Az inkrementáló és dekrementáló operátorok ==== Adott a következő Java programrészlet: int a = 3; b = a++; Jó kérdés lehet, hogy milyen érték kerül a b változóba. A kérdés úgy is feltehető, hogy az "++" operátor mikor növeli az "a" változó értékét? Mielőtt átadja az értékét "b" változónak, vagy csak utána. A helyes válasz csak utána. A b változóba tehát 3 kerül, utána növeli a ++ operátora az "a" változó tartalmát. Ezzel ellentétes viselkedés is elérhető, ha az ++ operátort nem a változó utána, hanem az előtt szerepeltetjük: int a = 3; b = ++a; Ebben az esetben a "b" változó értéke 4 lesz, mivel az operátor előbb növelte "a" értékét, majd ez az érték került átadásra. A "--" operátor használata megegyezik a "++" használatával, ebből a szempontból. ==== Bitműveletekre példa ==== class Program02 { public static void main(String[] args) { int a = 3; int b = ~a; System.out.printf("%32s\n", Integer.toBinaryString(a)); System.out.printf("%32s\n", Integer.toBinaryString(b)); } } //Előjeles balra mozgatás (baloldalon mindig az előjel bit jön be) class Program01 { public static void main(String[] args) { int a = 3; //Próbáljuk ki negatív értékkel int b = a << 2; System.out.printf("%4s\n", Integer.toBinaryString(a)); System.out.printf("%4s\n", Integer.toBinaryString(b)); } } //A baloldali első bit az előjel bit negatív számok esetén 1, pozitív esetén 0. //Előjel nélküli jobbra mozgatás (baloldalon mindig 0 jön be) class Program03 { public static void main(String[] args) { int a = 14; int b = a >>> 1; System.out.printf("%32s\n", Integer.toBinaryString(a)); System.out.printf("%32s\n", Integer.toBinaryString(b)); } } //Előjeles jobbra mozgatás class Program03 { public static void main(String[] args) { int a = 14; int b = a >> 1; System.out.printf("%32s\n", Integer.toBinaryString(a)); System.out.printf("%32s\n", Integer.toBinaryString(b)); } } ==== Feltételes értékadás ==== A feltételes operátor tulajdonképpen az if-then-else hasonlata. Van egy feltétel a kérdőjel előtt. Ha igaz, akkor az első értéket kapj az egyenlőség baloldalán álló "b" változó. Ne nem igaz, akkor a kettőspont utáni értéket kapja. class Program { public static void main(String[] args) { int a = 8; String b = a > 5 ? "Nagyobb" : "Kisebb"; System.out.println(b); } } ==== Az instanceof operátor ==== class Program01 { public static void main(String[] args) { Integer a = 3; System.out.println(a instanceof Integer); } } Primitív típussal nem működik a instanceof operátor! A mellékletek részben találunk egy sokkal hasznosabb példát az operátor használatára. A jelen példának azért nincs sok értelme, mert az Integer helyett nem is tudunk mást írni. ==== Művelettel kombinált értékadás ==== Legyen egy "a" változó, amelynek értékét szeretnénk 2-vel növelni. Ekkor ezt írnánk: int a = a + 2; Ennek van egy rövidebb formája: int a += 2; A plusz jelet az egyenlőség jel elé tesszük, az "a" változóba pedig csak egyszer írom le. Lehetséges kombinált értékadó operátorok: += -= *= /= %= &= ^= |= <<= >>= ==== Ternary ==== Hármas operátor. Ennek az operátornak három operandusa van, ezért a neve. Az operátor egy kérdőjelből és egy kettőspontból áll: ? : Használatát lásd a szelekciónál. ==== Gyakorlat ==== * A bitenkéni AND vagy a logikai AND van előrébb a prioritási sorban? * A logikai AND vagy a logikai OR van a prioritási sorban előbb? * Mire való az instaceof változó? * Mutassa be hogyan működik a feltételes értékadás. * Mi a különbség a >> és a >>> operátor között? ===== Konvertálás ===== ==== Sztring egész számmá ==== System.out.println(Integer.parseInt("89")); String s = "25"; int a = Integer.valueOf(s).intValue(); A valueOf() egyik prototípusa: static Integer valueOf(String s) Visszatér egy karaktersorozat számértékével egy Integer objektumban eltárolva. Az intValue() metódussal primitív int típussá alakítjuk. Az intValue()prototípusa: int intValue() String s = "87"; System.out.println(Integer.parseInt(s)); Szöveges formában tárolt valós számot alakítunk egésszé. int a = Float.valueOf( "799.87" ).intValue(); ==== Sztring valós számmá ==== System.out.println(Double.parseDouble("89.5")); Double d = Double.valueOf(str).doubleValue(); Float f = Float.valueOf(str).floatValue(); ==== Sztring hosszú egésszé ==== long l = Long.valueOf(str).longValue(); Long l = Long.parseLong(str); ==== Egész sztringgé ==== System.out.println(Integer.toString(77)); ==== Valós sztringgé ==== System.out.println(Float.toString(77.88)); ==== Dupla sztringgé ==== System.out.println(Double.toString(77.88)); double a = 3; System.out.println(Double.toString(a)); ==== Hosszú egész sztringgé ==== Long a = 7L; String str = Long.toString(a); ==== Hexadecimális sztring egésszé ==== int a = Integer.valueOf("B8DA3", 16).intValue(); int a = Integer.parseInt("B8DA3", 16); A következő sor például a 11-et ír a képernyőre: System.out.println(Integer.parseInt("B", 16)); ==== Karakter sztringgé ==== String s = String.valueOf('c'); ==== Karakter ASCII kóddá ==== char ch = 'A'; int b = ch; System.out.println(b); //Az eredmény: 97 vagy: char ch = 'A'; int b = (int) ch; System.out.println(b); //Az eredmény: 97 ==== Egész (ASCII kód) karakterré ==== int a = 97; char ch = (char)a; System.out.println(ch); //Az eredmény: a ==== Sztring ASCII kóddá ==== String str = "ABCD"; for ( int i = 0; i < str.length(); ++i ) { char c = str.charAt(i); int j = (int) c; System.out.println(j); } ==== Egész logikai típussá ==== int a = 2; boolean b = (a != 0); A nulla érték mindig hamis lesz. Az ettől eltérő pedig igaz. ==== Logikai típus egésszé ==== boolean a = true; int b = a ? 1 : 0; A true és a false a következő módon alakul át: * true --> 1 * false --> 0 ==== Illegális karakterkonverzió vizsgálata try/catch mechanizmussal ==== try { a = Integer.parseInt(str); } catch(NumberFormatException e) { } ==== Sztring bájt formára konvertálása ==== String s = "some text here"; byte[] b = s.getBytes("UTF-8"); ==== Bájt Sztring formára konvertálása ==== byte[] b = {(byte) 99, (byte)97, (byte)116}; String s = new String(b, "US-ASCII"); Az US-ASCII helyett lehet "UTF-8" is ==== Valós egészé ==== Double a = 3.8; int b = Double.valueOf(a).intValue(); Float a = 3.8f; int b = Float.valueOf(a).intValue(); double a = 3.8; int b = (int) a; ==== Egyéb lehetőség ==== === Decimális binárissá === import java.io.*; class Konvert { public static void main(String args[]) throws IOException { int i = 2; String bin = Integer.toBinaryString(i); System.out.println(bin); System.in.read(); } } === Decimális hexadecimálissá === import java.io.*; class Konvert { public static void main(String args[]) throws IOException { int i = 11; String bin = Integer.toBinaryString(i); System.out.println(bin); String hexstr = Integer.toHexString(i); System.out.println(hexstr); System.in.read(); } } ==== Bináris string számmá ==== String s = "1000100010000000"; int a = Integer.parseInt(s, 2); ==== Gyakorlat ==== * Hogyan konvertálunk karaktersorozatot egész számmá? * Hogyan konvertálunk karaktersorozatot egész valós? * Hogyan konvertálunk valós számot karaktersorozattá? * Hogyan konvertálunk egész számot karaktersorozattá? * Hogyan konvertálunk karaktert karaktersorozattá? ===== Bevitel a billentyűzetről ===== A Java nyelven az olvasás a billentyűzetről nem egyszerű feladat. Van ugyan az in mezőnek egy read() metódusa, de az csak egyetlen bájtot olvas be. Ha ezzel kérnénk be egy számot, azt utána még át kellene konvertálnunk számmá. A System.in.read() metódust így legfeljebb arra használjuk, hogy várjunk egy "Enter" lenyomására. ==== Az util csomag használata ==== A Netbeans és Maven együttes használata esetén a normál futtatás hibásan működik. A bekérés szövege csak később jelenik meg. Használjunk Maven helyett Ant-t. Másik megoldás lehet a projekten jobb egér gomb "Run Maven" > Goals. Majd töltsük ki: * Goals: exec:java * egy_létező-profile * exec.mainClass=and.zold.main.Main Megoldás lehet még, a java.io csomag osztályainak használata. === Egy egész szám bekérése === import java.util.Scanner; class Program01 { public static void main(String args[]) { Scanner bevitel = new Scanner(System.in); System.out.print("Egész szám: "); int a = bevitel.nextInt(); System.out.println(a); } } === Egy valós szám bekérése === import java.util.Scanner; class Program02 { public static void main(String args[]) { Scanner bevitel = new Scanner(System.in); System.out.print("Valós szám: "); double b = bevitel.nextDouble(); System.out.println(b); } } === Egy karaktersorozat bekérése === import java.util.Scanner; class Program03 { public static void main(String args[]) { Scanner bevitel = new Scanner(System.in); System.out.print("Szöveg: "); String s = bevitel.nextLine(); System.out.println(s); } } === Egész és valós bekérése === import java.util.Scanner; class Program04 { public static void main(String args[]) { Scanner bevitel = new Scanner(System.in); System.out.print("Egész szám: "); int a = bevitel.nextInt(); System.out.print("Valós szám (vesszővel írjuk a tizedesvesszőt): "); double b = bevitel.nextDouble(); System.out.println(a + b); } } === Két karakter sorozat bekérése === import java.util.Scanner; class Program05 { public static void main(String args[]) { Scanner bevitel = new Scanner(System.in); System.out.print("Szöveg: "); String s1 = bevitel.nextLine(); System.out.print("Szöveg: "); String s2 = bevitel.nextLine(); System.out.println(s1 + " " + s2); } } === Karakter bekérése === A Scanner osztállyal nem tudunk közvetlenül char vagy Character típust bekérni, bár megtehetjük, hogy egy beolvasott karaktersorozat első elemét vesszük: import java.util.Scanner; class Program06 { public static void main(String args[]) { Scanner olvaso = new Scanner(System.in); char ch = olvaso.nextLine().charAt(0); System.out.println("Olvasott: " + ch); } } === Ékezethelyes beolvasás === A fenti példákban láttuk, hogy Scanner osztály remek lehetőség a bekérésekre. Ha viszont magyar ékezetes betűket írunk bekéréskor Windowson, azok hibásan jelennek meg, mivel a felület ahol a bekérés történik 852-s kódlappal dolgozik, és erről nem tud a Scanner osztály. Lehetőség van, azonban arra, hogy megadjuk mi beviteli környezet kódlapja. A kódlapok a következők lehetnek: * 852 (közép-európai környezetben, parancssorban) * cp1250 -- Windows-1250 (közép-európai környezetben) * cp1252 -- Windows-1252 (nyugat európai környezetben) Ha parancsablakban fut a program, 852 bemenet beállítása: Scanner sc = new Scanner(System.in, "852"); Ha Windows ablakban fut a program, cp1250 bemenet beállítása: Scanner sc = new Scanner(System.in, "cp1250"); Ha szeretnénk operációs rendszertől függővé tenni a kódlap beállítást, akkor használhatjuk a System osztály getProperty() metódusát. System.out.println(System.getProperty("os.name")); Az OS megállapítása: String os = System.getProperty("os.name").toLowerCase(); if(os.indexOf("win") >= 0) { System.out.println("Windows"); }else if(os.indexOf("nix") >=0 || os.indexOf("nux") >=0 || os.indexOf("aix") >0) { System.out.println("Unix"); }else if(os.indexOf("mac") >= 0) { System.out.println("Mac"); } ==== Az io csomag használata ==== Az io csomagból a BufferedReader és az InputStreamReader osztályokat vesszük segítségül. Az io csomag osztályait nem használhatjuk kivételek feldolgozása nélkül. A metódust felkészíthetjük, hogy kezelje a kivételt, vagy rávesszük, hogy dobja el azt. A példaprogramunkban kivételeket nem kezelünk, eldobjuk őket. Az eldobáshoz a metódus fejrészének a végére írjuk: "throws IOException. import java.io.*; public class Program01 { public static void main(String[] args) throws IOException { InputStreamReader befolyam = new InputStreamReader(System.in); BufferedReader bemenet = new BufferedReader(befolyam); String s; int szam; System.out.print("Szám: "); s = bemenet.readLine(); szam = Integer.valueOf(s).intValue(); System.out.println("Ezt írtad: " + szam); } /* main vége */ } /* Fő osztály vége*/ Amit még felfedezhetünk, hogy a bekéréshez két osztály szükséges. A következő kód megegyezik az előzővel, de az InputStreamReader deklarációt beágyaztuk a BufferedReader részbe. import java.io.*; public class ap { public static void main(String[] args) throws IOException { BufferedReader bemenet = new BufferedReader(new InputStreamReader(System.in)); String s; int szam; System.out.print("Szám: "); s = bemenet.readLine(); szam = Integer.valueOf(s).intValue(); System.out.println("Ezt írtad: " + szam); } /* main vége */ } /* Fő osztály vége*/ import java.io.*; class Program { public static void main(String args[]) { Console console = System.console(); System.out.print("Szöveg: "); String str = console.readLine(); System.out.println(str); } } ==== System.console() metódus ==== Beolvasásra használható a System.console() metódus. Ez a metódus egy Console osztályt ad vissza, amelyen van egy readLine() metódusa, amely már alkalmas beolvasásra. class Program01 { public static void main(String args[]) { System.out.print("Név: "); String nev = System.console().readLine(); System.out.println("Ezt írtad: " + nev); } } A bekéréssel együtt írhatunk is a képernyőre a bekérés előtt: class Program04 { public static void main(String[] args) { String szamStr = System.console().readLine("Kerek egy szamot: "); System.out.println("Ezt irtad: " + Integer.parseInt(szamStr)); } } A readLine() valójában formázott bemenetre képes. ==== Console osztály ==== === Karaktersorozat bekérése === import java.io.Console; class Program { public static void main(String args[]) { Console kon = System.console(); System.out.print("Név: "); String szoveg = kon.readLine(); System.out.println("Neved: " + szoveg); } } === Egész szám bekérése === import java.io.Console; class Program { public static void main(String args[]) { Console kon = System.console(); System.out.print("Szam: "); int szam = Integer.parseInt(kon.readLine()); System.out.println("Duplája: " + szam * 2); } } ==== Karakterek bekérése ==== char ch; System.out.print("Karakter: "); ch = (char) System.in.read(); System.in.read(); System.out.println("A beírt karakter: " + ch); System.out.print("Karakter: "); ch = (char) System.in.read(); System.in.read(); System.out.println("A beírt karakter: " + ch); System.out.print("Karakter: "); ch = (char) System.in.read(); System.out.println("A beírt karakter: " + ch); Ha több karaktert kérünk be az első karakter leütése után a leütött "Enter" a billentyűzet pufferben marad. Így következő billentyűzetről olvasás nem vár billentyűnyomásra, hanem tovább lép. Ezt az "Enter" billentyűt kiolvassuk a bekérés után tett System.in.read() utasítással. Komplett példa: import java.io.*; class Program { public static void main(String args[]) throws IOException { System.out.print("Karakter: "); char ch1 = (char) System.in.read(); System.in.read(); System.out.print("Karakter: "); char ch2 = (char) System.in.read(); System.in.read(); System.out.print("Karakter: "); char ch3 = (char) System.in.read(); System.in.read(); System.out.println("A beírt karakterek: " + ch1 + " " + ch2 + " " + ch3); } } Karakterbekérés két másik módja: ch = (char) System.console().reader().read(); //Java 6 A következő megoldás nem hagyja az Entert a billentyűzetpufferben. ch = (char) new InputStreamReader(System.in).read(); import java.io.*; class Program { public static void main(String args[]) throws IOException { char ch; System.out.print("Karakter: "); ch = (char) System.console().reader().read(); System.console().reader().read(); System.out.println(ch); System.out.print("Karakter: "); ch = (char) System.console().reader().read(); System.console().reader().read(); System.out.println(ch); System.out.print("Karakter: "); ch = (char) new InputStreamReader(System.in).read(); System.out.println(ch); System.out.print("Karakter: "); ch = (char) new InputStreamReader(System.in).read(); System.out.println(ch); } } Újabb példa: import java.io.*; class Program { public static void main(String args[]) throws IOException { System.out.print("Karakter: "); char ch1 = (char) new InputStreamReader(System.in).read(); System.out.print("Karakter: "); char ch2 = (char) new InputStreamReader(System.in).read(); System.out.print("Karakter: "); char ch3 = (char) new InputStreamReader(System.in).read(); System.out.println("A beírt karakterek: " + ch1 + " " + ch2 + " " + ch3); } } ==== Gyakorlat ==== * Soroljon fel osztályokat, amelyekkel megvalósítható bekérés. * A Scanner osztállyal milyen primitív típust nem tudunk bekérni? * Írjon példát a egy karakter sorozat bekérésére. * Ha egy bejövő szám adatot karaktersorozatként kapunk meg, hogyan tudjuk átkonvertálni szám típussá? ===== Szelekció ===== ==== A szelekcióról ==== Alapesetben a program forráskódjában az utasítások egymás után sorban hajtódnak végre futtatáskor. Ezt nem mindig szeretnénk. Lesznek olyan utasítások, amelyek végrehajtását bizonyos feltételhez akarjuk majd kötni. Ha feltétel teljesül akkor végrehajtjuk az utasítást vagy utasításokat, ha nem akkor nem teszünk semmit, vagy éppen az utasítások egy másik csoportját akarom végrehajtani. Vegyünk egy egyszerű iskolapéldát. Szeretném eldönteni egy változóról, hogy kisebb számot tartalmaz-e mint 100. Ha kisebbet, akkor szeretném kiírni, hogy kisebb. Ehhez tennem kell egy állítást. Például, legyen az "a" változó amit vizsgálok. Azt állíthatom például, hogy kisebb: a < 100 Ez vagy igaz, vagy hamis állítás. Szükségünk van a Java nyelvben egy olyan utasításra, amellyel ezt képesek vagyunk megvizsgálni. Ez lesz az if. ==== if ==== Az if utasítással meg tudjuk vizsgálni, hogy egy állítás igaz, vagy hamis. Az állítást, mindig zárójelek közzé kell tennünk, az if után: if (feltétel) utasítás; A zárójel után jöhet az utasítás. Az utasítást persze tehetjük a következő sorba is, ha úgy átláthatóbb: if (feltétel) utasítás; Előfordul, hogy nem egy hanem több utasítást akarunk végrehajtani a feltétel teljesülése esetén. Az utasításokat ilyenkor blokk nyitó és blokk záró karakterek közzé teszem: if (feltétel) { utasítás_1; utasítás_2; ... utasítás_n; } A kapcsos zárójel jelzi, hogy a közzé zárt utasításokat együtt szeretném kezelni. A következő lehetséges eset, hogy ha feltétel nem teljesül, akkor is szeretnék valamilyen utasításokat végrehajtani. Ekkor az utasítás után egy "else" kulcsszó után írom ezeket az utasításokat. if (feltétel) utasítás_1; else utasítás_2; Ha a feltétel teljesül, akkor az első utasítás hajtódik végre, ha nem, akkor a második, azaz az "else" utáni utasítás. Ugyanez több utasítással: if (feltétel) { utasítás_1; utasítás_2; ... utasítás_n; } else { utasítás_1; utasítás_2; ... utasítás_m; } Eddig az szelekciónak csak a szintaxisát mutattuk be. Álljon itt egy konkrét példa a az if használatára: Szelekció példa import java.util.*; class szel { public static void main(String args[]) { Scanner bevitel = new Scanner(System.in); System.out.println("Szelekció"); System.out.print("Szám: "); int szam = bevitel.nextInt(); if(szam >0) System.out.println("Pozitív"); else System.out.println("0 vagy negatív"); } } A program bekér egy számot, majd megvizsgálja, hogy pozitív szám, nulla vagy negatív számot írt be a felhasználó. Bekéréshez a Scanner osztályt használtam. ==== else if ==== Többágú szelekció else if szerkezettel. Ha több feltételnek is meg kell feleljünk, akkor egy első if utasítás után else if utasításokat használunk. Általánosan: if (feltétel_1) utasítás_1; else if (feltétel_2) utasítás_2; else utasítás_3; Egy konkrét példához nézzük egy problémát. A fentebb volt egy feladatunk ahol azt vizsgáltuk, hogy egy szám pozitív vagy más. A program arra már nem volt képes, hogy azt is megvizsgálja, hogy ha nem pozitív, akkor 0 vagy negatív!?! Az "else if" szerkezet lehetőséget ad erre, mert újabb feltételt tudunk beilleszteni. import java.util.Scanner; class tobbagu { public static void main(String args[]) { Scanner olvaso = new Scanner(System.in); System.out.print("Szám: "); int szam = olvaso.nextInt(); if(szam > 0) System.out.println("Pozitív szám"); else if(szam == 0) System.out.println("Nulla"); else System.out.println("Negatív szám"); } } Ugyanaz csak a bekérés más osztályokkal (Kezdőknek akik nem használtak Scanner osztályt.). import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.IOException; class tobbagu2 { public static void main(String args[]) throws IOException { InputStreamReader folyam = new InputStreamReader(System.in); BufferedReader olvaso = new BufferedReader(folyam); System.out.print("Szám: "); int szam = Integer.parseInt(olvaso.readLine()); if(szam > 0) System.out.println("Pozitív szám"); else if(szam == 0) System.out.println("Nulla"); else System.out.println("Negatív szám"); } } ==== switch ==== A switch utasítás szintén többágú szelekcióra lett kitalálva. switch (kifejezés) { case érték1 : utasítások; break; case érték2 : utasítások; break; ... case értékn : utasítások; break; default : utasítások; } Switch példa class sw { public static void main(String args[]) { System.out.println("Hi"); int a = 7; switch(a) { case 1 : System.out.println("Egy"); break; case 2 : System.out.println("Kettő"); break; case 3 : System.out.println("Három"); break; case 4 : System.out.println("Négy"); break; default : System.out.println("Ismeretlen"); } } } A fenti program megvizsgálja, hogy az "a" változóban milyen szám van. Ha 1 akkor kiírja az "Egy" karaktersorozatot a képernyőre. Ha 2 akkor a "Kettő" karaktersorozatot, stb. Ha egyik sem -- mint a példában is -- akkor az "Ismeretlen" karaktersorozatot írja ki. A vizsgált változót a switch utáni zárójelek közzé írjuk. A case után írjuk szóközzel tagolva a feltételezett értékeket. A default után jönnek azok az utasítások, amelyek akkor hajtódnak végre, ha egyik feltétel sem teljesült. Vegyük észre minden kiírató utasítás után a break utasítást. Mit csinál a break utasítást? A brak utasítás megszakítja az utasítások végrehajtását és újból a switch részhez ugrik. Hogy jobban megértsük változtassuk kissé meg a példánkat. Tegyük az "a" változóba a 2-es értéket. A case 2 : végén lévő break utasítást pedig töröljük: class sw2 { public static void main(String args[]) { int a = 2; switch(a) { case 1 : System.out.println("Egy"); break; case 2 : System.out.println("Kettő"); case 3 : System.out.println("Három"); break; case 4 : System.out.println("Négy"); break; default : System.out.println("Ismeretlen"); } } } Végrehajtás után az eredmény a következő: Kettő Három A következő, azaz a case 3 : utáni utasítás is végrehajtódott. Ez éppen a berak utasítás hiány miatt történt. A szerkezetet pont ilyen esetekre hozták létre. Ha az "a" változó értéke "2" és szeretnénk ebben az esetben "Kettő" és "Három" karaktersorozatot is a képernyőre írni. A switch utasítás a következő primitív típusokkal működik: * byte * short * char * int Használható még a következő felsorolt típusokkal és a primitív típusok wrapper osztályaival Byte, Short, Char, Integer. A Java SE 7-es verziótól használható String osztállyal is. ==== Ternary operátor ==== Általánosan: állítás ? érték_ha_igaz : érték_ha_hamis A kifejezés visszaadja az első vagy második értéket, attól függően, hogy az állítás igaz, vagy hamis. A kapott érték eltárolható egy változóban: változó = állítás ? érték_ha_igaz : érték_ha_hamis class Program01 { public static void main(String[] args) { int a = 3; String e = (a > 10) ? "Nagyobb" : "Kisebb"; System.out.println(e); } } A program egyenértékű a következő if-es megoldással: class Program01 { public static void main(String[] args) { int a = 35; String e = null; if (a > 10) e = "Nagyobb"; else e = "Kisebb"; System.out.println(e); } } ==== Gyakorlat ==== * Hányféle szelekciós utasítás van a Java nyelvben? * Mi az a ternary operátor? * Egy if szelekció törzs részének elejét és végét mivel jelöljük a Java nyelvben? * Egy if szerkezetben a kapcsos zárójelek {} kötelezőek a Java nyelvben egy utasítás esetén? * Egy if szerkezetben mire való az else? * Az if szerkezetben kötelező az else ág használata? * A swicth utasításban milyen típusú változókat vizsgálhatunk a Java nyelvben? ===== Iteráció ===== ==== Az iterációról ==== Az iteráció vagy ismétlés, amely ciklus néven ismert még. Lesznek utasítások, amelyeket többször végre akarunk hajtani majd. Egyes esetekben tudni fogjuk hányszor, máskor pedig nem tudjuk hányszor, csak várunk valamilyen esemény bekövetkeztére. Az első eset a növekményes ciklus, a második pedig az "amíg" típusú ciklus. ==== for ==== A for utasítást jellemzően olyan ciklusoknál használjuk, ahol tudjuk meddig kell ismételni, azaz növekményes ciklusok esetén. for ( kezdeti_érték ; feltétel ; növekmény) utasítás; A for utasításnak három paramétere van. A három paramétert pontosvesszővel (;) választjuk el egymástól. A három paraméter a következő: * kezdő érték * feltétel (meddig menjünk) * növekmény Ha már számolnunk kell hányszor hajtunk végre az utasításokat, akkor kell egy változó ahol ezt tárolni fogjuk. Gyakran erre a célra az "i" változót használjuk. Az "i" változónevet egy programban csak ciklusváltozóként szoktuk használni. A Java fordító erre nem kötelez, de jó szokás. Ha az "i" foglalt, akkor a következő "j". Ha ez is foglalt, akkor "k". Ennél több eset ritka, de van még betű az ábécében. A következő példában az "i" változót használjuk ciklusváltozónak: for ( i = 1; i <= 10 ; i++) System.out.println("Város"); Az i változót persze valahol deklarálni kell. A Java nyelv megengedi, hogy ezt a ciklus fejrészében (a ciklus zárójelben lévő része) tegyük: for ( int i = 1; i <= 10 ; i++) System.out.println("Város"); Hasonlóan az if szerkezethez, itt is írhatunk több utasítást is a ciklus törzsébe (egy utasítás esetén, maga ez az egy utasítás a törzs, több utasítás esetén a blokk nyitótól a blokk záróig tart. for ( int i = 1; i <= 10 ; i++) { System.out.println("Város"); System.out.println("Cím"); } A fenti példákban a ciklustörzsben lévő utasítás, illetve utasítások 10-szer hajtódnak végre. Ezt a következő fejrésszel értük el: for ( int i = 1; i <= 10 ; i++) Ugyanez elérhető így is: for ( int i = 0; i < 10 ; i++) Vegyük észre a különbséget. A kezdő érték az utóbbi esetben 0, és addig megy a ciklus amíg kisebb mint 10, tehát 9-ig. ==== while ==== A while ciklus alapvetően "amíg" típusú ciklusok használatára találták ki. A while ciklus általánosan így épül fel: while (feltétel) utasítás; Egy konkrét példa i = 1; while (i <= 10) { System.out.println("Város"); i++; } A példában szereplő while ciklus ugyanazt csinálja mint a fentebbi programok legtöbbje. Itt is tudjuk meddig megyünk. A while utasítást úgy használtuk mint a for-t. Csak a kezdőértéket a ciklus előtt adtam meg, a növekményt meg a ciklus törzsében. Ez persze még nem az "amíg" típusú ciklus. Az "amíg" típusú ciklusnál nem tudjuk meddig megyünk. Várunk egy eseményre. A példa kedvéért a felhasználótól számokat kérünk be összeadás céljából. Nem tudjuk mennyit, majd a felhasználó eldönti. Ekkor valahogy biztosítanunk kell, hogy a bevitel végét jelezze. Ha 0 értéket nem vihet be a felhasználó, akkor használhatjuk ezt végjelnek. Vagyis kérjük be sorra a számokat, amikor a felhasználó 0 számot üt be, akkor nem kérünk több számot. A következő példában a Scanner osztállyal kérünk be számokat 0 végjelig: import java.*; import java.util.*; class vegjelig { public static void main(String[] argv) { Scanner bevitel = new Scanner(System.in); int szam=-1; while(szam != 0) { System.out.print("Kovetkezo szam: "); szam = bevitel.nextInt(); } } } A példában persze a bekért számokkal még nem csinálunk semmit. Szeretnénk összeadni a bekért számokat: import java.*; import java.util.*; class osszeg { public static void main(String[] argv) { Scanner bevitel = new Scanner(System.in); int szam=-1; int osszeg = 0; while(szam != 0) { System.out.print("Kovetkezo szam: "); szam = bevitel.nextInt(); osszeg = osszeg + szam; } System.out.printf("%d\n", osszeg); } } Gyakorlásképpen összeadás helyett szorozza össze a bekért számokat. Bekérés közben ne írja ki a részeredményeket. Csak a ciklus végén írja ki a szorzatot. ==== do while ==== Az eddigi ciklusok úgynevezett elől tesztelő ciklusok voltak. Ez annyit tesz, hogy előbb megvizsgálták a feltételt, majd ha az igaz volt, végrehajtották a ciklustörzs utasításait. A most következő ciklus hátul tesztelő ciklus. A ciklus törzsében lévő utasítások egyszer mindenképpen végrehajtódnak, a feltétel csak ez után kerül vizsgálatra. Ha a feltétel igaz, akkor az ciklus törzsében lévő utasítások megint végrehajtódnak. do { utasítások; }while(feltétel); Vegyük észre, hogy ezt ciklust végén le kell zárni pontosvesszővel. Konkrét példa a hátul tesztelésre: import java.util.*; class hatul { public static void main(String args[]) { Scanner bevitel = new Scanner(System.in); System.out.println("Hátul tesztelő ciklus"); int szam; do { System.out.print("Szám: "); szam = bevitel.nextInt(); }while(szam != 0); } } ==== for újra ==== A for utasításnak van egy kiterjesztett változata, amely tömbök és kollekciók iterálására lett kitalálva. Angolosan //enhanced for// néven ismert. A következőben ennek a használatát látjuk. class Program01 { public static void main(String args[]) { String[] varos = {"Debrecen", "Nyíregyháza", "Zalaegreszeg", "Pécs", "Szeged"}; for(String str : varos) System.out.println(str); } } A for() ciklus segítségével végtelen ciklust is előállíthatunk ha nem adunk meg paramétert: for(;;){ //ciklustörzs } ==== Gyakorlat ==== * Mit jelent az iteráció? * Hányféle iterációs utasítást ismert a Java nyelvben? * A for ciklusban hány alakja van a Java nyelvben? * Mi a különbség a do-while és while ciklus között? ===== Tömbök ===== A tömb **azonos típusú értékeket** tárolására alkalmas adatszerkezet. A tömböknek beszélünk a kiterjedéséről. Ha a kiterjedés csak egyirányú akkor vektorról beszélünk, ami hasonlít is a matematikában tanult vektorfogalomhoz. Ha a kiterjedés kétirányú akkor mátrixról beszélünk, szintén a matematikában használt mátrixhoz hasonlóan. A tömböknek lehet ennél több kiterjedése is, három, vagy akár több. De ezeket már ritkán szoktuk használni. ==== Vektorok ==== Egy tömb akkor vektor, ha egyirányú a kiterjedése. Például egész számokat szeretnénk eltárolni: | 37 | 23 | 47 | 52 | 28 | A példában öt darab egész számot szeretnénk tárolni. A tömb egyes elemeivel szeretnénk valamit csinálni, így hivatkozni kell rájuk. Ezt úgy szoktuk megtenni, hogy minden értékhez egy indexet rendelünk. Az első érték indexe nulla, a következőé egy, aztán kettő, stb. ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ | 37 | 23 | 47 | 52 | 28 | [] ; vagy []; Konkrét példa: int[] tomb; vagy int tomb[]; Kezdőérték adása int[] tomb = {37, 23, 47, 52, 28}; De lehet így is: int[] tomb = new int[] {37, 23, 47, 52, 28}; Más típussal: long[] fizetesek = new long[] {10000, 20000, 30000, 40000}; int[] tomb = {3, 4, 7, 8}; A Java tömböknek deklaráláskor nincs hely lefoglalva a memóriában. Ez a new kulcsszóval kell megtennünk. Pl.: class tomb { public static void main(String args[]) { int[] tomb; tomb = new int[5]; tomb[0]=37; System.out.println(tomb[0]); } } class tomb2 { public static void main(String args[]) { int[] tomb = new int[5]; tomb[0]=37; System.out.println(tomb[0]); } } {{:oktatas:programozás:java:tombegeszekbol.png|}} Tömb mérete import java.lang.reflect.*; ... System.out.println(Array.getLength(tomb)); System.out.println(tomb.length); Tömb feltöltése: import java.util.*; class Program { public static void main(String[] argv) { int[] tomb = new int[10]; Arrays.fill(tomb, 5); for(int i=0; i A példában 5-ös számokkal töltjük fel a tömböt. ==== Java többdimenziós tömbök ==== | 1 | 3 | 3 | | 2 | 4 | 6 | | 3 | 4 | 7 | | 5 | 6 | 7 | Integer ars[][] = new Integer[4][3]; // Integer az int burkoló osztálya int ars[][] = new int[][]{{1,3,3}, {2,4,6}, {3,4,7}, {5,6,7}}; Olyan mint egy 4 x 3 matrix public class MultiDimensionalArrayExample { public static void main(String[] args) { int ars[][] = new int[][]{{1,2,3}, {2,4,6}, {3,4,7}, {5,6,7}}; for(int i = 0; i < 4; i++) for(int j = 0; j < 3; j++) System.out.println(ars[i][j]); } }
{{:oktatas:programozas:java:valos_tomb.png?300|}} Valós számokat tartalmazó tömb
==== Tömb mérete ==== int tomb[][] = new int[8][4]; System.out.println(tomb.length); // 8-at ír ki System.out.println(tomb[0].length); // 4-et ír ki ==== Tömb átméretezése ==== A Java egyszerű tömbjeit nem arra találták ki, hogy később átméretezzük őket. Az átméretezés azért megoldható: int ujHossz = 20; int eredetiHossz = tomb.length; Class componentType = tomb.getClass().getComponentType(); Object tomb2 = Array.newInstance(componentType, ujHossz); int vedettHossz = Math.min(eredetiHossz,ujHossz); if (vedettHossz > 0) System.arraycopy(tomb, 0, tomb2, 0, vedettHossz); tomb = (int[]) tomb2; A komplett program működés közben: class tombmeret { private static Object resizeArray (Object oldArray, int newSize) { int oldSize = java.lang.reflect.Array.getLength(oldArray); Class elementType = oldArray.getClass().getComponentType(); Object newArray = java.lang.reflect.Array.newInstance( elementType,newSize); int preserveLength = Math.min(oldSize,newSize); if (preserveLength > 0) System.arraycopy (oldArray,0,newArray,0,preserveLength); return newArray; } public static void main(String[] args) { int[] tomb = new int[10]; tomb[0] = 35; tomb[1] = 27; tomb[2] = 42; System.out.println(tomb.length); tomb = (int[]) resizeArray(tomb, 20); System.out.println(tomb.length); } } Látjuk, hogy az ilyen egyszerű tömbök nem méretezhetők át könnyen. Ha méretezhető tömböt szeretnénk, akkor használjuk az ArrayList vagy a Vector osztályt, az util csomagból. Ezek átméretezése automatikus. ==== Tömb feltöltése ==== Az Arrays osztály arra való, hogy tömbökön végezzünk néhány műveletet. Ez lehet annak feltöltése. int[] tomb = new int[10]; java.util.Arrays.fill(tomb, 0); ==== Tömb paraméterként kezdőértékkel ==== method(new Object[] { a, b, c}); ==== Egyéb tömbök ==== === ArrayList === Az java.util.ArrayList dinamikus tömböt valósít meg. A tömblisták (ArrayList) automatikusan átméreteződnek, mérete mindig az elemek számától függ. Az egyes elemeket mindössze fel kell venni vagy törölni. Egy ilyen változó (objektum) deklarálásánál meg kell adnunk milyen típusú elemet szeretnénk tárolni kisebb-mint és nagyobb-mint jelek között. A következő példában például karaktersorozatot szeretnénk tárolni: ArrayList tomb = new ArrayList(); Vagy egészek tárolása ArrayList tomb = new ArrayList(); Lássuk az alábbi példában egy komplett programot: import java.util.*; class Program { public static void main(String[] argv) { ArrayList tomb = new ArrayList(); tomb.add("eper"); tomb.add("málna"); tomb.add("barack"); System.out.println(tomb.get(2)); } } Az ArrayList tartalmának kiíratása: ArrayList lista = new ArrayList<>(); lista.add('János'); lista.add('Mihály'); lista.add('Imre'); System.out.println(lista); === Vector === Az ArrayList-et egyszálas programokhoz tervezték. A Vectort többszálas programokhoz. A Vector nem ellenőrzi, ha a kollekciója megváltozik, ami hibákhoz vezethet. megváltozhat az iteráció során, viszont a változás nem ellenőrzött. A vektor az ArrayList-hez hasonlóan használható. Meg kell adnunk mit szeretnénk benne tárolni. A következőben lássunk egy komplett példát a használatára. import java.util.*; class Program2 { public static void main(String[] argv) { Vector tomb = new Vector(); tomb.add("eper"); tomb.add("málna"); tomb.add("barack"); System.out.println(tomb.get(2)); } } Elem törlése tomb.remove(1); Ha Object típust adok meg akkor különböző típusokat is eltehetek a verembe. import java.util.*; class Program3 { public static void main(String[] argv) { Vector tomb = new Vector(); tomb.add("eper"); tomb.add(25); tomb.add("málna"); tomb.add("barack"); System.out.println(tomb.get(1)); } } Egyéb metódusok használat közben: import java.util.*; class Program4 { public static void main(String[] argv) { Vector tomb = new Vector(); tomb.add("eper"); tomb.add(25); tomb.add("malna"); tomb.add("barack"); tomb.addElement("korte"); System.out.println(tomb.get(1)); System.out.println(tomb.size()); System.out.println(tomb.remove(1)); System.out.println(tomb.size()); System.out.println(tomb.get(1)); System.out.println(tomb.elementAt(2)); System.out.println("Hol talalhato: " + tomb.indexOf("malna")); tomb.clear(); System.out.println(tomb.size()); tomb.addElement(new Integer(1)); tomb.addElement(new Integer(2)); System.out.println("Utolso: " + tomb.lastElement()); System.out.println("Elso: " + tomb.firstElement()); tomb.removeAllElements(); tomb.addElement("Valami"); tomb.addElement("Masik"); //Konverziók: Object[] tomb2 = tomb.toArray(); String[] tomb3 = new String[10]; tomb3 = (String []) tomb.toArray(tomb3); //Itt gond, ha a vektor nem string típusú elemet tartalmaz //Olyankor Object típusba lehet konvertálni. Enumeration e = tomb.elements(); } } Ha Vector és hasonló listák esetén, ha számot akarunk tárolni akkor nem használhatjuk a primitív típust, helyette a burkolóosztályt kell használnunk. Ugyanakkor a for ciklusnak használhatjuk egy újabb változatát a lista kiíratására. A következő példa ezt mutatja be: import java.util.Scanner; import java.util.Vector; class Program { public static void main(String args[]) { Vector szamok = new Vector(); szamok.add(37); szamok.add(52); szamok.add(48); szamok.add(87); szamok.add(23); for(Integer szam : szamok) System.out.print(szam + " "); System.out.println(); } } Vegyük észre az "Integer"-t az "int" helyett, a for ciklus fejrészében pedig "Integer szam : szamok". Utóbbi azt jelenti, hogy veszem a szamok list minden elemét. Az elemeket a szam változóban kapom meg minden ciklusban, ameddig a lista elemei el nem fogynak. === List === A List egy Interfész, ezért példányt nem lehet belőle létrehozni. A konstruktorként az előző osztályok valamelyikét használhatjuk. A következő példában a Vector<> osztályt használjuk konstruktorként. import java.util.*; class Program5 { public static void main(String[] argv) { List tomb = new Vector(); tomb.add("eper"); tomb.add("málna"); tomb.add("barack"); System.out.println(tomb.get(1)); } } Használható típussal egyszerre több típus. === Set === A Set egy interface, nem osztály. Ezért nincs is konstruktora. Helyette a TreeSet vagy HashSet osztályok konstruktorát használjuk. Egy halmazt határozhatunk meg vele, amelyen a szokásos halmazműveletek használhatók. import java.util.*; class Program6 { public static void main(String[] argv) { //Set halmaz = new TreeSet(); Set halmaz = new HashSet(); halmaz.add("eper"); halmaz.add("málna"); halmaz.add("barack"); System.out.println(halmaz.size()); System.out.println(halmaz.contains("eper")); Iterator it = halmaz.iterator(); while(it.hasNext()) { Object elem = it.next(); } } } === Iterátor === import java.util.Iterator; import java.util.Vector; public class Program02 { public static void main(String args[]) { Vector v = new Vector(); v.add("alma"); v.add("körte"); v.add("barack"); v.add("szilva"); Iterator i = v.iterator(); while (i.hasNext()) { System.out.println(i.next()); } } } === ArrayList kezdőérték === import java.util.ArrayList; import java.util.Arrays; class Program01 { public static void main(String args[]) { Integer[] t = {45, 37, 29, 82, 34, 56}; ArrayList v = new ArrayList(Arrays.asList(t)); for(Integer a : v) System.out.println(a); } } === ArrayList listák összefűzése === List list = new ArrayList(); list.addAll(list1); list.addAll(list2); ==== Gyakorlat ==== - Mondjon olyan típust vagy osztályt, amely azonos típusú elemek felvétele során automatikusan nő annak mérete. - Milyen osztállyal tudunk feltölteni egy tömböt? - Mi a vektor? - Mi a mátrix? - Hogyan deklarálunk egy mátrixot Java nyelven? ===== Különböző típusú adatok egy adatszerkezetben ===== A C nyelvben ezt struct, míg Pascal nyelvben ez a record. A Java nyelvben ezek egyike sem használható, helyette osztályt használhatunk a már meglévő osztályon belül. import java.io.*; class Program01 { public static void main(String args[]) throws IOException { class Dolgozo { int kor; double fizetes; } Dolgozo Joska = new Dolgozo(); Joska.kor = 23; Joska.fizetes = 370000; System.out.printf("%f\n", Joska.fizetes); System.out.println("Folytatáshoz nyomjon egy billentyűt"); System.in.read(); } } vagy import java.io.*; class Program01 { static class Dolgozo { int kor; double fizetes; } public static void main(String args[]) throws IOException { Dolgozo Joska = new Dolgozo(); Joska.kor = 23; Joska.fizetes = 370000; System.out.printf("%f\n", Joska.fizetes); System.out.println("Folytatáshoz nyomjon egy billentyűt"); System.in.read(); } } ==== Osztály tömbként ==== Sokszor előfordulhat, hogy több különböző adatot szeretnénk tárolni de nem csak egy dologról vagy személyről hanem többről. Például szeretnénk dolgozók adatait tárolni: import java.io.*; class Osztalytomb { public static void main(String[] args) throws IOException { Dolgozo[] munkas = new Dolgozo[3]; munkas[0] = new Dolgozo("Nagy Béla", 350000); munkas[1] = new Dolgozo("Kis János", 750000); munkas[2] = new Dolgozo("Rózsa Sándor", 380000); for (int i = 0; i < 3; i++) munkas[i].print(); System.in.read(); } } class Dolgozo { private String nev; private double fizetes; public Dolgozo(String n, double s) { nev = n; fizetes = s; } public void print() { System.out.println(nev + "\t" + fizetes); } } Újabb példa: class Program01 { static class Dolgozo { String nev; int kor; double fizetes; } public static void main(String[] args) { Dolgozo[] munkas = new Dolgozo[3]; for(int i=0; i<3;i++) munkas[i] = new Dolgozo(); munkas[0].nev = "Nagy István"; munkas[0].kor = 25; munkas[0].fizu = 285600.0; munkas[1].nev = "Kis Béla"; munkas[1].kor = 32; munkas[1].fizu = "Kis Béla"; munkas[2].nev = "Be Kornél"; munkas[2].kor = 22; munkas[2].fizu = "Erős Lajos"; } } Harmadik példa /* Több tulajdonság tárolása listában */ import java.util.ArrayList; public class Program02 { public static void main(String[] a) { ArrayList dolgozok = new ArrayList(); dolgozok.add(new Dolgozok("Nagy", "József")); dolgozok.add(new Dolgozok("Rezeg", "István")); dolgozok.add(new Dolgozok("Kékedi", "János")); System.out.println(dolgozok); Dolgozok d = dolgozok.get(1); d.beallitVezNev("Erős"); System.out.println(dolgozok); Dolgozok d2 = dolgozok.get(1); System.out.println(d2.lekerVezNev()); } } class Cim { } class Dolgozok { private String vezNev; private String kerNev; private Double fizetes; public Cim cim; public Dolgozok(String vezNev, String kerNev) { this.vezNev = vezNev; this.kerNev = kerNev; this.cim = new Cim(); } public String lekerVezNev() { return this.vezNev; } public void beallitVezNev(String vezNev) { this.vezNev = vezNev; } public String lekerKerNev() { return this.kerNev; } public void beallitKerNev(String kerNev) { this.kerNev = kerNev; } public double lekerFizetes() { return this.fizetes; } public void beallitFizetes(double fizetes) { this.fizetes = fizetes; } } Egy példa automatikus feltöltéssel: class Szemely { private String nev; private int szuletesEve; Szemely(String nev, int szuletesEve) { this.nev = nev; this.szuletesEve = szuletesEve; } @Override public String toString() { return nev + ":" + szuletesEve; } } class Program01 { public static void main(String args[]) { Szemely[] szemelyek = new Szemely[5]; for(int i=0;i<5;i++) { szemelyek[i] = new Szemely("Névtelen" + i, 0); } System.out.println(szemelyek[1].toString()); } } {{:oktatas:programozás:java:tombszemelyosztalybol.png|}} Ha HashSet osztályba szeretnénk például egy Dolgozo osztály példányait tárolni, néhány dolog nem fog működni alapértelmezetten. Ha például felveszem kétszer ugyanazt az adatot, mindkét adat tárolásra kerül, pedig halmazról lévén szó ennek nem lenne szabad bekövetkeznie. Ha egy HashSet objektumba, amely például Integer értékeket tartalmaz, a 22 értéket kétszer adom hozzá az add() metódussal, az csak egyszer fog tárolódni. Visszatérve a Dolgozo osztályunkhoz, hasonló probléma lép fel, ha meg akarom vizsgálni, hogy egy adott dolgozó szerepel-e már a halmazban. Ezt a contains() metódussal szoktuk vizsgálni. Ha a HashSet halmazunkban a Dolgozo osztály példányai vannak a contains() metódus mindig hamis értéket fogunk kapni, vagyis nem tudjuk megvizsgálni vele, hogy egy adott dolgozó szerepel-e egy halmazban. Természetesen a probléma megoldható, csak felül kell írnunk a hashCode() és a equals() metódust. A következő programban erre látunk példát: import java.util.HashSet; class Dolgozo { String nev; int kor; double fiz; Dolgozo(String nev, int kor, double fiz) { this.nev = nev; this.kor = kor; this.fiz = fiz; } @Override public boolean equals(Object o) { if(this == o) return true; Dolgozo dolgozo = (Dolgozo) o; if(!dolgozo.nev.equals(this.nev)) return false; if(dolgozo.kor!=(this.kor)) return false; if(dolgozo.fiz!=(this.fiz)) return false; return true; } @Override public int hashCode() { int nevHash = this.nev.hashCode(); int korHash = this.kor; int fizHash = (new Double(this.fiz)).hashCode(); int res = nevHash + korHash + fizHash; return res; } } class Program01 { public static void main(String args[]) { HashSet h = new HashSet(); h.add(new Dolgozo("Nagy József", 35, 350000)); h.add(new Dolgozo("Nagy József", 35, 350000)); System.out.println(h.contains(new Dolgozo("Nagy József", 35, 350000))); System.out.println(h.size()); } } ===== Enum típusok ===== Az enum típus egy speciális típus, amellyel a nevesített állandókhoz hasonló típusok jönnek létre. Egy ilyen típus több nevet tartalmaz. Értéket azonban nem adunk nekik, csak a nevükkel hivatkozunk rájuk. Használatával **olvashatóbb kódot** kapunk. enum Egtaj { ESZAK, DEL, KELET, NYUGAT } enum Os { LINUX, WINDOWS, MACOSX } class Program { enum Nap { HETFO, KEDD, SZERDA, CSUTORTOK, PENTEK, SZOMBAT, VASARNAP } public static void main(String[] args) { Nap a = Nap.HETFO; System.out.println(a); } } ==== Dolgozók státusza ==== Legyen egy példa, ahol dolgozók adatait tároljuk, köztük a dolgozó státuszát. A státusz lehet aktív, próbaidős, szabadságos, beteg, megszüntetés alatt. A státuszok nyilvántartására készítünk egy enum típust: public enum Status { TRIAL, ACTIVE, HOLIDAY, SICK, TERMINATE } A dolgozók tárolásánál ezt használjuk: public class Employee { int id; String name; String city; double salry; Status status; } Dolgozó státuszának beállítása: public class App { public static void main(String[] args) throws Exception { handleEmp(); } public static void handleEmp() { Employee emp = new Employee(); emp.status = Status.ACTIVE; System.out.println(emp.status); } } A lehetséges kimenet: ACTIVE A dolgozók státuszát tárolhattuk volna String típusban is, de amikor értéket kell adni neki: emp.status = "active"; El kell gondolkodnunk, hogy most akkor mit kell pontosan írni? Acitve, active, aktív, ACTIVE, esetleg working vagy más? Ha enum típust használunk a fordító vagy maga a fejlesztő eszköz szól, ha elírtuk. ==== Még több ==== További lehetséges enum típusok Még több: enum Day {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } enum Nap {HETFO, KEDD, SZERDA, CSUTORTOK, PENTEK, SZOMBAT, VASARNAP} ; enum MovieType {ACTION, HORROR, COMEDY}; enum Gender {MALE, FEMALE}; enum WeekDay { MON, TUE, WED, THU, FRI, SAT, SUN }; enum Grade { A, B, C, D, F, INCOMPLETE }; //Ertekeles enum Tank { EMPTY, HALF, FULL }; //Penny =1 centes, Nickel=5 centes, Dime=10 centes, Quarter=25 centes ; Amerika enum Currency {PENNY, NICKLE, DIME, QUARTER}; enum Color {WHITE, BLACK, RED, YELLOW, BLUE }; enum Planet { MERCURY, VENUS, EARTH, ARS, JUPITER, SATURN, URANUS, NEPTUNE}; //sugár km, tömeg kg. enum Bolygo { MERKUR (2439.7, 3.302E+23), VENUSZ (6051.8, 4.8685E+24), FOLD (6378.137, 5.9736E+24), MARS (3402.5, 6.4185E+23), JUPITER (71492.0, 1.899E+27), SZATURNUSZ (60268, 5.6846e+26), URANUSZ (25559, 8.6832e+25), NEPTUNUSZ (24764, 1.0243e+26); private final double radius; private final double mass; Bolygo(double radius, double mass){ this.radius = radius; this.mass = mass; } private double getRadius() { return radius;} private double getMass() { return mass;} } ===== Karakterkezelés ===== ==== ASCII ==== A char típus egy karakter tárolására való. Igaz a Java Unicode karaktereket tárol, de az angol ábécé betűi az UTF-8 megvalósítás esetén kompatibilisek az [[:oktatas:számítástechnika:ascii_tábla|ASCII]] kódtáblával. Ha tudjuk, hogy az ASCII kódtáblában a nagy "A" és a kis "a" közötti különbség 32, akkor egyszerűen alakíthatjuk a nagybetűs karaktereket kisbetűssé és fordítva: class ascii { public static void main(String args[]) { char ch = 'A'; System.out.printf("%c\n", ch + 32); } } A példában a nagy "A" karaktert kis "a" karakterré alakítjuk. Rendelkezésre állnak a Character osztály metódusai is: Kisbetűssé alakítása char ch = Character.toLowerCase('A'); Szám, karakterként kezelése továbbiakban: int a = 65; char ch = (char) a; A Character osztály további metódusai: | boolean isDigit(char ch) | | boolean isLetter(char ch) | | boolean isLetterOrDigit(char ch) | | boolean isWhitespace(char ch) | | boolean isLowerCase(char ch) | | boolean isUpperCase(char ch) | | String toString() | | String toString(char c) | | char toUpperCase(char ch) | class Program01 { public static void main(String args[]) { System.out.println(Character.toChars(97)); // a System.out.println(Character.toChars(369)); // ű System.out.println((char)97); // a System.out.println((char)369); // ű } } ==== ASCII kód ==== A következő programban szeretnénk az "a" karakter ASCII kódját megkapni: class Program01 { public static void main(String args[]) { char ch = 'a'; System.out.printf("%d\n", (int) ch); } } Itt pedig van egy ASCII kódunk és szeretnénk kiíratni a hozzátartozó karaktert: class Program01 { public static void main(String args[]) { int a = 65; System.out.printf("%c\n", a); } } Az "a" karaktert tárolhatjuk eleve **int típusban**: class Program01 { public static void main(String args[]) { int a = 'a'; System.out.printf("%d\n", a); } } Kódpontok kiíratása: class Program01 { public static void main(String args[]) { System.out.println(Character.codePointAt("a", 0)); // 97 System.out.println(Character.codePointAt("é", 0)); // 233 System.out.println(Character.codePointAt("ű", 0)); // 369 } } ==== Összehasonlítás, egyenlőség vizsgálat ==== Összehasonlításhoz használhatjuk a "==" az egyenlőségjeleket vagy ha burkolóosztályt használtunk, akkor equals() függvényt is. class Program01 { public static void main(String args[]) { Character ch = 'a'; char ch2 = 'b'; System.out.println(ch.equals('a')); // true System.out.println(ch == 'a'); // true System.out.println(ch2 == 'b'); // true } } class Program01 { public static void main(String args[]) { char ch1 = 'a'; char ch2 = 'a'; char ch3 = 'c'; System.out.println(Character.compare(ch1, ch2)); // 0 System.out.println(Character.compare(ch1, ch3)); // -2 System.out.println(Character.compare(ch3, ch1)); // 2 } } ==== Karakter bekérés példa1 ==== A Scanner osztállyal közvetlenül nem kérhető be karakter. De bekérhetünk egy sztringet, aminek vesszük az első karakterét. import java.util.*; class App { public static void main(String args[]) { Scanner sc = new Scanner(System.in); System.out.print("Karakter: "); String str = sc.next(); char ch = str.charAt(0); System.out.println(ch); sc.close(); } } A next() metódus helyett használható a nextLine() metódus is. ==== Példa 2 ==== import java.io.*; class App { public static void main(String args[]) throws IOException { System.out.print("Karakter: "); char ch = (char) System.in.read(); System.out.println(ch); } } ==== Példa 3 ==== import java.io.*; class Pel { public static void main(String args[]) throws IOException { InputStreamReader folyam = new InputStreamReader(System.in); BufferedReader olvaso = new BufferedReader(folyam); System.out.print("Karakter: "); String str = olvaso.readLine(); char ch = str.charAt(0); System.out.println(ch); } } ==== Sztring és karakter hasonlítása ==== class Program01 { public static void main(String args[]) { if(Character.toString('a').equals("a")) System.out.println("Egyenlő"); else System.out.println("Nem egyenlő"); } } ==== Karaktertömb sztringgé ==== class Program01 { public static void main(String args[]) { //char tömb sztringgé 1: char[] t = {'a', 'b', 'c'}; String s = new String(t); System.out.println(s); //char tömb sztringgé 2: String s2 = String.copyValueOf(t); System.out.println(s2); } } ===== Sztring kezelés ===== ==== String osztály ==== Stringeket a String osztállyal hozhatunk létre. Nincs string primitív típus. String s; s = "alma"; A Java nyelvben a sztringváltozónak értékadással is adhatunk értéket. A String osztály statikus, vagyis használható példányosítás nélkül. A legnagyobb beírható string hossza: 65534 import java.io.*; class Szoveg { public static void main(String args[]) throws IOException { String s; s = "alma"; System.out.println(s.length()); System.in.read(); } } Egyenlőség vizsgálat String gyumolcs = "körte"; if (gyumolcs.equals("alma")) System.out.println("A gyümölcs alma"); ==== String osztály metódusai ==== === length() === A karaktersorozat hosszát adja vissza. int hossz = s.length(); === concat() === Karaktersorozatok összefűzésére való. String s = "egyik"; s.concat(" másik"); Az s változót kiíratva ezek után ezt kapjuk: egyik másik === replace() === Egy karaktersorozatban egy adott karaktersor cseréje egy másikra. Általános szintaxis: replace(mitCserél, mireCserél) Egy konkrét példa: String s = new String("Nagy kő esett le a szívemről tegnap"); System.out.print(s.replace("szívemről", "egy kocsiról")); === replaceAll() === Egy karaktersorozatban a megtalált mintát minden helyen kicseréli. str.replaceAll("\\s+", "\t"); //Szóközök tabulátorra cserélése === toLowerCase() === Kisbetűssé alakít minden karaktert. toLowerCase() String str = "SziLVa"; String kisbetus = str.toLowerCase(); === toUpperCase() === Nagybetűssé alakít minden karaktert. toUpperCase() String str = "SziLVa"; String nagybetus = str.toUpperCase(); === trim() === A trim() a szöveg elejéről és a végéről eltávolítja a whitespace karaktereket. String s = " alma "; System.out.println(s.trim()); === split() === A karaktersorozatot feldarabolja a megadott szeparátor alapján. str.split("\\s+"); //Egy vagy több szóköz Szeparátorként megadható szabályos kifejezés. A split() függvény egy String[] típus ad vissza. === isEmpty() === Megvizsgáljuk, hogy a karaktersorozat-változó üres-e. Példa: boolean ures = str.isEmpty(); === További példák === class Str { public static void main(String args[]) { System.out.println("Szövegkezelés Java nyelven"); String szoveg = "alma"; System.out.println(szoveg.equals("almaa")); // true értéket ad, ha egyezik, vagy false System.out.println(szoveg.compareTo("alma")); // 0-át kapunk, ha egyezik System.out.println(szoveg.indexOf("alma")); // -1 ha nem található; // Ha szoveg változóban van ilyen annak a kezdő indexét kapjuk meg // Esetünkben 0 //Szöveg darabolása String sor ="alma:körte:barack:szilva"; String[] tomb = sor.split(":"); System.out.println(tomb[1]); String mondat = "Ha megint ezért üzen"; System.out.println(mondat.substring(4)); //Kezdő indextől szeretném a karaktereket System.out.println(mondat.substring(4, 6)); //Kezdő index és vég index közötti karakterek } } ==== char[] és String ==== A Sztring típusú objektum egy karakterére nem hivatkozhatunk a Java nyelven szögletes zárójelekkel, mint egy tömbnél. Sztring esetén a charAt() metódust használhatjuk. Karakter tömb esetén a hivatkozás: char[] tomb = {'a', 'b', 'c'}; System.out.println(tomb[1]); Sztring esetén csak így: String tomb = "abc"; System.out.println(tomb.charAt(1)); Esetleg, használjunk String() konstruktort: char[] adat = {'a', 'b', 'c'}; String adat2 = new String(adat); System.out.println(adat2.charAt(1)); ==== Pufferelt sztringek ==== A string osztállyal létrehozott változó valójában nem változtatható meg. Ha ilyen műveletet végzünk a háttérben valójában egy új példány jön létre. String str = "szilva"; str = "barack"; A fenti példa második sorában a egy új str objektum jön létre a memóriában. === StringBuilder === Ugyanaz mint a StringBuffer, de a Stringek nincsenek szinkronizálva. Ezért használatát egy szálas programokhoz találták ki. StringBuilder defString = new StringBuilder(); // 16 karakter méret beállítása StringBuilder nulString = new StringBuilder(6); // pontos méret megadása StringBuilder aString = new StringBuilder("kezdőérték"); // kezdőérték megadása Hozzátartozó metódusok: capacity(), length(), charAt(i), indexOf(g), lastIndexOf(g) Módosító metódusok: append(g), delete(i1, i2), insert(iPosn, g), getChars(i), setCharAt(iposn, c), substring(), replace(i1,i2,gvalue), reverse(), trimToSize(g ), toString(g) Összehasonlítás String típussal: if(strb.toString().equals("hasonlítószöveg")) //Mit tegyünk === StringBuffer === StringBuffer s; A StringBuffer osztállyal olyan sztringeket hozhatunk létre, amit meg is tudunk változtatni. StringBuffer defString = new StringBuffer(); // 16 karakter méret beállítása StringBuffer nulString = new StringBuffer(6); // pontos méret megadása StringBuffer aString = new StringBuffer("kezdőérték"); // kezdőérték megadása Hozzátartozó metódusok: capacity(), charAt(i), length(), substring(iStart [,iEndIndex)]) Módosító metódusok: append(g), delete(i1, i2), deleteCharAt(i), ensureCapacity(), getChars(srcBeg, srcEnd, target[], targetBeg), insert(iPosn, g), replace(i1,i2,gvalue), reverse(), setCharAt(iposn, c), setLength(),toString(g) ==== Sztring formázás ==== Az alábbi sorok a Calander típusú objektum tartalmát teszik olvashatóvá: java.util.Calendar c = java.util.Calendar.getInstance(); String s = String.format("Születésnap: %1$tY-%1$tm-%1$te", c); Valós szám kiíratása: double a = 3.7; System.out.println(String.format("%.2f\n", a)); ==== Összefűzés ==== String s1 = "Egyik"; String s2 = s1 + "Másik"; ==== Sztring hossza ==== int hossz = s2.length(); ==== Számok sztringgé ==== int szam1 = 4; double szam2 = 3.5; String szamegy = String.valueOf(szam1); String szamketto = String.valueOf(szam2); ==== Sztringek számmá ==== String s1 = "3.5"; String s2 = "34"; double szam1; int szam2; szam1 = Double.valueOf(s1).doubleValue(); szam2 = Integer.alueOf(s2).intValue(); ==== Összehasonlítás ==== String gyumolcs = "alma"; if (gyumolcs.equals("körte")) System.out.println("A gyümölcs: körte"); Lexikográfiai összehasonlítás. 0-át kapunk ha azonos, 0-nál kisebb értéket ha a második kisebb (lexikográfialilag), illetve 0-nál nagyobb értéket ha nagyobb. String abc = "abc"; Stirng def = "xyz"; if (abc.compareTo(def) < 0) // 'a' kisebb mint 'x' if (abc.compareTo(abc) == 0) // ez is igaz ==== Egy adott karakter első előfordulása ==== String s = "Finomabb"; int kezdet; kezdet = s.indexOf('b') ==== Egy adott sztring első előfordulása ==== String s = "Finomabb"; int kezdet; kezdet = s.indexOf("nom") ==== Rész sztring ==== String s = "Finomabb"; String resz; resz = s.substring(2,4); Az első paraméter a kezdet, a második a vég. ==== Sztring karaktertömbbé ==== String s = "barack"; char[] t = s.toCharArray(); System.out.println(t[0]); Iterálással: class Program01 { public static void main(String[] args) { String str = "almakörte"; char[] ca = str.toCharArray(); for(char ch : ca) { System.out.println(ch); } } } ==== Sztring darabolása ==== String s = "barack:körte:alma"; String[] ts = s.split(":"); System.out.println(ts[1]); A "|" szeparátorral nem működik. A Szeparátor lehet reguláris kifejezés is. ==== Gyakorlás ==== * Milyen osztályokkal deklarálhatunk karaktersorozatot tárolni képes változót, illetve objektumot? * Hogyan kérdezhetjük le egy karaktersorozat hosszát? * Hivatkozhatok-e egy karaktersorozat adott elemére a szögletes zárójelekkel, a tömbökhöz hasonlóan? * Hogyan tudom egy szöveg egy részét venni? * Hogyan tudom megvizsgálni, hogy egy karaktersorozat egyenlő-e egy másik karaktersorozattal? ===== Kivételkezelés ===== ==== A kivételkezelésről ==== A kivételkezelést a program futtatása során fellépő abnormális állapotok kezelésére találták ki. Abnormális állapot esetén a programok kivételt dobnak. Például, egy nemlétező állományra hivatkozunk, vagy írni akarunk állományba, de nincs hozzá jogunk. Esetleg nullával próbáltunk meg osztani. Ha egy program dobott egy kivétel, mi két dolgot tehetünk. Eldobjuk vagy kezeljük. Az eldobás a throws utasítással lehetséges. Az elkapás a try-catch utasítás párral. ==== Osztás nullával ==== import java.io.*; import java.util.*; class program { public static void main(String args[]) throws IOException { Scanner be =new Scanner(System.in); double c=0; int a = be.nextInt(); try { c = 50 / a; } catch (Exception e) { if (e instanceof ArithmeticException) System.out.println("Osztás nullával"); } System.out.printf("%f\n", c); System.out.println("Folytatáshoz nyomj egy billentyűt!"); System.in.read(); } } try{ //utasítások }catch(IOException e) { System.err.println("Kivétel törént - Hogy miért? Lásd itt: "); e.printStackTrace(); System.exit(-1); } A kivétel eldobása: import java.io.IOException; class Program01 { public static void main(String[] args) throws IOException { System.out.println("Folytatáshoz nyomjon Entert"); System.in.read(); } } ==== Osztás 0-val lebegőpontos számokkal ==== Ha lebegőpontos számokkal dolgozunk és 0-val osztunk, akkor az nem hiba. Ez csak egész számok esetén hiba. Valós számok esetén az eredmény végtelen. class Program01 { public static void main(String[] args) { double a = 1/0.; if(a == Double.POSITIVE_INFINITY) { System.out.println("Végtelen"); } else { System.out.println("Valami más"); } } } ==== Néhány kivétel ==== * ArithmeticException - Például osztás nullával * InputMismatchException - java.util.Scanner osztállyal pl. számot várunk szöveget kapunk ==== Gyakorlat ==== * Mikor használjuk a kivételkezelést? * Milyen utasítással alkalmazzuk a Java nyelvben a kivételkezelést? ===== Fájl műveletek ===== ==== Műveletek fájlokkal ==== Fájl létezésének ellenőrzése: import java.io.*; public class ap { public static void main(String[] args) { File f = new File("adat.txt"); System.out.println(f.exists()); } } További metódusok: * exists() -- Ha a fájl létezik true, ha nem false * getName() -- A fájl neve String-ként * length() -- A fájl mérete long-ként * createNewFile() -- Azonos nevű fájl létrehozása, ha még nem létezik * delete() -- A fájl törlése, ha létezik * renameTo(Fájl) -- A fájl átnevezése a paraméterben megadott File objektumot használva. A fájl objektum könyvtárakat is jelölhet. Ha egy File objektum könyvtárat jelöl akkor hívható a következő metódus: * listFiles() ==== Olvasás fájlból ==== === Egyszerűen === import java.io.*; class Program2 { public static void main(String args[]) throws IOException { FileReader olvaso = new FileReader("adat.txt"); StringBuilder strb = new StringBuilder(); char ch; while(olvaso.ready()) { ch = (char)olvaso.read(); strb.append(ch); } olvaso.close(); System.out.println(strb); } } === BufferedReader használata === import java.io.*; class readfile { public static void main(String[] argv) throws IOException { FileReader folyam = new FileReader("adat.txt"); BufferedReader fileolvaso = new BufferedReader(folyam); String sor; while ((sor = fileolvaso.readLine()) != null) { System.out.println(sor); } fileolvaso.close(); } } === Három osztály használata === import java.io.*; public class ap { public static void main(String[] args) throws IOException { File f = new File("adat.txt"); FileReader fr = new FileReader(f); BufferedReader bemenet = new BufferedReader(fr); boolean vege = false; String s; while(!vege) { s = bemenet.readLine(); if (s != null) System.out.println(s); else vege = true; } bemenet.close(); } } === Olvasás Scanner osztállyal === import java.io.*; import java.util.*; class readfile2 { public static void main(String[] argv) throws IOException { Scanner olvaso = new Scanner(new FileReader("adat.txt")); while(olvaso.hasNextLine()) { System.out.println(olvaso.nextLine()); } } } === Újabb példa === import java.io.*; class readfile { public static void main(String[] argv) throws IOException { FileReader folyam = new FileReader("adat.txt"); BufferedReader fileolvaso = new BufferedReader(folyam); String sor = null; do { sor = fileolvaso.readLine(); System.out.println(sor); }while (sor != null); fileolvaso.close(); } } === A File és a Scanner osztály használata === import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; class Program01 { public static void main(String[] args) throws FileNotFoundException { File f = new File("adat.txt"); Scanner bef = new Scanner(f); while(bef.hasNextLine()) { System.out.println(Integer.parseInt(bef.nextLine())); } } } === Fájl olvasása kivételkezelésével === A kivételek kezelését sokan a úgy oldják meg, hogy a fájlkezelő utasításokat egy try..catch szerkezetbe ágyazzák. Például így: import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; class Program01 { public static void main(String[] args) { File f = new File("adat.txt"); try { Scanner fin = new Scanner(f); while(fin.hasNextLine()) { System.out.println(Integer.parseInt(fin.nextLine())); } } catch (FileNotFoundException ex) { ex.printStackTrace(); } } } A kivétel elkapásának persze akkor van értelme, ha magunk akarunk valamilyen szöveges üzenetet megjeleníteni. Ekkor a szöveges üzenet a catch() { } blokkba kerül. === Fájlbeolvasás korrekt kivételkezeléssel === A fenti kivételkezeléses példában a fájlkezelő utasításokat a try..catch szerkezetbe ágyaztuk. Ez nem valami elegáns, ráadásul átláthatatlanná teszik a szépen megírt fájlkezelő blokkunkat. A következő példában a kivételt eldobjuk a fájlkezelő részben, és mellette létrehozunk egy hasonló nevű függvényt, amelynek a feladata csak a kivétel kezelése. import java.io.FileNotFoundException; import java.io.File; import java.util.Scanner; public class FileBeolvas { public static void beolvas() { try { tryBeolvas(); }catch(FileNotFoundException ex) { System.err.println("A fájl nem található"); } } public static void tryBeolvas() throws FileNotFoundException { File f = new File("adat.txt"); Scanner olvaso = new Scanner(f); while(olvaso.hasNextLine()) { System.out.println(olvaso.nextLine()); } } public static void main(String[] args) { beolvas(); } } Vegyük észre a fájlkezelő metódus, amelynek a neve beolvas() volt fentebb, most át lett nevezve tryBeolvas()-ra. A hibakezelő metódus kapta a beolvas() nevet. A hibakezelő metódusból hívjuk meg a tryBeolvas() metódust. ==== Fájlba írás ==== === Egyszerű fájlba írás === import java.io.*; class Program { public static void main(String args[]) throws IOException { FileWriter iro = new FileWriter("adat.txt", true); iro.write("joska:titok:gazdasag:Szolnok\n"); iro.flush(); iro.close(); System.out.println("Kiírva"); } } A konstruktorban a második paraméter true, azt jelenti hozzáfűzünk az állományhoz. Ez a paraméter nem kötelező. Ha nem adjuk meg alapértelmezetten felülírjuk az állományt. === BufferedWriter használata === import java.io.*; class Program3 { public static void main(String args[]) throws IOException { FileWriter firo = new FileWriter("adat2.txt", true); BufferedWriter iro = new BufferedWriter(firo); iro.write("Valai"); iro.close(); firo.close(); System.out.println("Kiírva"); } } === PrintWriter használata === import java.io.*; class Program4 { public static void main(String args[]) throws IOException { FileWriter firo = new FileWriter("adat2.txt", true); PrintWriter iro = new PrintWriter(firo); iro.println("Valai"); firo.close(); System.out.println("Kiírva"); } } === Összetettebb fájlba írás === import java.io.*; public class ap { public static void main(String[] args) throws IOException { File f = new File("adat.txt"); FileWriter kifolyam = new FileWriter(f); // Ha hozzáfűzni akarunk akkor FileWriter(f, true); PrintWriter kimenet = new PrintWriter(kifolyam); kimenet.println("alma"); kimenet.println("körte"); kimenet.println("szilva"); kimenet.println("barack"); kimenet.close(); } } ==== Fájl sorainak olvasása darabolással ==== import java.io.*; import java.util.*; public class ap { public static void main(String[] args) throws IOException { File f = new File("adat.txt"); FileReader bemenet_folyam = new FileReader(f); BufferedReader bemenet = new BufferedReader(bemenet_folyam); boolean vege = false; String s, gyumolcs; int sorszam, suly; while(!vege) { s = bemenet.readLine(); if (s != null) { StringTokenizer Tokenek = new StringTokenizer(s); sorszam = Integer.valueOf(Tokenek.nextToken()).intValue(); suly = Integer.valueOf(Tokenek.nextToken()).intValue(); gyumolcs = Tokenek.nextToken(); System.out.println(sorszam + " " + suly + " " + gyumolcs); } else vege = true; } bemenet.close(); } } ==== Fájl olvasása karakterenként ==== InputStream in = new FileInputStream("adat.txt"); Reader r = new InputStreamReader(in, "US-ASCII"); int intch; while ((intch = r.read()) != -1) { char ch = (char) intch; //... } ==== Az util csomag használata ==== import java.io.*; import java.util.*; class Program { private static String fajlOlvas(String path) { File file = new File(path); Scanner olvaso = null; StringBuilder strb = new StringBuilder((int)file.length()); try { olvaso = new Scanner(file); } catch(IOException e) { e.printStackTrace(); } String sorTores = System.getProperty("line.separator"); try { while(olvaso.hasNextLine()) strb.append(olvaso.nextLine() + sorTores); return strb.toString(); } finally { olvaso.close(); } } public static void main(String[] args) { String str = fajlOlvas("adat.txt"); System.out.println(str.replace("m", "g")); } } Egy rövid példa: import java.util.Scanner; import java.io.File; import java.io.IOException; class Program { public static void main(String[] args) throws IOException { File file = new File("adat.txt"); Scanner olvaso = new Scanner(file); System.out.println(olvaso.nextLine()); System.out.println(olvaso.nextLine()); } } Vegyük észre, hogy itt nem olvasunk a fájl végéig. A fájl végéig olvasáshoz: while(olvaso.hasNextLine()) strb.append(olvaso.nextLine() + sorTores); ==== Olvasás byte tömbbe ==== import java.io.*; import java.util.*; class Program { private static String readFileAsString(String filePath) throws IOException { byte[] buffer = new byte[(int) new File(filePath).length()]; FileInputStream f = new FileInputStream(filePath); f.read(buffer); return new String(buffer); } public static void main(String[] args) throws IOException { String str = readFileAsString("adat.txt"); System.out.println(str); } } ==== Karakterkódolás beállítása ==== Néhány megadható kódolás: * UTF-8 * ISO-8859-1 * Windows-1252 * US-ASCII További kódokat, a java.nio.charset.Charset osztály dokumentációja biztosít. UTF-8 kódolással, Linuxon és Windowson is helyesen látszanak az ékezetek. Scanner nFile = new Scanner(new File(fileName), "UTF-8"); vagy: try { String fileName = "adat.txt"; Reader r = null; try { InputStream in = new FileInputStream(fileName); //US-ASCII r = new InputStreamReader(in, "UTF-8"); } catch(UnsupportedEncodingException e) {} Scanner nFile = new Scanner(r); while(nFile.hasNextLine()) { String str = nFile.nextLine(); System.out.println(str); } nFile.close(); } catch(FileNotFoundException e) { System.err.println("Hiba a fájlból olvasás során"); } Stream osztállyokkal: import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.BufferedReader; class Program01 { public static void main(String args[]) throws IOException { OutputStreamWriter fout = new OutputStreamWriter(new FileOutputStream("adat.txt"), "UTF-8"); fout.write("almaáűé"); fout.flush(); fout.close(); System.out.println("Kiírva"); InputStreamReader fin = new InputStreamReader(new FileInputStream("adat.txt"), "UTF-8"); BufferedReader in = new BufferedReader(fin); System.out.println(in.readLine()); } } Karakterkódolás a Scanner osztállyal: import java.util.Scanner; import java.io.FileNotFoundException; import java.io.File; class Program01 { public static void main(String[] args) { Scanner nFile = null; try { nFile = new Scanner(new File("adat.txt"), "UTF-8"); } catch(FileNotFoundException ex) { System.err.println("Nemlétező fájl"); } String str = nFile.nextLine(); System.out.println(str); nFile.close(); } } ==== Típusos fájl ==== import java.io.BufferedOutputStream; import java.io.BufferedInputStream; import java.io.DataOutputStream; import java.io.DataInputStream; import java.io.FileOutputStream; import java.io.FileInputStream; class Program01 { public static void main(String[] argv) throws Exception { FileOutputStream fileOut = new FileOutputStream("data.txt"); BufferedOutputStream bufferOut = new BufferedOutputStream(fileOut); DataOutputStream dataOut = new DataOutputStream(bufferOut); dataOut.writeUTF("árvíztűrő"); dataOut.writeLong(34L); dataOut.writeInt(44); dataOut.writeDouble(32.343); dataOut.writeBoolean(true); dataOut.close(); bufferOut.close(); fileOut.close(); FileInputStream fileIn = new FileInputStream("data.txt"); BufferedInputStream bufferIn = new BufferedInputStream(fileIn); DataInputStream dataIn = new DataInputStream(bufferIn); System.out.println(dataIn.readUTF()); System.out.println(dataIn.readLong()); System.out.println(dataIn.readInt()); System.out.println(dataIn.readDouble()); System.out.println(dataIn.readBoolean()); dataIn.close(); bufferIn.close(); fileIn.close(); } } A sorrendet tartani kell. ==== Véletlen hozzáférésű fájlok ==== === Írás fájlba === import java.io.*; class Program01 { public static void main(String args[]) throws IOException{ System.out.println("Hi"); RandomAccessFile file = new RandomAccessFile("adat.txt", "rw"); file.seek(12); file.write("Hello World".getBytes()); file.close(); } } A seek() metódussal a 12-es helyre állítom a fájlmutatót. Ha üres a 12 pozíció előtt a fájl, akkor NUL értékekkel tölti fel. === UTF karakterek írása és olvasása === import java.io.*; class Program01 { public void kiir() throws IOException { System.out.println("Kiírás"); RandomAccessFile file = new RandomAccessFile("adat.txt", "rw"); file.seek(20); file.writeUTF("alma"); file.seek(40); file.writeUTF("körte"); file.seek(60); file.writeUTF("barack"); file.seek(80); file.writeUTF("szilva"); file.close(); } public void olvas() throws IOException { RandomAccessFile file = new RandomAccessFile("adat.txt", "r"); file.seek(40); System.out.println(file.readUTF()); file.seek(60); System.out.println(file.readUTF()); file.close(); } public static void main(String args[]) throws IOException{ new Program04().kiir(); new Program04().olvas(); } } ==== Gyakorlat ==== * Sorolja fel, milyen osztályok használata jöhet szóba fájlkezelés esetén. * Mondjon egy osztály, amellyel egy állomány végéhez fűzhetünk sorokat. * Milyen osztályok használata esetén adhatjuk meg a karakterkódolást is fájlból olvasás során? ===== Típus ellenőrzés ===== ==== Kivételek használata ==== Ellenőrizi szeretnénk, hogy valóban szabályosan valós szám lett beírva: try { double a = be.nextDouble(); } catch (Exception e) { System.out.println("Nem valós szám!"); } Ha nem így történt, hibaüzenetet küldünk. Ügyeljünk arra, hogy a forrásban ugyan tizedes pontot használunk, de a bekérésnél tizedes vesszőt vár a java. Ugyanez egész számmal: try { int a = be.nextInt(); } catch (Exception e) { System.out.println("Nem egész szám!"); } Teljes példa a Scanner osztály használatára: import java.io.*; import java.util.*; class Tip { public static void main(String args[]) throws IOException { System.out.println("Típusellenőrzés"); Scanner be = new Scanner(System.in); System.out.print("Szám: "); try { int a = be.nextInt(); } catch (Exception e) { System.out.println("Nem egész szám"); } System.in.read(); } } Teljes példa BufferedReader osztály használata esetén import java.io.*; class Tip { public static void main(String args[]) throws IOException { System.out.println("Típusellenőrzés"); InputStreamReader befolyam = new InputStreamReader(System.in); BufferedReader be = new BufferedReader(befolyam); String s; int szam; System.out.print("Szám: "); s = be.readLine(); try { szam = Integer.valueOf(s).intValue(); } catch(Exception e) { System.out.println("Gond van konverzióval"); } System.in.read(); } } Konverziónál, használhatjuk a NumberFormatException kivételt is: try { szam = Integer.valueOf(s).intValue(); } catch(NumberFormatException e) { System.out.println("Gond van konverzióval"); } ==== Függvény megírásával ==== import java.io.*; class Tipusv { public static void main(String args[]) throws IOException { System.out.println("Hi"); InputStreamReader befolyam = new InputStreamReader(System.in); BufferedReader be = new BufferedReader(befolyam); String s = be.readLine(); if (isInteger(s)) System.out.println("Egész szám"); else System.out.println("Nem egész szám"); System.in.read(); } static public boolean isInteger(String bemenet) { try { Integer.parseInt(bemenet); return true; } catch(Exception e) { return false; } } /* isInteger */ } ==== Reguláris kifejezések használata ==== import java.io.*; class Tipusv { public static void main(String args[]) throws IOException { System.out.println("Hi"); InputStreamReader befolyam = new InputStreamReader(System.in); BufferedReader be = new BufferedReader(befolyam); String s = be.readLine(); if(s.matches("((-|\\+)?[0-9]+(\\.[0-9]+)?)+")) System.out.println("Szám"); else System.out.println("Ez nem szám"); System.in.read(); } } Ez a kódrész elfogad előjeleket és tizedespontot is. ==== text csomag ==== import java.io.*; import java.text.*; class Tipusv { public static void main(String args[]) throws IOException { System.out.println("Hi"); InputStreamReader befolyam = new InputStreamReader(System.in); BufferedReader be = new BufferedReader(befolyam); String s = be.readLine(); DecimalFormat df = new DecimalFormat("#%"); Number a = 0; try { a = df.parse(s); System.out.println("Szám: " + a.doubleValue()); } catch(Exception e) { System.out.println("Nem megfelelő formátum" ); } System.in.read(); } } Példaformátum leírás: "#,##0.00%" "#,##0.00" A Number típusú objektum metódusai. | byte | byteValue() | Az adott szám bájt értékével tér vissza | | abstract double | doubleValue() | Az adott számot doulbe-ként adja vissza | | abstract float | floatValue() | Az adott számot float-ként adja vissza | | abstract int | intValue() | Az adott számot int-ként adja vissza | | abstract long | longValue() | Az adott számot long-ként adja vissza | | short | shortValue() | Az adott számot short-ként adja vissza | import java.io.*; import java.text.*; class Tipusv { public static void main(String args[]) throws IOException { System.out.println("Hi"); InputStreamReader befolyam = new InputStreamReader(System.in); BufferedReader be = new BufferedReader(befolyam); String s = be.readLine(); NumberFormat df = NumberFormat.getInstance(); Number a = 0; try { a = df.parse(s); System.out.println("Szám: " + a.doubleValue()); } catch(Exception e) { System.out.println("Nem megfelelő formátum" ); } System.in.read(); } } ===== Metódusok létrehozása ===== ==== Statikus metódusok ==== Ha már nagyon sok utasításunk van, azokat csoportosítani szoktuk, adunk neki egy nevet, majd a nevével hivatkozva hívjuk meg az összes utasítást. Például szeretnénk egy névjegykártyát kiíratni, amelyen szerepel a nevünk, címünk, telefonszámunk, e-mail címünk, weblapunk. class Program { static void nevjegy() { System.out.println("Nagy József"); System.out.println("Budapest"); System.out.println("Tél u. 3."); System.out.println("+36 (30) 123-4567"); System.out.println("nagy@valaholdomain.hu"); System.out.println("http://valaholdomain.hu"); } public static void main(String[] args) { nevjegy(); } } A fenti példában a metódus fej része így néz ki: static void nevjegy() * ( ) * A név után tettünk egy nyitó és egy bezáró zárójelet. * static * A static egy módosító, amely megmondja, hogy a metódust akkor is használhatjuk, ha nem hoztunk létre az osztályból példányt. * void * A void a visszatérés típusát mondja meg. A void azt jelenti nem térünk vissza semmivel. * { } * Az utasításokat a kapcsos zárójelekkel fogom össze egyetlen blokká. Néha a metódusainknak szeretnénk bemenő paramétereket megadni. Például, szeretnénk egy szám négyzetét venni. Ekkor a metódusnak paraméterkén megadhatjuk mi legyen ez a szám. class Program { static void negyzet(double szam) { System.out.println(szam * szam); } public static void main(String[] args) { negyzet(3.5); } } Előfordulhat, hogy a kapott számot nem képernyőre szeretném íratni, hanem szeretném azt megkapni, továbbszámolás céljára. Ekkor a metódust úgy kell megírni, hogy adja vissza a kért értéket. Maradva a fenti négyzetszámító programnál, alakítsuk úgy át a programot, hogy adja vissza az adott szám értékét. class Program { static double negyzet(double szam) { return szam * szam; } public static void main(String[] args) { System.out.println(negyzet(3.5)+2); } } Vegyük észre, hogy a metódusainkat az osztályon belül hoztuk létre, static kulcsszóval láttuk el, ennek hatására az osztály példányosítása nélkül tudjuk azokat használni. A metódusoknak egész sorozatát hozhatjuk létre: class Program { static double dupla(double szam) { return 2 * szam; } static double negyzet(double szam) { return szam * szam; } static double felez(double szam) { return szam / 2; } public static void main(String[] args) { System.out.println(Program.negyzet(3.0)); System.out.println(Program.dupla(3.0)); System.out.println(Program.felez(3.0)); } } ==== Példánymetódus ==== Az alábbi példában a metódust a static kulcsszó nélkül hozzuk létre. A használata ebben az esetben csak példányosítással lehetséges. class Program { double negyzet(double szam) { return szam * szam; } public static void main(String[] args) { Program program = new Program(); System.out.println(program.negyzet(3.5)+2); } } Metódusok egész sorozata: class Program { double dupla(double szam) { return 2 * szam; } double negyzet(double szam) { return szam * szam; } double felez(double szam) { return szam / 2; } public static void main(String[] args) { Program program = new Program(); System.out.println(program.negyzet(3.0)); System.out.println(program.dupla(3.0)); System.out.println(program.felez(3.0)); } } ==== Metódusok külön osztályban ==== class Szamitas { double dupla(double szam) { return 2 * szam; } double negyzet(double szam) { return szam * szam; } double felez(double szam) { return szam / 2; } } class Program { public static void main(String[] args) { Szamitas szamitas = new Szamitas(); System.out.println(szamitas.negyzet(3.0)); System.out.println(szamitas.dupla(3.0)); System.out.println(szamitas.felez(3.0)); } } ==== Paraméterátadás ==== Ha készítek egy metódust, a bemenő paramétereket **formális paraméternek** is nevezzük. Ezzel szemben az **aktuális paraméter**, a metódus hívásának helyén behelyettesített változók. A Java nyelvben a paraméterek **érték szerint** kerülnek átadásra. Másként szólva, ha egy metóduson belül megváltoztatom egy formális paraméter értéket, ez nem érinti az aktuális paraméter értékét. Ha nem alaptípusokat használunk paraméterként az átadás már nem érték szerint történik. A következő példában egyszerű típust adunk át paraméterként: class Program01 { public static void szamol(Integer szam) { szam = szam * 2; System.out.println(szam); } public static void main(String[] args) { Integer szam = 4; szamol(szam); System.out.println(szam); } } Eredmény: 8 4 A következő példában referencia típus adunk át: class Dolog { int szam = 1; } class Program01 { public static void szamol(Dolog dolog) { dolog.szam = dolog.szam * 2; System.out.println(dolog.szam); } public static void main(String[] args) { Dolog dolog = new Dolog(); dolog.szam = 4; szamol(dolog); System.out.println(dolog.szam); } } Eredmény: 8 8 Az utóbbival egyező eredményt kapunk tömbökkel, mivel azok is referenciák: class Program01 { public static void szamol(int[] t) { t[0] = t[0] * 2; System.out.println(t[0]); } public static void main(String[] args) { int[] t = new int[2]; t[0] = 4; t[1] = 10; szamol(t); System.out.println(t[0]); } } Eredmény: 8 8 ===== Több fájl ===== Ha már sok osztályunk van érdemes azokat külön állományban tárolnunk. A következő két fájl egyszerűen egy könyvtárban használom. class Program01 { public static void main(String args[]) { Program02 prog = new Program02(); prog.kiir(); } } class Program02 { public void kiir() { System.out.println("Másik osztály"); } } ===== Saját osztályaink "becsomagolása" ===== Ha még több saját osztályunk van azokat külön állományokba rakjuk és becsomagoljuk. Abban a fájlban ahol az osztályaink el vannak helyezve, az állomány elején egy package Csomagnév; utasítást kell elhelyeznünk. Egy osztály importálása egy csomagból az import utasítás után megadott csomagnév.Osztály; formában történhet. Ilyen formában: import csomagnév.Osztály; Ha "*" karaktert használunk, akkor a csomag összes osztályát használatba vettük. Minden csomag számára saját könyvtárat kell létrehozni. A csomag osztályainak .class állományait ide be kell másolni. import sajat.*; class Program01 { public static void main(String args[]) { Program02 ketto = new Program02(); ketto.kikuld(); Program03 harom = new Program03(); harom.kikuld(); } } package sajat; public class Program02 { public void kikuld() { System.out.println("Második"); } } package sajat; public class Program03 { public void kikuld() { System.out.println("Harmadik"); } }