A Java általános célú, objektumorientált programozási nyelv, amelyet James Gosling kezdett el fejleszteni, később átvette a Sun Microsystems fejlesztett a ’90-es évek elejétől kezdve egészen 2009-ig, amikor a céget felvásárolta az Oracle.
A Java alkalmazásokat jellemzően bájtkód formátumra alakítják, de közvetlenül natív (gépi) kód is készíthető Java forráskódból. A bájtkód futtatása a Java virtuális géppel történik, ami vagy interpretálja a bájtkódot, vagy natív gépi kódot készít belőle, és azt futtatja az adott operációs rendszeren. Létezik közvetlenül Java bájtkódot futtató hardver is, az úgynevezett Java processzor.
A Java nyelv a szintaxisát főleg a C és a C++ nyelvektől örökölte, viszont sokkal egyszerűbb objektummodellel rendelkezik, mint a C++. A JavaScript szintaxisa és neve hasonló ugyan a Javához, de a két nyelv nem áll olyan szoros rokonságban, mint azt ezekből a hasonlóságokból gondolhatnánk.
Bár a nyelv neve kezdetben Oak (tölgyfa) volt (James Gosling, a nyelv atyja nevezte így az irodája előtt növő tölgyfáról), később kiderült, hogy ilyen elnevezésű nyelv már létezik, ezért végül Java néven vált ismertté. A Java szó a Oracle védjegye.
Általános tudnivalók A Java nyelvet kávézás közben találták ki, innen ered a kávéscsésze ikon. Négy fontos szempontot tartottak szem előtt, amikor a Javát kifejlesztették: objektumorientáltság; függetlenség az operációs rendszertől, amelyen fut (többé-kevésbé); olyan kódokat és könyvtárakat tartalmazzon, amelyek elősegítik a hálózati programozást; távoli gépeken is képes legyen biztonságosan futni.
Objektumorientáltság A nyelv első tulajdonsága, az objektumorientáltság („OO”), a programozási stílusra és a nyelv struktúrájára utal. Az OO fontos szempontja, hogy a szoftvert „dolgok” (objektumok) alapján csoportosítja, nem az elvégzett feladatok a fő szempont. Ennek alapja, hogy az előbbi sokkal kevesebbet változik, mint az utóbbi, így az objektumok (az adatokat tartalmazó entitások) jobb alapot biztosítanak egy szoftverrendszer megtervezéséhez. A cél az volt, hogy nagy fejlesztési projekteket könnyebben lehessen kezelni, így csökken az elhibázott projektek száma.
A Java szerepe A Java szoftver három igen fontos szerepet tölt be: mint programozási nyelv; mint köztes réteg (middleware); mint platform.
A Java legfontosabb része a Java virtuális gép (Java Virtual Machine – JVM). A JVM mindenütt jelen van (szinte mindenféle berendezés, chip és szoftvercsomag tartalmazza), így a nyelv középszintként és platformként egyaránt működik. Ugyanakkor a nyelv „platformfüggetlen” is, mert a Java virtuális gépek interpretálják a szabványos Java bájtkódot. Ez azt jelenti, hogy egy PC-n megírt Java program minimális módosítás után ugyanúgy fog futni egy javás telefonon is. Innen jön az írd meg egyszer, futtasd bárhol kifejezés. Ez jelentős költségcsökkenést eredményez, mert a kódot csak egyszer kell megírni.
Platformfüggetlenség (hordozhatóság) Ez a tulajdonság azt jelenti, hogy a Java nyelven írt programok a legtöbb hardveren (megközelítőleg) ugyanúgy futnak. Ezt úgy érik el, hogy a Java fordítóprogram a forráskódot csak egy úgynevezett Java bájtkódra fordítja le. Ez azután a virtuális gépen fut, ami az illető hardver gépi kódjára fordítja. Léteznek továbbá szabványos könyvtárcsomagok, amelyek – közvetítve a kód és a gép között – egységes funkcionalitásként teszik elérhetővé az illető hardver sajátosságait (grafika, szálak és hálózat).
Vannak olyan Java-fordítóprogramok, amelyek a forráskódot natív gépi kódra fordítják le – ilyen például a GCJ –, ezzel valamelyest felgyorsítva annak futtatását. Cserébe a lefordított program elveszíti hordozhatóságát.
A Sun Microsystems licence ragaszkodik a különböző Java kivitelezések egymással való összeférhetőségéhez (felcserélhetőségéhez?). Egyes cégek, mint például a Microsoft, mégis platformfüggő sajátságokat adtak a nyelvhez, amire a Sun keményen reagált: beperelte a Microsoftot (az amerikai bíróság 20 millió dollár kártérítésre és a sajátos tulajdonságok visszavonására kötelezte a céget).
Válaszként a Microsoft kihagyta a Java rendszert a jövőbeli termékekből és Windows-változatokból. Ez azt jelenti, hogy az Internet Explorer webböngésző alapváltozataiból hiányzik a Java. Így abban az olyan weboldalak, amelyek Javát használnak, nem fognak helyesen megjelenni. A Windows-felhasználók e problémáját megoldva a Sun és más cégek ingyenesen letölthetővé tették a JVM rendszert azon Windows-változatok számára, amelyekből a virtuális gép hiányzik.
A hordozhatóság megvalósítása technikailag nagyon bonyolult. E közben a Java esetében is sok vita volt. Az „írd meg egyszer, futtasd bárhol” szlogenből „írd meg egyszer, keress hibát mindenhol” lett. 2016-ra a hordozhatóság nem okoz tovább problémát, mivel maga a Java is nyílt szabványokra épül, pl. openGL v. Open POSIX vagy az RFC-k, a Java minden jelentősebb platformon elérhető (Linux, Unix, Windows, más rendszerek pl. AS/400).
Java 2016-ban is sikeres a szerver oldalon a servlet, a JSP és Enterprise JavaBeans, JDBC technológiákkal, integrációs lehetőségeivel, nyelvi eszközeivel, jvm nyelveivel és a nyílt forráskódú közösség tudására is építve.
Biztonságos távoli futtatás A Java rendszer volt az első, amely lehetővé tette a távoli gépeken való futtatást sandboxban (homokozóban). Egy kisalkalmazás futtatható a felhasználó gépén (letöltve a Java kódot egy HTTP kiszolgálóról). A kód egy biztonságos környezetben fut, amely nem engedi meg "rossz szándékú" kód futtatását. A gyártók kiadhatnak olyan tanúsítványokat, amelyeket digitálisan aláírnak, ezzel a nevüket adva ahhoz, hogy a kisalkalmazás biztonságos. Így azok a felhasználó felügyelete alatt léphetnek ki a biztonságos környezetből.
A nyelv A klasszikus „Helló Világ!” Javában A következő egyszerű program kiírja azt, hogy „Helló Világ!” az alapértelmezett kimeneti eszközre (ami általában a konzol, de lehet egy fájl vagy bármi más is). public class HelloVilag { public static void main(String[] args) { System.out.println("Helló Világ!");
Vezérlés Ciklusok while A while egy olyan ciklus, amely a belsejében lévő utasításokat mindaddig ismétlődően végrehajtja, ameddig a megadott feltétel igaz.
while (logikai kifejezés) { utasítás(ok) } do – while A do...while ciklus hasonlóan a while ciklushoz, addig hajtja végre a belsejében lévő utasításokat, ameddig a feltétel igaz. A while és a do...while között annyi a különbség, hogy a while az utasítások lefuttatása előtt kiértékeli feltételt, így ha már az első alkalommal a feltétel hamis, a belsejében lévő utasítások egyszer sem futnak le. A do...while ezzel ellentétben viszont csak az utasítások lefuttatása után értékeli ki a kifejezést, tehát ebben az esetben egyszer mindenképpen végrehajtja a belsejében lévő utasításokat.
do { utasítás(ok) } while (logikai kifejezés); for A for ciklus általános alakja a következő:
for (inicializáló kifejezés(ek) ; ciklusfeltétel(ek) ; léptető kifejezés(ek) ) { utasítás(ok)
for – each A Java 1.5 verziótól kezdve for ciklussal iterálhatóak a tömbök és a java.lang.Iteratable interfész implementációi a következő szintaxissal: for (elem : tömb) { utasítás(ok) } Például: for (String s : new String[]{"1","2","3"}) { System.out.println(s);
Feltételes utasítások if (logikai kifejezés) { utasítás(ok) } if (logikai kifejezés) { utasítás(ok) } else { utasítás(ok) } Elegendő else if utasításokkal bármilyen komplex ha-akkor szerkezetet ki lehet építeni. if (logikai kifejezés) { utasítás(ok) } else if (logikai kifejezés) { utasítás(ok) } else if (logikai kifejezés) { utasítás(ok) } else { utasítás(ok) } Az előbbi szerkezet kiváltható, ha ugyanazt az egész, felsorolható ill. string típusú (Java 1.7 óta) kifejezést kell kiértékelni több esetben is. Így kevesebb karakter felhasználásával (rövidebb a kód), átláthatóbb megvalósítást kapunk. switch (egész kifejezés) { case konstans egész kifejezés: utasítás(ok) break; … default: utasítás(ok) break;
Java 14-től elérhető egy rövidebb, break nélküli szintaxis, továbbá használható kifejezésként is, nem csak utasításként.
// Rövidebb szintaxis switch (egész kifejezés) { case konstans egész kifejezés -> { utasítás(ok) } … default -> { utasítás(ok) } }
// Kifejezés var változó = switch (egész kifejezés) { case konstans egész kifejezés: opcionális utasítás(ok) yield érték; … default: opcionális utasítás(ok) yield érték;
// Kifejezés és rövidebb szintaxis var változó = switch (egész kifejezés) { case konstans egész kifejezés -> érték; … default -> érték;
Java 21-től mintaillesztést is lehet végezni vele, és kezelhető a null érték is (ha nincs külön kezelve, akkor továbbra is kivételt okoz a null). Például:
Boolean logikaiÉrtékFeldolgozás(Object érték) { return switch (érték) { // Egyszerű mintaillesztés: illesztés a típusra case Boolean b -> b; // Őrfeltételes mintaillesztés case String s when s.equalsIgnoreCase("igaz") -> true; case String s when s.equalsIgnoreCase("hamis") -> false; // null érték kezelése case null -> null; default -> null;
Kivételkezelés try { utasítás(ok) } catch (kivételtípus) { utasítás(ok) } catch (kivételtípus) { utasítás(ok) } finally { utasítás(ok)
A Java nyelvben a kivételtípusok osztályok, és közöttük is fennáll típushierarchia. Éppen ezért, ha több catch ágat használunk egy blokkban, akkor mindig a speciálisabb típust kell korábban feltüntetni, mert a catch ágak kiértékelése fentről lefelé halad.
Egy try után kötelező legalább egy catch vagy egy finally ágat tenni (az egyetlen kivételt lásd alább). A catch ágakból több is lehet, de egy try blokk végén csak egy finally lehet.
Ha két catch ág tartalma azonos, akkor ezek Java 1.7 óta összevonhatók, a típusokat | jellel elválasztva (ez magyar billentyűzeten az Alt Gr+W billentyűkombinációval vihető be): try { utasítás(ok) } catch (kivételtípus | kivételtípus) { utasítás(ok) } Szintén 1.7-es Java óta használható a try erőforrásokkal (angolul try-with-resources) konstrukció. Ez egy kényelmes megoldást kínál a használt erőforrások (megnyitott fájlok, hálózati kapcsolatok stb.) bezárására kivétel fellépése esetén is: az erőforrás close metódusa lefut közvetlenül a try blokk elhagyása előtt, akár a blokk végét elérve hagyja el a vezérlés a blokkot, akár kivétellel. Ez az egyetlen típusú try blokk, aminél a catch és finally ágnak opcionálisak. try (BufferedReader br = new BufferedReader(new FileReader("fájl.txt"))) { br.readLine(); }
Feltétel nélküli ugróutasítások A Java nem támogatja a goto utasítást, mivel ennek használata spagettikódot eredményezhet. Nagyon ritkán mégis szükség van a goto-ra, a Java lehetővé tesz alternatív megoldásokat, ami a címkézhető continue és break utasítás. A goto fenntartott szó és nem használható azonosítóként.
Korai kilépés a ciklusokból A Java nyelv két utasítást is ad a ciklusból való kilépéshez. A continue; utasítás megszakítja a folyamatban levő ismételgetést és egy újabbat kezd (ugyanúgy viselkedik, mint a ciklus elejére ugró goto).
Hasonlóan, a break; utasítás teljesen kilép a ciklusból, és több ismételgetést nem hajt végre. A hatás ugyanaz, mint egy goto utasítás a cikluson kívülre.
A Java break és continue utasításai sokkal hatásosabbak, mint a C és C++ hasonló nevű utasításai, mert képesek egy többszintű ciklusból is kilépni. (Csak annyi a teendő, hogy megcímkézzük a ciklust és hozzátoldjuk a break vagy continue utasításokhoz. Ugyanezt csak goto utasítással lehet elérni C-ben és C++-ban.)
Példa: kulso: while (true) { belso: while (true) { break; // kilépés a legbelső ciklusból break belso; // ugyancsak kilépés a legbelső ciklusból break kulso; // kilépés a legkülső ciklusból
Korai kilépés az eljárásokból A return; utasítás befejez egy eljárást.
A return aErtek; visszaad a hívó eljárásnak egy értéket (aErtek) is visszatéréskor.
Alapvető adattípusok A nyelv egyszerű adattípusai, más szóval primitív típusai a következők: