Java első lépések

Kategória: Standard Java.

Filozófia

A technika részletek előtt némi filozófiával kezdem: mi is a Java. Őszintén bevallom, hogy kezdetben az esetemben "nem működött a kémia": nem értettem, miért van szükség még egy n+1-edik programozási nyelvre, mivel tud többet a Java, mint mondjuk a C++, vagy akár a Pascal. Ugyanakkor szembeötlő volt a hátránya: az akkori 16 bites 386-os számítógépemen, 6-os DOS-szal, 3.1-es Windows-zal nem működött, új számítógép és új operációs rendszer kellett tehát, ami jelentősen megterhelte a családi költségvetést. Majd jöttek a gyermekbetegségek: sehogy sem akart úgy működni, ahogy a nagykönyvben meg van írva, lassú volt, szóval még egyáltalán nem volt kiforrott, mondjuk a C++-szal ellentétben. És sajnos a környezetemben nem voltak olyanok, akik rendesen megválaszolták volna a kétségeimet. Pl. arra a kérdésre, hogy miért nem használható DOS-szal a Java, azt a választ kaptam, hogy a fájl kiterjesztése .java, míg a DOS csak 3 karakteres kiterjesztést tesz lehetővé. Ami persze nem válaszolja meg azt a kérdést, hogy miért ne lehetne mondjuk .JAV a kiterjesztés… Szóval igen hosszú volt az út odáig, hogy azt gondoljam, a Java nyelv megtanulása életem egyik legjobb döntése volt.

Ennek elfogadásához a Java mélyebb filozófiai megértése szükséges. Kezdjük a C++-szal! Egy fordító a forráskódot fordítja le gépi kódra, amit a processzor végrehajt. Noha elég sok processzor létezik, nagyjából hasonló, egyszerű műveleteket tudnak végrehajtani: bitek mozgatását regiszterek és a memória között, egyszerű matematikai műveleteket stb. Magát a fordítót tehát el kell készíteni minden architektúrára, a nyelvet viszont úgy kellett megalkotni, hogy alkalmas legyen arra, hogy minden architektúrára elkészülhessen a fordító. Jobban belegondolva, ez egy nagyon komoly megkötés! Lehet, hogy az egyik a processzor csak 16 bites egész számokat képes kezelni, és a 32 bites lebegőpontos ábrázolást szimulálni kell, míg a másik esetén ez natív módon működik, de olyan, ma már hétköznapi fogalmakat, mint mondjuk a többszálúság, vagy a grafikus felhasználói felület, processzor szinten nem létezik. A konzol is valójában határeset: a processzor ugyan nem ismeri ezt a fogalmat, viszont azt feltételezhetjük, hogy a program valamilyen operációs rendszeren fut, és a legtöbb esetben értelmezhető az a fogalom, hogy standard input és standard output, ami legtöbb esetben a konzolt jelenti.

A Java nagy újítása ezzel szemben az, hogy megalkotott egy köztes réteget, a Java virtuális gépet, amelynek az utasításkészletében már olyan fogalmak is szerepelnek, mint mondjuk a többszálúság vagy a grafikus felület. Ez viszont megkötéssel is jár: csak olyan operációs rendszeren lehet implementálni a Java virtuális gépet, amely ezeket a fogalmakat ismeri. Többszálúság (olyan értelemben, ahogy azt a Java megkívánta) nem létezett Windows 3.1-ben, ill. általában a 16 bites operációs rendszereken, így nagyon komoly megkötést jelentett volna ezeknek a támogatása. Egyébként is, általában igaz, hogy a technikai újítások fájdalommal járnak: a korábbi technológia használhatatlanná válik. Ugyanakkor érdemes meghozni az áldozatot: képzeljük csak el, hogy hogyan néznének ki az autópályák, ha mondjuk a lovaskocsi forgalom is megengedett lenne! Azóta viszont tovább fejlődött a világ, és az akkori, előre mutató döntések mára komoly megkötéssé váltak. Az újabb technológiák ismételten elvetik a régiekkel való kompatibilitást, cserében megszabadulnak a bizonyos megkötésektől, majd a világ tovább fejlődik, és idővel azok is elavulttá válnak. És így tovább, és így tovább…

Adott volt tehát egy új megközelítés, mely csak a legújabb hardveren működött, és mivel megjelent egy absztrakciós réteg a fizikai processzor és a programnyelv között, végeredményben az utasítások (a processzor szintjén) interpretáltak voltak, ami iszonyat lassúvá tette a futást. Ráadásul akkor új technológiáról beszélünk, annak minden gyermekbetegségével.

A kezdeti nehézségeket azonban bőven kompenzálják az előnyök. Leginkább a C++-szal érdemes összehasonlítani.

  • Széles körben elterjedt. Maga a bájt kód futtatható számos rendszeren, nem kell lefordítani mindenhova, mint a C++ programot (ami egyébként a legritkább esetben működik elsőre).
  • Az alaprendszernek része az, ami a C++-ban külső, platformfüggő könyvtárral volt elérhető. Néhány példa: többszálúság, GUI, hálózat elérés, fájlkezelés, collection (a Standard Template Library egész későn lett része a C++-nak, sokáig erre a célra is külső könyvtárt kellett használni; a collection kezdettől része a Java-nak) stb. Sőt, még nyelvi szinten is támogat bizonyos olyan dolgokat, amelyek a C++-ban csak külső könyvtárral érhetőek el, gondoljunk pl a synchronized kulcsszóra.
  • A Java külső könyvtárakkal való ellátottsága kiváló, sok közülük szinte szabványnak tekinthető. Gondoljunk csak pl. Log4J-re, a junit-ra vagy a jdbc-re; szinte úgy használjuk ezeket, mintha az alaprendszer részei lennének, pedig nem azok. A C++-ban még azok sem voltak tekinthetőek szabványnak, amelyek a Java-ban az alaprendszer részei, hát még a speciálisabb dolgok!
  • A Java az egyik legnépszerűbb programozási nyelv már hosszú ideje. Igen keresett szakma.

Ugyanakkor vannak hátulütői is:

  • Nagyon sok lépést meg kell tenni, mire eljutunk az első programunk futásáig. Mondjuk egy Python-t letöltjük, feltelepítjük Next → Next → … → Finish-sel, elindítjuk, és máris kiadhatjuk a print("Hello, vilag") parancsot, ezzel szemben már a letöltés sem egyértelmű, a telepítés is összetettebb a fentinél, majd külön osztályt kell létrehozni szigorú szintaxissal, le kell fordítani és csak utána tudjuk futtatni.
  • Hosszú a betanulási görbe. Ahhoz, hogy valaki elmondhassa magáról, tud Java-ban programozni, meg kell tanulnia a nyelvi elemek mellett a legfontosabb belső és külső könyvtárakat is. Ellenben pl. JavaScript-ben már lehet valaki produktív akkor, ha megtanulja az alapokat (ami amúgy egyszerűbb mint a Java), és egy könyvtárat, és azt használja.
  • A nyelv megalkotásánál utólag néhány döntés kissé elhibázottnak tekinthető, viszont a kompatibilitási kényszer miatt ezzel együtt kell élnünk.

A Java egyébként az Indonéziában található Jáva szigetről kapta a nevét, az ott termő finom kávéra utalva (a Java logója egy kávéscsésze). Ennélfogva a szokásos magyar kiejtése magyarul jáva, angolul dzsava (ami angol szövegkörnyezetben szinte megtévesztésig hasonlít arra, ahogy a nem magyar anyanyelvűek kiejtik azt, hogy Csaba).

A Java programozási nyelvről nagyon sok könyv született, többnyire ezer oldalas nagyságrendű oldalszámmal, és azok is inkább bevezető jellegűeknek tekinthetőek. Ez az oldal tehát még a bevezetőnek is épp, hogy a felszínét karcolja. Lássuk a legfontosabbakat!

Ezt az oldalt érdemes a programozás oldallal együtt tanulmányozni, mivel az általános tudnivalók ott találhatóak.

A Java története

A Java az 1990-es évek közepén jelent meg. A számozása kissé félrevezető: van egy verziószám, amit a —version paraméter hatására kiír: ez 1.x.y_z formátumú, ahol az x értékei sorban 0, 1, 2, 3 stb. voltak; az írás pillanatában 12 (az y általában 0, a z pedig egy viszonylag nagyobb, százas nagyságrendű szám, de ez most számunkra érdektelen). Ugyanakkor a Java megnevezése ettől valamelyest eltér:

  • A Java 1.0 és 1.1 neve JDK 1.0 ill. JDK 1.1 volt. A JDK 1.0-ás verziója 1996 januárjában jelent meg.
  • A Java 1.2-ben a megnevezés Java 2 lett, a JDK-t pedig átnevezték SE-re (Standard Edition), hogy megkülönböztessék a nagyvállalati (EE, Enterprise Edition) és a mobil (ME, Mobile Edition) verzióktól. Így ez a verzió J2SE 1.2 lett. Majd a következő pár verzióban a 2-es szám meglepő módon megmaradt, a verzió változott: J2SE 1.3, J2SE 1.4. Ebben az időszakban a könyvtárak fejlődése terén voltak jelentős előrelépések, valójában nagyon sok olyan funkció került bele a belső könyvtárba, ami más programozási nyelvek esetén tipikusan külső.
  • A Java 1.5 ismét változást hozott a verziózásban: átnevezték Java 5-té, tehát az alverzió lett a főverzió, és ez azóta is így van. Viszont ez megtartotta a Java 1.2-ben bevezetett 2-est is, így a teljes megnevezése: J2SE 5.0 lett. Ez egyébként 2004 szeptemberében jelent meg, és ez az egyik legjelentősebb előrelépés volt a Java történetében: az annotációk megjelenése hatalmas lökést adott a nagyvállalati Java-nak, megjelentek a generikus típusok, az újfajta for ciklus és számos új nyelvi elem.
  • A Java 1.6-ban megszabadultak a 2-estől (legalábbis a hivatalos verziózásban), a megnevezés pedig Java SE lett, valamint az alverzió: Java SE 6. Azóta a verziók ezt a mintát követik. A következő, 1.7-es verziója tehát a Java SE 7. A fejlesztések nagy része ebben az időszakban a már meglevő könyvtárakon belül történt.
  • A Java 1.8 (Java SE 8) hozta a Java történetének másik nagy előrelépését 2014 márciusában, többek között egyes funkcionális programozási elemekkel, a stream megjelenésével. (Úgy tűnik, hogy 10 évente lépnek előre egy nagyobbat.) Egyúttal ez a verzió LTS (Long Term Support) minősítést is kapott.
  • Jött a Java 1.9 (Java SE 9), a Java 1.10 (Java SE 10), majd az újabb LTS Java 1.11 (Java SE 11). Az írás pillanatában a legfrissebb a Java 1.12 (Java SE 12). Ezek az apró előrelépések verziói, a nyelvet alapjaiban megváltoztató, átütű horderejű változásokat nem találtam bennük. A módosítások jelentős része olyan belső optimalizálás, ami a programozó számára láthatatlan.

Az alábbi Wikipédia oldalon olvashatunk részletesebben a Java verzióinak történetéről: https://hu.wikipedia.org/wiki/Java_verziótörténet..

Telepítés

A Java esetén megkülönböztetünk két fogalmat:

  • JRE (Java Runtime Environment): a Java programok futtatásához szükséges. Erre lénygében mindenkinek szüksége van, mert a programok nagy része Java-ban készül, és csak ezzel tudjuk futtatni. Ez egyre több helyre alapból feltelepül. A legfontosabb komponense a Java futtató, melynek meglétét az alábbi paranccsal tudjuk ellenőrizni: java -version.
  • JDK (Java Development Kit): ez a Java fejlesztőeszköz, melyre a Java programozóknak van szükségük. A legfontosabb a Java fordító, melynek meglétét a következőképpen tudjuk ellenőrizni: javac -version.

A Java-t innen tudjuk letölteni: https://www.oracle.com/technetwork/java/javase/downloads/index.html. Ne ijedjünk meg a túl sok verziótól, válasszunk egy fő verziót, azon belül a legfrissebb alverziót, a megfelelő operációs rendszerhez tartozó, megfelelő bitszámú verziót (i586 végű a 32 bites és x64 a 64 bites), célszerűen .exe kiterjesztésűt, fogadjuk el a felhasználói feltételeket (rádiógomb felül), majd töltsük le és telepítsük fel. A telepítő sajnos nem állítja be a szükséges környezeti változókat, azt nekünk kell beállítanunk:

  • JAVA_HOME: a JDK telepítés gyökere (pl. c:\Program Files\Java\jdk-11.0.2).
  • PATH: egészítsük ki a JDK-n belüli bin könyvtárral, pl. c:\Program Files\Java\jdk-11.0.2\bin.

Helló, világ!

A "Helló, világ!" programoknak hívjuk azokat a programokat, amelyek elvégzik a legegyszerűbb értelmes feladatot az adott rendszeren. Ez a legtöbb esetben azt jelenti, hogy kiírja a standard kimenetre azt, hogy "Hello, world!". Persze nem minden esetben jelenti szó szerint ezt, pl. az Arduino esetén a LED villogtatása számít a Helló, világ!-nak, míg a Big Data területen a szószámolás.

Maradjunk most a Java-nál! Ezen a ponton elvileg van egy működő Java rendszerünk. Első körben vegyünk egy tetszőleges szövegszerkesztőt (én személy szerint a NotePad++-t használom, de tényleg bármit használhatunk, ami képes formázatlan szövegfájlt létrehozni), hozzunk létre egy HelloWorld.java nevű fájlt (célszerűen egy külön könyvtárba, de ez sem kötelező), majd másoljuk be az alábbi programot:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

Ennek a kódnak az értelmezését később részletezzük; egyelőre fogadjuk el az alábbiakat:

  • A public class HelloWorld sorban szereplő HelloWorld-nek meg kell egyeznie a fájlnévben található HelloWorld.java-val.
  • A public static void main(String[] args) a Java programok fő belépési pontja.
  • A System.out.println() függvénnyel tudunk kiírni a konzolra.

Nyissunk meg egy parancssor értelmezőt, angolul command promptot az adott könyvtárban. Windows operációs rendszer alatt ezt a cmd parancs segítségével tudjuk megtenni. Első lépésben le kell fordítani a fenti forrásfájlt, amit az alábbi paranccsal tudunk megtenni:

javac HelloWorld.java

Elég barátságtalan amúgy, mert ha sikeres, nem ír ki semmit. Viszont megjelenik a könyvtárban egy HelloWorld.class nevű bináris fájl, ez a fordítás eredménye. Ez tartalmazza azokat az utasításokat, amelyeket a processzor ugyan nem tud közvetlenül értelmezni, a Java Virtuális Gép viszont már igen. A következő paranccsal tudjuk lefuttatni:

java HelloWorld

Figyeljük meg azt, hogy noha a bináris fájl kiterjesztése az, hogy .class, ezt nem kell odaírni.

Ha mindent jól csináltunk, akkor megjelenik a konzolon a Hello, world! felirat.

Fejlesztő környezet

Elméletben a fent megadott módon is lehet fejleszteni: a forrásokat elkészítjük egy akármilyen szövegszerkesztővel, majd futtatjuk. Idővel ugyan meg kell tanulunk egyre több kapcsolót, ill. egy-két újabb programot (ami a JDK része), de elméletben semmi sem akadályozhat meg abban, hogy akár a legbonyolultabb programokat is ily módon elkészítsük.

A valóságban azonban elég gyorsan elérjük azt a szintet, amikor kényelmetlen felsorolni az összes forrásfájlt, vagy jó lenne, ha a szerkesztő jelezné a legdurvább hibákat, valamint valamelyest segítene a fejlesztésben. Ehhez célszerű valamilyen integrált fejlesztőeszközt használnunk.

Valamint, noha elvileg bármit meg tudunk valósítani, nagyon sok olyan általános célú programkönyvtár van, amit fel tudunk mi magunk is használni. És ezeket ugyan le tudjuk tölteni az internetről "kézzel", és megfelelő kapcsolókkal hozzá tudjuk szerkeszteni a mi programunkhoz (amit egyébként fordítás és futás során is meg kell tennünk), ez két-három könyvtáron túl eléggé kényelmetlenné válik. Ezekhez alkották meg az ún. build rendszereket.

Ezen a ponton máris a fejlesztőeszközök végtelennek tűnő területére tévedtünk, emiatt nem lesz szó erről túl részletesen, de most első körben telepítsünk fel két dolgot:

  • Maven: töltsük le a https://maven.apache.org/ oldalról, csomagoljuk ki, majd a bin könyvtárát adjuk hozzá a PATH környezeti változóhoz. Ellenőrizzük a következő paranccsal: mvn -version
  • Eclipse: töltsük le a https://www.eclipse.org/ oldalról és telepítsük fel (vagy csomagoljuk ki), majd indítsuk el. (Az Eclipse-nek sajnos van pár "rigolyája". Ebben a projektben még együtt tudunk élni vele, de hosszabb távon érdemes megfelelően bekonfigurálni, ahogy az a fejlesztőeszközök oldalon le van írva.)

A példában létrehozunk Eclipse-ben egy Maven projektet. A példa egy összeadó lesz: egy olyan függvényt írunk, ami összead két számot. Ehhez unit tesztet is készítünk. Egyelőre nem feltétlenül kell megérteni minden lépést. A következő lépéseket hajtsuk végre.

  • Az Eclipse-ben készítsünk egy új Maven projektet: File → New → Other… → Maven → Maven project
  • Adjunk meg egy munkaterületet (workspace), ami praktikusan egy külön, erre a célra létrehozott könyvár.
  • Egyszerű projektet hozzunk létre: Create a simple project (skip archetype selection), az alapértelmezett munkaterületen: Use default Workspace location.
  • Kattintsunk a Next gombra
  • A Configure project oldalon az alábbiakat adjuk meg:
    • Group Id: ez a magunkra, a cégre vonatkozik, ahol dolgozunk, ill. magára a tágabb értelembe vett projektre; pl. hu.faragocsaba.
    • Artifact Id: ez magának a projektnek a neve, pl. adder.
    • Version: legyen 1.0
    • Minden mást hagyunk alapértelmezésen, és kattintsunk a Finish gombra.
  • A létrejött adder projektet nyissuk meg, kattintsunk jobb egérgombbal az src/main/java-n, majd New → Package. Name: adder (kisbetűvel), majd Finish.
  • Az így létrejött adder csomagon jobb kattintás → New → Class. A név legyen Adder (nagybetűvel), minden más maradjon alapértelmezett, majd Finish.
  • Az Adder.java tartalma legyen a következő:
package adder;
 
public class Adder {
    public static int add(int a, int b) {
        int result = a + b;
        return result;
    }
}
  • Hasonlóan az Adder osztályhoz, hozzunk létre egy Main osztályt is, az Adder mellett az alábbi tartalommal:
package adder;
 
public class Main {
    public static void main(String[]args) {
        System.out.println(Adder.add(5, 3));
    }
}
  • Indítsuk el, pl. a következőképpen: Run → Run As → Java Application. Ha mindent jól csináltunk, megjelenik egy 5-ös.
  • Hozzunk létre unit testet! Ehhez hozzá kell adnunk egy megfelelő külső könyvtárat. Módosítsuk a pom.xml fájlt úgy, hogy a következőképpen nézzen ki:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>hu.faragocsaba</groupId>
    <artifactId>adder</artifactId>
    <version>1.0</version>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>adder.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • Az src/test/java könyvtáron belül, a fent megadott módon, hozzunk létre egy adder nevű csomagot, azon belül pedig egy AdderTest nevű osztályt. Ez utóbbinak a tartalma legyen a következő:
package adder;
 
import static org.junit.Assert.assertEquals;
 
import org.junit.Test;
 
public class AdderTest {
    @Test
    public void testAdd() {
        assertEquals(5, Adder.add(2, 3));
    }
}
  • Futtassuk le: Run → Run As → JUnit Test. Ha mindent jól csináltunk, akkor kizöldül az eredmény.
  • Most vessünk egy pillantást a létrejött könyvtár szerkezetre!
    • .settings/, valamint a gyökérben levő .classpath és .project fájlok - ezt az Eclipse használja, nem tekinthető a projekt részének.
    • src/ - a forrásfájlokat tartalmazza
      • main/ - a főprogram forrásai
        • java/ - a programozási nyelv
          • adder/ - a csomag neve
            • Adder.java
            • Main.java
        • resources/ - a főprogramhoz tartozó erőforrás fájlokat tartalmazza; jelenleg üres
      • test/ - a unit teszteléshez szükséges forrásokat találhatóak itt
        • java/adder/AdderTest.java - az összeadót tesztelő unit teszt
        • resources/ - a teszteléshez tartozó erőforrás fájlok; jelenleg üres
    • target/ - ide kerül a lefordított eredmény
    • pom.xml - a Maven leíró
  • Indítsunk egy egy parancssort a projekt főkönyvtárában, és adjuk ki a következő parancsot:
mvn clean install

El lefordítja, és a unit teszteket is lefuttatja. Ha minden jól ment, akkor BUILD SUCCESS üzenet jelenik meg az alján.

  • Az alábbi paranccsal tudjuk futtatni:
java -jar target\adder-1.0.jar

Ha mindent jól csináltunk, akkor megjelenik a 8.

Láthatjuk, hogy ha a Helló, világ! programnál egy nagyon picit is bonyolultabb dolgot szeretnénk megoldani, akkor igen sok lépést kell végrehajtanunk. Ebből is látható, hogy a Java kezdeti indulási görbéje igen hosszú. Viszont ne feledjük: kellő rutinnal mindez csak pár perc, míg a nagy Java projekteket akár fejlesztők százai fejlesztik éveken át, és a megfelelő fejlesztőeszközök valóban nagyban megkönnyítik a fejlesztést.

Anyagok

Mivel ez az egyik legnépszerűbb programozási nyelv, igen sok jó tananyag található a neten:

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License