Első teendők¶
- Java JDK telepítése saját számítógépre.
- Fejlesztőkörnyezet telepítése saját számítógépre. Otthon bárki bármit használhat, a kabinetben azonban nincs fent a világ összes fejlesztőkörnyezete, így célszerű otthon is olyat használni, ami a kabinetben is rendelkezésre áll. Mi az IntelliJ IDEA-t ajánljuk.
- Bíró regisztráció (mindkét Bírón)
Figyelem!
A Bíróhoz való belépés ellenőrzése, szükség esetén a problémák megoldása. Aki nem tette volna meg korábban, az regisztráljon a Bíróba ezen és ezen a linkeken. Mindkettőn! Ha valaki nem biztos abban, hogy már regisztrált, az inkább regisztráljon újra. A Bíróba történő regisztráció nem volt szükséges a Programozás alapjai gyakorlat teljesítéshez!
A Java használatával, telepítésével kapcsolatos, gyakori problémák és megoldásuk angol nyelven. Ha valakinek ezektől eltérő problémája van, az keresse meg a gyakorlatvezetőjét e-mailben, vagy pedig az összevont színtér kurzusfórumán jelezze a problémát.
Videók
A gyakorlatok anyagát megpróbáljuk színesíteni és érthetőbbé tenni azzal, hogy mindaz, ami itt elolvasható, gyakorlatban is látható legyen egy-két példán keresztül, akár több gyakorlatvezető interpretálásában. Természetesen ezek nem helyettesítik az órára járást (a gyakorlatok látogatása kötelező), de segíthet egy-egy téma jobb megértését, illetve betegség esetén is nagy segítség lehet.
- Üdvözlünk a kurzuson: https://youtu.be/dwpRekuonHM.
- Hogy valójában miről is szól a kurzus? Első ránézésre a Java nyelvről, de sokkal inkább az objektumokról, objektumorientált gondolkodásról: https://youtube.com/playlist?list=PLGlj9VbLRrjBoIrYBE410Y3DjzYd-x8EI.
A fordított nyelvekről¶
A fordított programozási nyelvek olyan nyelvek, ahol a forráskódot először egy fordítóprogram (compiler) alakítja át gépi kódra, majd az átalakított, lefordított kódot tudjuk futtatni. A fordítási folyamat több lépésből áll, melyek vázlatosan: először a fordító ellenőrzi a kód szintaktikai helyességét, majd gépi kódra fordítja azt, végül pedig egy futtatható állományt hoz létre. A fordítás eredménye általában egy önállóan futtatható program, ami közvetlenül az adott architektúra által értelmezhető utasításokat tartalmaz. Általában a lefordított, bináris gépi kódú alkalmazások hardverfüggő és operációs rendszer függő utasításokat is tartalmaznak.
A fordított nyelvek előnye, hogy a programok általában gyorsabban futnak, mivel a kódot nem kell futtatás közben értelmezni. További előny a fordítás során végzett típusellenőrzés, ami segít a hibák korai felderítésében. Ugyanakkor hátrányuk, hogy a programot minden támogatni kívánt platformra külön le kell fordítani, és a fejlesztési ciklus hosszabb lehet a fordítási idő miatt. Klasszikus példák a fordított nyelvekre a C, C++, Rust és Go. A Java különleges eset: bár fordított nyelv, a fordító nem közvetlenül gépi kódot, hanem platformfüggetlen bájtkódot állít elő, amit aztán a Java Virtual Machine (JVM) futtat. Ez biztosítja a "Write Once, Run Anywhere" elvet (amivel a kezdetek kezdetén reklámozták a Java nyelvet), miközben megtartja a fordított nyelvek előnyeinek jelentős részét.
Hogyan néz ki ez a gyakorlatban?
Pythonban csak simán elindíthattuk az alkalmazást a python fajl.py
paranccsal, azonban Java esetén a program futtatása előtt még le kell fordítanunk a forrásfájljainkat. De természetesen egy kevésbé buta IDE-ben ez a folyamat automatizálható, azonban ha magunk fordítjuk a programot, erre figyelni kell, mivel hibaforrás lehet.
Java nyelvről röviden¶
- Az Oracle angol nyelvű bevezetője.
- Platformfüggetlen programozási nyelv.
- Erősen típusos programozási nyelv
- JVM: Java Virtual Machine - Java virtuális gép
- A Java virtuális gép minden architektúrán különbözik
- Bájtkód: Egy olyan bájtsorozat, amely a JVM által végrehajtható utasításokat tartalmaz.
- JIT (Just In Time) - Futás idejű "fordítás".
- a nyelv felépítésének koncepciója
- a Java forrásfájlok tartalmazhatnak Unicode, pl.: UTF-8 karaktereket is
A kép forrása, ahol bővebben olvashatsz a Java virtuális gép működéséről.
Java ökoszisztéma¶
Ahhoz, hogy Java programokat tudjunk futtatni, illetve fejleszteni, szükségünk lesz egy fordító- és futtatókörnyezetre, valamint egy fordítóprogramra. A kész programunk futtatásához mindösszesen a JRE (Java Runtime Environment) szükséges, ami biztosítja a Java alkalmazások futtatásának minimális követelményeit, mint például a JVM (Java Virtual Machine). A fejlesztéshez szükségünk lesz a JDK-ra (Java Development Kit) is. Ez tartalmazza a Java alkalmazások futtatásához, valamint azok készítéséhez, fordításához szükséges programozói eszközöket is (tehát a JRE-t nem kell külön letölteni, a JDK tartalmazza).
A jelenleg elérhető legfrissebb Java disztribúciók már nem kínálnak külön letölthető JRE és JDK csomagokat, ezeket együttesen tudjuk letölteni. A Java beszerzéséről és telepítéséről itt írtunk bővebben.
Első Java nyelvű programunk¶
A kapcsolódó Oracle oldal.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!"); //Kiírja, hogy Hello World!
}
}
Ahogy látható, itt egy kicsit bonyolultabb a helyzet, mint a Python esetében volt. Az alábbiakban megnézzük a főbb különbségeket:
Típusok
Egyrészt, Javaban már megjelennek a típusok, ezeket mindenhol használnunk kell majd. Nem készíthetünk változót anélkül, hogy ne adnánk meg egy explicit típust. A típusokról lentebb olvashatunk.
Szintaxis-beli különbségek
A Pythonban nem találkozhattunk explicit blokkszintaxissal, az indentálás (behúzás) mértéke jelölte, hogy melyik kódrészlet melyik blokkhoz tartozik.
Ezzel szemben Javaban hagyományos blokkszintaxist használunk, kapcsoszárójelek formájában.
Minden, ami egy {
és }
között van, azonos blokkban van.
Furcsa lehet, hogy Javaban az utasítások végén kötelező pontosvesszőt használni.
Minden végrehajtható utasítás, értékadás, metódushívás vagy deklaráció után kötelező kitenni.
A pontosvessző hiánya fordítási hibát eredményez.
Nem kell pontosvesszőt tennünk azonban a blokkok ({ }
), az osztály- és metódusdeklarációk, valamint a vezérlési szerkezetek fejléce (például if
, for
, while
) után.
A pontosvessző lehetővé teszi több utasítás írását egy sorba, bár ezt a gyakorlatban ritkán használjuk, mert rontja a kód olvashatóságát, így ezeket lehetőség szerint hanyagoljuk.
Java esetében nem írhatunk "csak úgy" függvényeket, mindent bele kell tennünk egy osztályba (az, hogy ez micsoda, miért jó, később részletesen taglaljuk).
Belépési pont
Számos programozási nyelvben (Javaban is) a futtatható programoknak kell, hogy legyen belépési pontja, ezt általában main
függvénynek kell elneveznünk.
Ez egy speciális metódus, amelynek pontos fejléce (szignatúrája): public static void main(String[] args)
(esetleg olyat is láthatunk, hogy String...
, de ez ugyanazt jelenti).
Minden futtatható Java programnak tartalmaznia kell ezt a függvényt, mivel a JVM (Java Virtual Machine) ezt keresi és hívja meg először a program indításakor.
Ha nem csinálunk belépési pontot, akkor a programunk nem fog működni, hibát kapunk, amikor szeretnénk majd futtatni.
Gondoljunk a Pythonra
A Python nem követeli meg külön belépési pont definiálását, egyszerűen "sorról sorra" (fentről lefelé haladva) hajtja végre a kódot. Python esetében gyakran találkozhatunk az if __name__ == "__main__":
szerkezettel, ami hasonló célt szolgál, mint a main
függvények, de ezek használata nem kötelező. A szerkezet használata lehetővé teszi, hogy ugyanaz a fájl modulként importálva és közvetlenül futtatva is használható legyen.
Részletesen a main metódusról:
public
: a metódus kívülről is elérhető, ez szükséges ahhoz, hogy a JVM megtalálja a metódust.static
: az osztály példányosítása nélkül futtatható, ez szükséges ahhoz, hogy a JVM megtalálja a metódust.void
: a metódus nem ad vissza értéket (Python-ban nem kell megadni visszatérési típust), Java esetén viszont mindenképpen kell egy visszatérési típust megadnunk. Ha a metódus nem tér vissza semmivel, ez avoid
lesz.main
: a metódus neve kötelezően "main"String[] args
: parancssori argumentumok tömbje (Python-bansys.argv
)
Fordítás, futtatás¶
Az elkészült fájlt mentsük el HelloWorld.java
néven.
Fontos, hogy mindig olyan néven mentsük el a fájlt, ami a publikus osztályunk neve (ami a public class
után van).
Jelen esetben bármilyen nevet adhatunk az osztálynak (és egyben a fájlnak), csak arra figyeljünk oda, azonos néven mentsük el.
Fordítás¶
Most már csak maga a fordítás, majd a program futtatása van hátra.
Az elkészült programokat a parancssorból a javac
paranccsal fordíthatjuk le (ami a telepített Java fordító binárisa), a következőképp: javac FájlNeve.java
, jelen esetben javac HelloWorld.java
.
(A Java fordítóról, kapcsolóiról bővebben olvashatsz ezen az oldalon.)
Normál esetben a parancs kiadása után semmilyen válasz sem érkezik, csak visszakapjuk a kurzort egy idő után.
A fordítás befejezése után látnunk kell a HelloWorld.java
fájl mellett egy HelloWorld.class
nevű fájlt is, ami a fordítás után jött létre.
Ez a fájl tartalmazza az elkészült Java bájtkódot, amelyet aztán hordozhatunk, és bármely gépen futtathatjuk, ahol van egy Java virtuális gép (azaz a célszámítógépen telepítve van a JDK).
Futtatás¶
Az elkészült alkalmazás futtatása a java
paranccsal történik, melynek használata a következő: java OsztalyNeve arg1 arg2 arg3 ... argN
, jelen esetben java HelloWorld
.
Fontos, hogy a HelloWorld
után nem szerepelhet a .class
kiterjesztés.
A parancs hatására a JRE megkeresi a megadott osztályt a fájlrendszeren, majd miután betöltötte, a benne található main
metódust kezdi el futtatni.
Ha nem találja meg a fájlt, vagy nincs benne main
, hibával fog kilépni.
Megjegyzés
A fordítás után elkészült .class
kiterjesztésű fájlba belenézhetünk a JDK-ban szereplő javap
paranccsal, vagy akár vissza is fejthetjük őket, így itt erre is figyelnünk kell majd a későbbiekben (főleg, ha pénzért szeretnénk eladni a programunkat). Itt különböző obfuszkálási módszereket lehet használni, de ez nem tananyag.
Normál esetben a program futtatása után megjelenik a konzolon a "Hello World!" szöveg.
Alapértelmezett kimenetek¶
Ahogy láthattuk, a Java nyelvben szöveget írhatunk ki a képernyőre a System.out.println()
paranccsal.
Ez viszont nem feltétlenül mindig a terminált jelenti.
A System.out
az alapértelmezett kimenet, ami esetünkben a terminálra volt irányítva.
Ezt természetesen át is lehet állítani, hogy máshova írjunk vele, például egy fájlba.
A kiíratáshoz több függvény is rendelkezésünkre áll:
System.out.print("Ez egy szoveg");
System.out.println("Ez egy szoveg!");
System.out.printf("Ez %d Pythonbol talan ismeros formazott kiiratas\n", 1);
System.out.format("Ez %d Pythonbol talan ismeros formazott kiiratas\n", 1);
Kimenet
Ez egy szovegEz egy szoveg!
Ez 1 Pythonbol talan ismeros formazott kiiratas
Ez 1 Pythonbol talan ismeros formazott kiiratas
A System.out.print
és a System.out.println
között annyi a különbség, hogy az első nem tesz sortörést a kiíratás végére, míg a println
-es változat igen.
A sortörő karakter mindig az adott platform sortörő karaktere, sosem egy beégetett karakter, így a legtöbb, sortörést tartalmazó kiíratásnál célszerű ennek használata.
Az alsó kettő kiíratás pedig a Pythonból is ismerős formázott kiíratás Java megfelelője.
A beégetett \n
, \r\n
karakterek használatát pedig lehetőség szerint mellőzzük, hiszen így a platformfüggetlenség sérülhet.
Egy üres sortörés kiíratásához a legegyszerűbb a System.out.println();
utasítást használni.
Ha mindenáron szeretnénk használni egy kiíratáson belül sortörtést, akkor a sortörő karakter helyett a System.lineSeparator()
utasítással kérhetünk egy adott platformra megfelelő sortörő karaktert.
Az eddig tanult kiíratáshoz hasonló az alapértelmezett (vagy default) hibakimenet, melynek fogalma szintén ismerős lehet.
Ez Javaban a System.err
, amire a már látott módon írhatunk ki.
Ez hibaüzenetek közlésére szolgál.
Használata teljesen megegyezik a System.out
használatával, egyetlen szemmel látható különbsége, hogy a fejlesztőkörnyezet belső konzolján a System.err
-re kiírt szöveg pirossal jelenik meg.
Az egyszerű terminál használatakor ez az alapértelmezett kimenet és hibakimenet megegyezik, így mindkét kimenetet a konzolon látjuk. A két kimenet viszont lehet két különböző helyre is irányítva.
A két kimenet egymáshoz képesti működése aszinkron. Ez azt jelenti, hogy nem feltétlenül pont akkor írja ki a dolgokat, amikor mi utasítjuk rá: ha az alapértelmezett kimenet éppen nem tudja ellátni a feladatát, akkor a kiírandó adat várakozik; miközben lehet, hogy az alapértelmezett hibakemenet szabad, így kódsor szinten hiába írtunk ki előbb az alapértelmezett kimenetre, majd pedig a hibakimenetre, lehet hogy a konzolon előbb jelenik meg az, amit a hibakimenetre írtunk. Tehát a következő kódnak két lehetséges kimenetele lehet:
Az egyik kimenetel:
Kimenet
Most hibaüzenet következik:
Ez a hibaüzenet.
A másik pedig:
Kimenet
Ez a hibaüzenet.
Most hibaüzenet következik:
Ebből következik, hogy a hibakimenet NEM használható a szöveg egyszerű színezésére, mert összekavarodhat a mondanivalónk.
Attól persze nem kell félni, hogy a System.out
-ra küldött két üzenet összekeveredik, ezek sorrendben várakoznak.
A gyorsabb munka érdekében az IntelliJ IDEA és az Eclipse is megkönnyíti a kimenetre írást.
- IntelliJ IDEA: A default kimenet eléréséhez egyszerűen beírhatjuk a
sout
szót, majd Ctrl+Space hatására kiegészíthetjükSystem.out.println()
-né, aserr
szót pedigSystem.err.println()
-né. - Eclipse: A default kimenet eléréséhez egyszerűen beírhatjuk a
sysout
szót, majd Ctrl+Space hatására kiegészíthetjükSystem.out.println()
-né, asyserr
szót pedigSystem.err.println()
-né.
Típusok¶
Habár jelen anyagban lévő legtöbb típus ismerős Programozás alapjai tantárgyból, itt szintén bemutatásra kerülnek, a Java szemszögéből.
Erősen típusos programozási nyelvek¶
Az erősen típusos nyelvekben minden változónak szigorúan meghatározott adattípusa van, amit explicit módon deklarálni kell (vagyis meg kell, hogy adjuk) a használat előtt. Például Java-ban:
Ezekben a nyelvekben jellemzően nem lehet különböző típusú értékeket összekeverni vagy implicit módon konvertálni. A típuskonverziót mindig explicit módon kell elvégezni. A fordító már fordítási időben ellenőrzi a típushibákat. Rossz példa:
Egy kis visszaemlékezés Pythonra
A Python dinamikusan típusos nyelv, ami azt jelenti, hogy:
- Nem kell előre deklarálni a változók típusát.
- Egy változó típusa futás közben változhat.
- A Python automatikusan kezeli a típuskonverziókat.
Néhány alapvető típus Javaban¶
Egyszerű (primitív) adattípusok: boolean, char, byte, short, int, long, float, double. Ezek egy része ismerős lehet Pythonból, azonban akadnak eddig ismeretlen típusok is.
Egész számtípusok¶
Előjeles egész számok tárolására szolgáló típus.
A Python int
típusához hasonló, de fontos különbség, hogy míg Pythonban gyakorlatilag bármekkora egész számokat tárolhatunk, az erősen típusos nyelvekben (mint például a Javaban) az int
általában 32 bites (4 byte), ami azt jelenti, hogy -2^31
és (2^31-1
) közötti értékeket tárolhat (-2,147,483,648 és 2,147,483,647 között).
Egész értéket tároló típusból több is létezik Javaban.
Ha a fentinél nagyobb egész számot szeretnénk tárolni, lehetőségünk van long
(64 bit, 8 byte) típust használni, kisebb egész számok esetében pedig használhatjuk a short
(16 bit, 2 byte), esetleg byte
(8 bit, 1 byte) adattípust.
Ennél nagyobb számok tárolására is van lehetőség, azonban ez jelen kurzusnak nem anyaga.
public class EgeszPelda {
public static void main(String[] args) {
// Alap értékadás
byte b1 = 127;
byte b2 = -128;
// Hexadecimális formában
short s1 = 0xFF; // 255 decimálisan
// Bináris formában
int i1 = 0b1010; // 10 decimálisan
// Csak hagyományosan
int szam = 2354;
// Nagy szám, alulvonás használata az olvashatóságért
int i2 = 1_000_000;
// Long típusnál L vagy l "kötelező" a végén
long l1 = 12345678910L;
// int l3 = 12345678910; // túl nagy int lenne
long l2 = 0xFFFFL; // hexadecimális formában
// Értékek kiíratása
System.out.println("byte értékek: " + b1 + ", " + b2);
System.out.println("short érték hexából: " + s1);
System.out.println("int érték binárisból: " + i1);
System.out.println("int érték hagyományos: " + szam);
System.out.println("int érték underscoreval: " + i2);
System.out.println("long értékek: " + l1 + ", " + l2);
}
}
Inkrementálás és dekrementálás¶
Számos nyelv, köztük a Java speciális operátorokat biztosít a számok 1-gyel való növeléséhez és csökkentéséhez.
A ++
operátor eggyel növeli, a --
operátor eggyel csökkenti az értéket.
Ezek az operátorok használhatók prefix (operátor a változó előtt) és postfix (operátor a változó után) módban is.
A prefix változat (++i
) először növeli az értéket, majd visszaadja azt, míg a postfix változat (i++
) először visszaadja az eredeti értéket, és csak utána növeli.
public class InkrementalasPelda {
public static void main(String[] args) {
int a = 5;
// Postfix növelés - először az a értéke íródik ki (5), utána nő
System.out.println("a++ : " + a++); // 5
System.out.println("a értéke most: " + a); // 6
// Prefix növelés - először nő az a értéke, aztán íródik ki
System.out.println("++a : " + ++a); // 7
// Csökkentés hasonlóan működik
System.out.println("a-- : " + a--); // 7
System.out.println("--a : " + --a); // 5
// Ugyanezt el lehet érni így is:
a += 1; // növelés
a -= 1; // csökkentés
}
}
Lebegőpontos számtípusok¶
A lebegőpontos számok (floating-point numbers) lehetővé teszik a tizedes törtek tárolását a programunkban.
A név onnan ered, hogy a tizedesvessző (ami angolul egy pont karakter, ".") "lebeghet", vagyis a szám belső ábrázolása során változtatható a pozíciója.
A Java két típust kínál ezen számokra: a 4 bájtos (32 bites) float
és a 8 bájtos (64 bites) double
típust.
A lebegőpontos számok tárolása az IEEE 754 szabvány szerint történik, amely három részre bontja a szám tárolását: előjel, mantissza és exponens.
Ez a tárolási módszer lehetővé teszi nagyon nagy és nagyon kis számok tárolását is, viszont fontos tudni, hogy a lebegőpontos számok nem mindig pontosak, bizonyos számok nem ábrázolhatók pontosan bináris lebegőpontos formában.
Emiatt a pénzügyi szektorban általában kerülik a használatukat, helyette inkább fixpontos vagy speciális pénzügyi típusokat (például BigDecimal
) használnak.
A double
típus a gyakrabban használt választás, mivel nagyobb pontosságot biztosít, mint a float
.
public class LebegopontosPelda {
public static void main(String[] args) {
// Alap értékadás
float f1 = 3.14f; // f vagy F használata kötelező
float f2 = -45.67F;
// Underscore használata
float f3 = 3.141_592f;
// Tudományos jelölés is megengedett
double d1 = 1.23e2; // 123.0
double d2 = 1.23e-2; // 0.0123
// Hagyományos értékadás
double d3 = 3.1415;
double d4 = 0.333d;
double d5 = 0.333D;
// Underscore használata
double d6 = 1_234.567_89;
// Értékek kiíratása
System.out.println("float értékek: " + f1 + ", " + f2);
System.out.println("double értékek tudományos jelöléssel: " + d1 + ", " + d2);
System.out.println("underscore használata: " + f3 + ", " + d3);
System.out.println("hagyományos kiíratás: " + d4 + ", " + d5);
}
}
Szöveg¶
Javaban a szövegek tárolására a String
típus szolgál.
Célje teljesen ugyanaz, mint a Python-beli str
típusnak, szövegek (karakterláncok) tárolása és kezelése.
Fontos különbség, hogy itt nincs három idézőjelből álló, többsoros szöveg, és a formázott szöveghez sem használhatjuk a %
operátort.
Ezen felül természetesen némileg másképp kell használni a szövegeket, mint Pythonban, de a funkcionalitás jelentős részét Javaban is megtalálhatjuk.
A karakterláncokat csak dupla idézőjelek között adhatjuk meg (pl.: String szoveg = "Hello World";
), ez egy nagyon fontos különbség a Pythonhoz képest.
Ez a típus immutable, vagyis ha létrehoztunk egy szöveget (String objektumot), akkor annak tartalmát később nem tudjuk megváltoztatni, minden szöveges műveletnél valójában egy új szöveg jön létre, ez nagyon hasonló a Pythonhoz.
Szövegek tárolása a memóriában
A JVM (Java Virtual Machine) a szövegliterálokat egy speciális memóriaterületen, a String Pool-ban tárolja az újrafelhasználhatóság érdekében.
A szövegek számos hasznos metódust tartalmaznak, amelyekkel könnyűvé válik a kezelésük:
contains
: visszaadja, hogy a paraméterként átadott szöveget tartalmazza-e a szöveg, amire meghívtuk.endsWith
: visszaadja, hogy a paraméterként átadott szöveggel végződik-e a szöveg, amire meghívtuk.equals()
: stringek összehasonlításaindexOf
: visszaadja, hogy a paraméterként átadott szöveg melyik indexen kezdődik abban a szövegben, amire meghívtuk. -1-gyel tér vissza, ha nem található meg a szövegben a paraméter.isEmpty
: visszaadja, hogy a szöveg üres-e.length
: ez a metódus visszaadja a szöveg hosszát.replace()
: karakterek vagy részstringek cseréjesubstring()
: szövegrész kivágásastartsWith
: visszaadja, hogy a paraméterként átadott szöveggel kezdődik-e a szöveg, amire meghívtuk.toLowerCase
: visszaadja a szöveg kisbetűsített változatát.toUpperCase
: visszaadja a szöveg nagybetűsített változatát.
Stringek összefűzésére használhatjuk a +
operátort.
public class StringPelda {
public static void main(String[] args) {
// String létrehozása
String szoveg = "Hello World";
// Alapvető műveletek
System.out.println("Eredeti szöveg: " + szoveg);
System.out.println("Hossz: " + szoveg.length());
System.out.println("Nagybetűs: " + szoveg.toUpperCase());
System.out.println("Kisbetűs: " + szoveg.toLowerCase());
// Részstring műveletek
System.out.println("Első 5 karakter: " + szoveg.substring(0, 5));
System.out.println("'World' kezdőpozíciója: " + szoveg.indexOf("World"));
// String összehasonlítás
String masikSzoveg = "Hello World";
System.out.println("Egyenlő? " + szoveg.equals(masikSzoveg));
// Csere
System.out.println("World cseréje Java-ra: " + szoveg.replace("World", "Java"));
// Immutable típus
System.out.println("Immutable: " + szoveg);
// String összefűzés
String keresztnev = "Kovács";
String vezeteknev = "Keresztnév";
String teljesNev = keresztnev + " " + vezeteknev;
System.out.println("Összefűzött név: " + teljesNev);
}
}
Hatékony összefűzés
Nagy mennyiségű összefűzés esetén javasolt a StringBuilder
vagy StringBuffer
használata a jobb teljesítmény érdekében.
A szimpla idézőjelek között csak egy karaktert adhatunk meg, ami elkalauzol minket egy új adattípushoz, a karakterhez.
Karakter¶
A char
típus egyetlen Unicode karaktert tárol 16 biten.
Fontos különbség a Stringhez képest, hogy a karaktereket aposztrófok (szimpla idézőjel, '
) között adjuk meg, nem dupla idézőjelek között ("). A karakter típusú változóban tárolhatunk sima karaktereket, számokat (mint karaktereket), valamint speciális karaktereket is escape szekvenciákkal (például \u0041
).
public class CharPelda {
public static void main(String[] args) {
// Alap karakterek
char betu = 'a';
char szam = '5';
// Speciális karakterek
char ujsor = '\n';
char tabulator = '\t';
// Unicode karakterek
char unicode = '\u0041'; // 'A' betű
// Kiíratás
System.out.println("Karakter: " + betu);
System.out.println("Számjegy: " + szam);
System.out.println("Unicode karakter: " + unicode);
// Char műveletetek
betu = 'a' + 1;
System.out.println("A következő karakter: " + betu); // 'b'
}
}
Boolean¶
A boolean
típus logikai értékek tárolására szolgál, csak két értéket vehet fel: true
vagy false
.
Fontos, hogy Java-ban ezeket kisbetűvel írjuk (szemben a Python True/False értékeivel).
public class BooleanPelda {
public static void main(String[] args) {
// Boolean értékek
boolean igaz = true;
boolean hamis = false;
// Logikai műveletek
boolean es = igaz && hamis; // és művelet
boolean vagy = igaz || hamis; // vagy művelet
boolean nem = !igaz; // negálás
// Összehasonlítások
int x = 5;
boolean nagyobb = x > 3;
boolean egyenlo = x == 5;
// Kiíratás
System.out.println("Igaz érték: " + igaz);
System.out.println("És művelet: " + es);
System.out.println("Vagy művelet: " + vagy);
System.out.println("Negálás: " + nem);
System.out.println("Összehasonlítás: " + nagyobb);
}
}
Logikai műveletek Javaban¶
A logikai műveletek Javaban szigorúbban működnek, mint Pythonban.
Míg Pythonban bármilyen érték kiértékelhető logikai értékké (pl. üres lista False
lesz, 0
szintén False
), Java-ban csak a boolean
típusú értékek használhatók logikai műveletekben.
A Java logikai operátorai (&&
, ||
, !
) csak boolean
típusú operandusokkal működnek, és mindig boolean
értéket adnak vissza.
Tehát, ha egy változóról szeretnénk eldönteni, hogy nulla-e az értéke, az if (valtozo){}
nem megfelelő kód, ilyenkor egy logikai kifejezéssé kell alakítanunk: if (valtozo !=0){}
.
Művelet | Python | Java | Megjegyzés |
---|---|---|---|
És | and |
&& |
Java: csak boolean értékekkel |
Vagy | or |
\|\| |
Java: csak boolean értékekkel |
Nem | not |
! |
Java: csak boolean értékekkel |
"Truthy" értékelés | if lista: |
Nem létezik | Java: explicit összehasonlítás kell, pl. if (lista.length > 0) |
Számok | if szam: |
Nem létezik | Java: explicit összehasonlítás kell, pl. if (szam != 0) |
Stringek | if szoveg: |
Nem létezik | Java: explicit összehasonlítás kell, pl. if (!szoveg.isEmpty()) |
Null értékek | if obj is not None: |
Nem létezik | Java: explicit összehasonlítás kell, pl. if (obj != null) |
Tehát Javaban mindig explicit logikai kifejezéseket kell használnunk, nem hagyatkozhatunk arra, hogy egy érték igazra vagy hamisra értékelődik ki.
Vezérlési szerkezetek különbségei¶
Feltételes vezérlés¶
Java-ban kötelező a zárójelezés és a blokkok jelölése is, ezen kívül viszont az if
elég hasonló, elif
helyett else if
szerkezetet kell használnunk.
Ciklusok¶
For¶
Python for ciklusa közvetlenül iterálható objektumokon működik alapvetően, például egy listán, szövegen.
Ezzel szemben Java esetén "hagyományos" for ciklusunk van, ami egy számlásos ismétléses vezérlést valósít meg. Ez három részből áll:
- Inicializálás: a ciklus kezdetekor, egyszer fut le. A ciklusban használt változókat hozzuk itt létre.
- Feltétel: minden egyes ismétléskor újra és újra ellenőrzésre kerül. Amennyiben igaz lesz, a ciklus folytatódik; ha hamis, a ciklus működése befejeződik.
- Léptetés: a ciklusváltozót léptetjuk itt általában.
public class ForPelda {
public static void main(String[] args) {
// Alap for ciklus
for (int i = 0; i < 5; i++) {
System.out.println("Szám: " + i);
}
// Többes léptetés
for (int i = 0; i < 10; i += 2) {
System.out.println("Páros szám: " + i);
}
// Visszafelé számolás
for (int i = 5; i > 0; i--) {
System.out.println("Visszaszámlálás: " + i);
}
}
}
Természetesen bármelyik rész elhagyható, akkor egy üres utasítás kerül az adott rész helyére.
public class ForUresPelda {
public static void main(String[] args) {
int i = 0; // Ciklusváltozó kívül deklarálva
// Üres inicializálás (már létezik az i)
for (; i < 5; i++) {
System.out.println(i);
}
// Üres léptető rész (a cikluson belül léptetünk)
for (int j = 0; j < 5;) {
System.out.println(j);
j++; // Itt léptetünk
}
// Üres feltétel (végtelen ciklus, break-kel állítjuk meg)
for (int k = 0; ; k++) {
System.out.println(k);
if (k >= 5) {
break; // Kilépés a ciklusból
}
}
// Minden rész üres (végtelen ciklus)
int counter = 0;
for (;;) {
System.out.println("Végtelen ciklus: " + counter);
counter++;
if (counter >= 5) {
break;
}
}
}
}
While¶
While ciklus hasonló, de Java-ban kellenek a zárójelek:
Ezzel szemben a do-while egy olyan szerkezet, amely először végrehajtja a ciklus törzsét, és csak utána ellenőrzi a feltételt. Emiatt garantáltan legalább egyszer lefut a törzs, függetlenül a feltételtől (a while végén figyeljünk a pontosvesszőre!).
Szintaxis:
Egy konkrét példa:
public class DoWhilePelda {
public static void main(String[] args) {
int szam = 5;
// A ciklus egyszer mindenképp lefut
do {
System.out.println("A szám értéke: " + szam);
szam--;
} while (szam > 0);
}
}
Tulajdonság | While | Do-while |
---|---|---|
Feltétel ellenőrzése | Ciklus elején | Ciklus végén |
Minimum futási szám | 0 | 1 |
Szintaxis | while (feltétel) { } |
do { } while (feltétel); |
Pontosvessző a végén | Nem kell | Kell |
Tipikus használat | Előfeltételes ismétlés | Utófeltételes ismétlés, input validálás |
A do-while
ciklust gyakran használjuk olyan helyzetekben, amikor biztosan szeretnénk, hogy a ciklus törzse legalább egyszer végrehajtódjon, például felhasználói input validálásnál.
Switch¶
A switch egy olyan vezérlési szerkezet, amely egy változó értékét több konstans értékkel hasonlítja össze.
Lényegében egy elegánsabb és sokszor átláthatóbb alternatívája a több if-else if
utasításból álló szerkezeteknek.
Persze mindkettőt használhatjuk sok esetben, csak ez kevesebb kódolást jelent sokszor, ami így kevesebb hibaforrás is.
Az alapszintaxis a következő:
Az egyes ágak (case) után legtöbbször szokott lenni egy alapértelmezett (default) ág is, a nem kezelt értékekre, de ez opcionális. Itt gyakran valamilyen alapműködés, vagy pedig hibadobás történik.
A switch
szerkezet csak az alábbi típusokkal működik (ezek állhatnak a switch
utasítás után):
- byte, short, char, int (egész típusok)
- enum (felsorolás típus)
- String (szöveges típus)
A break használata kulcsfontosságú lehet, mivel a a kiértékelés az összehasonlítás után is átfolyhat (fall-through) az egyes értékeken.
int honap = 8;
switch (honap) {
case 12:
case 1:
case 2:
System.out.println("Tél");
break;
case 3:
case 4:
case 5:
System.out.println("Tavasz");
break;
default:
System.out.println("Más évszak");
}
Ahogy látható is, ha a hónap 12, 1, 2 értékek valamelyikét veszi fel, a "Tél" íródik ki az alapértelmezett outputra.
public class HetiMenu {
public static void main(String[] args) {
int nap = 3; // szerda
System.out.print("Ma a menü: ");
switch (nap) {
case 1:
System.out.println("Húsleves és rántott hús");
break;
case 2:
System.out.println("Gyümölcsleves és főzelék");
break;
case 3:
System.out.println("Gulyásleves és palacsinta");
break;
case 4:
System.out.println("Zöldségleves és rántott halfilé");
break;
case 5:
System.out.println("Babgulyás és túrós csusza");
break;
case 6:
case 7:
System.out.println("Hétvégi menü: Jókai bableves és Paradicsomos káposzta");
break;
default:
System.out.println("Érvénytelen nap!");
break;
}
}
}
Összegzés: Java vs Python¶
Tulajdonság | Python | Java |
---|---|---|
Blokk jelölés | Indentálás (behúzás) | Kapcsos zárójelek {} |
Utasítás vége | Sortörés | Pontosvessző ; |
If szintaxis | if feltetel: |
if (feltetel) { |
Else if | elif feltetel: |
else if (feltetel) { |
For ciklus | for elem in lista: |
for (int i = 0; i < n; i++) { |
While ciklus | while feltetel: |
while (feltetel) { |
Növelés/csökkentés | x += 1 , x -= 1 |
x++ , x-- , x += 1 , x -= 1 |
Összehasonlítás | == , != |
.equals() stringeknél, == primitív típusoknál |
Logikai operátorok | and , or , not |
&& , || , ! |
Megjegyzések | # vagy ''' |
// vagy /* */ |
String formázás | f"x = {x}" |
String.format("x = %d", x) vagy "x = " + x |
Null érték | None |
null |
Igaz/Hamis | True , False |
true , false |
Beolvasás az alapértelmezett inputról¶
Az alábbiakban bemutatjuk, hogy hogy lehet az alapértelmezett bemenetről beolvasni egy szöveget, számot. Ennek célja, hogy az olvasó elkezdhessen interaktív alkalmazásokat készíteni. Nem célunk, hogy minden részletet megismertessünk, elmagyarázzunk, a részletes ismertetése ennek egyik későbbi gyakorlaton lesz.
A használatához először importálni kell a java.util
csomagból a Scanner
osztályt.
Alapértelmezetten a standard inputról (billentyűzetről) olvas, amit a System.in
paraméterrel jelzünk létrehozáskor: Scanner sc = new Scanner(System.in);
.
A Scanner osztály számos metódust biztosít különböző típusú adatok beolvasására:
nextLine()
: egy teljes sort olvas be String-kéntnext()
: a következő szót (whitespace-ig) olvassa be String-kéntnextInt()
: egész számot olvas benextDouble()
: lebegőpontos számot olvas benextBoolean()
: logikai értéket olvas be
import java.util.Scanner;
public class Beolvasas {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Hello! Hogy hívnak?");
String nev = sc.nextLine();
System.out.println("Hello " + nev + "! Hany eves vagy?");
int kor = sc.nextInt();
System.out.println("Hello " + nev + ", aki " + kor + " eves.");
}
}
Online fejlesztői eszközök¶
Manapság már számos online fejlesztői eszköz közül válogathatunk, amelyek eltérő lehetőségeket, funkciókat kínálnak. Ezek használata hasznos lehet, ha esetleg vendégségben vagyunk vagy olyan számítógép előtt ülünk, ahol nincs Java és nem is telepíthetünk (pl.: nincs adminisztrátori jogosultságunk), esetleg gyorsan, akár tabletről, telefonról szeretnénk egy kódot kipróbálni. Néhány online fejlesztőkörnyezet, melyből válogathatunk: IdeOne, TutorialsPoint Java compiler, CodeChef, Browxy, JDoodle. Otthoni, mindennapos használatra azonban nem javasoljuk őket, mert ezek az eszközök számos limitációval rendelkezhetnek (például a nehézkés/lehetetlen debuggolás).
Videók¶
- Java környezet beüzemelése, minimális Java program írása, fordítása, futtatása: https://youtu.be/I5N5p7orGBU
- Egyszerű program írása, fordítása, parancssori argumentumok használata: https://youtu.be/012UYS3KBjQ
- IntelliJ használata: https://youtu.be/SVJ3G1UDg4k
- Input adatok beolvasása, projekt létrehozása és programozás IDEA-ban: https://youtu.be/Zx3OsETKT94
- Parancssori argumentumok kezelése IntelliJ-ben-ban: https://youtu.be/KjVGkhuZ8Wg
- Parancssori argumentumok, sztringek, sztringek összehasonlítása: https://youtu.be/_uV-qNMCLvM
- Primitív adattípusok, változók, kommentek, hibakeresés : https://youtu.be/Y9xXVu-rLsU
- Javadoc dokumentáció készítése: https://youtu.be/-oZNKjVPCz4
- Input adatok beolvasása, prímszámok keresése: https://youtu.be/6EubCt3k1H4
Feladatok¶
-
Írj egy programot, ami százszor kiír egy tetszőleges szöveget, valamint azt, hogy hányadik kiiratásnál jár éppen!
-
Kérj be egy életkort és írd ki, hogy kiskorú, felnőtt vagy nyugdíjas-e az illető (0-18, 19-65, 65+). Tipp: Használj if-else szerkezetet, figyelj az intervallumokra.
-
Kérj be két számot és egy műveleti jelet (+,-,*,/), majd végezd el a műveletet. Tipp: Használj switch szerkezetet a műveletek kezelésére.
-
Írasd ki a szorzótáblát 1-től 10-ig, szépen formázva.
-
Kérj be egy jelszót újra és újra, amíg nem egyezik a szuperbiztonságos "jelszo123" szöveggel. Tipp: Használj do-while ciklust és String összehasonlítást.
-
Kérj be egy szöveget és számold meg benne a magánhangzókat. Tipp: Használj String metódusokat és for ciklust.
-
Írasd ki a számokat 1-től 100-ig, de a 3 többszöröseinél írj "Fizz"-t, az 5 többszöröseinél "Buzz"-t.
-
Kérj be 7 napi maximum hőmérsékletet és számold ki az átlagot.
-
Kérj be számokat a felhasználótól, amíg 0-át nem ír. Számold meg a páros és páratlan számokat.
-
Írj egy programot, ami bekéri a felhasználó PIN kódját. A felhasználónak 3 próbálkozása van a helyes PIN (1234) megadására. Tipp: Használj for ciklust és megszakítást. A helyes jelszó megadásakor írjon ki egy viccet.
-
Írd ki az összes Armstrong számot 1 és 1000 között. (Egy szám Armstrong szám, ha a számjegyeinek a számjegyek darabszámának megfelelő hatványának összege egyenlő magával a számmal, pl. 153 = 1^3 + 5^3 + 3^3)
-
Készíts egy egyszerű banki tranzakció szimulátort, ahol a felhasználó tud pénzt betenni, kivenni, egyenleget lekérdezni. Minden tranzakcióról készüljön napló (kiírás az alapértelmezett hibakimenetre).