Dátumok csoportosítása

dátumintervallumok logó

dátumintervallumok logóEbben a Java projektben dátumok csoportosítását oldjuk meg, többféleképpen is. Mikor van erre szükség? Jelentés, kimutatás, riport, lista készítése során.

Példaként tekintsünk egy blogot. A blogban rendszeresen jelenik meg új tartalom (bejegyzés, poszt). Azért, hogy a blog hosszabb távon, sok bejegyzéssel is könnyen kereshető, átlátható, böngészhető legyen/maradjon a felhasználók, látogatók számára, célszerű:

  • taxonómia kialakítása. Ez kategóriákat és címkéket jelent. Ebből címkefelhő vagy szófelhő is készíthető, ahogyan erről blogoltunk már: Címkefelhő generálása.
  • marketing analitika használata. Ezek általában toplisták valamilyen könnyen hozzáférhető adat alapján. Például: látogatottság, népszerűség, eltöltött idő, hozzászólások száma, megosztások száma, egérmutató mozgása alapján hőtérkép. Ezek általában toplisták, amelyek eleje listázódik csökkenő sorrendben.
  • dátum szerint is csoportosítani a blog bejegyzéseit. Érdemes megjeleníteni a legújabbtól a régebbi felé haladó (retrospektív) listát, hierarchikus fa struktúrát, lenyíló panelt. Mindez kombinálható toplistával. A csoportosítás elvégezhető igény szerint tetszőlegesen, például évente, negyedévente, havonta.

Lássuk, hogyan lehet megvalósítani a dátumok csoportosítását Java programozás nyelven!

Milyen adatokra van szükség?

Egy megadott zárt dátumtartományban véletlenszerűen előállítunk néhány dátumot. Nem számít, hogy különböznek-e. A dátumokat tároló listát érdemes csökkenő sorrendben tárolni. Minden dátum múltbeli, így ez a sorrend a jelenhez legközelebbitől halad a legtávolabbi felé. Például a Java program ezekkel a dátumokkal dolgozik (lapozható):

Milyen eredményeket kaphatunk?

Az évenkénti csoportosítás így jelenik meg:

A havonkénti csoportosítás így jelenik meg (lapozható):

Természetesen blog esetén gyűjtőoldalra mutató hivatkozást kell tenni a megjelenő elemekre. Azok az évek és hónapok nem jelennek meg, ahol nincs dátum (blog bejegyzés).

Hogyan kapjuk meg az eredményeket?

Természetesen Java nyelven programozva készítünk megoldást, sőt többféle megoldást. Ezek szépen összevethetők és mindenki kiválaszthatja azt, amit szívesen használna. A dátumobjektumok tárolása generikus listában történik, aminek típusa LocalDate. A dátumok formátuma: DateTimeFormatter.ofPattern("yyyy.MM.dd.").

1. megoldás

Ez a hagyományosnak tekinthető megoldás. Végigjárja a dátumobjektumokat tartalmazó dateList dátumlista adatszerkezetet. Két egymásba ágyazott ciklussal csoportváltást valósít meg. Feltételezi – nem ellenőrzi -, hogy az adatok sorrendje megegyezik az eredmény kiírásának megfelelő sorrenddel. Amíg két egymást követő dátum GROUP_BY_FORMAT formátuma azonos, addig ugyanabba a csoportba tartoznak. A csoportváltáskor az eredmény TYPE_FORMAT formátumú. Közben a beépített megszámolás programozási tétel is működik.

A groupByDate1() függvény képes az évente és havonta csoportosítás megvalósítására. Mindez a paraméterezésén múlik. Évente csoportosít, ha így hívja meg a vezérlés:

Évenkénti csoportosítás során például a 2024.02.26. és a 2024.01.30. (dátumként, nem szövegként értelmezve) azért tartozik egy csoportba, mert a dátumobjektumoktól elkért év "2024" szövegként mindkettő esetében megegyezik.

A groupByDate1() függvény havonta csoportosít, ha így hívja meg a vezérlés:

Havonkénti csoportosítás során például a  2023.06.14. és a 2023.06.08. (szintén dátumként értelmezve) azért tartozik egy csoportba, mert mindkettő illeszkedik a "202306" szövegmintára.

2. megoldás

Ez a Stream API-t és funkcionális programozást használó, újabb megoldás. Ciklus helyett beépített műveletek vannak. A groupByDate2() függvény a dátumok évenkénti csoportosítását képes megoldani:

A groupByDate3() függvény a dátumok havonkénti csoportosítására készült. A YearMonth osztály beépített ( java.time csomag). A DateCount saját POJO. Konstruktora 4 paramétert kap: YearMonth key, Long value, DateTimeFormatter format és String groupText, valamint van két hasznos metódusa. Az egyik az örökölt és felüldefiniált toString() a formázott kiíráshoz, a másik pedig a Comparable interfésztől implementált compareTo() a sorrend kialakításához szükséges összehasonlításhoz.

A funkcionális programozáshoz kötődő lambda műveletekről többször is blogoltunk már, így azokat most nem részletezem. Helyette ajánlom a szakmai blog lambda kifejezés címkéjét.

Továbbfejlesztés

Érdemes átgondolni az 1. és 2. megoldás markáns különbözőségeit, illetve egymást kiegészítő gondolatmenetét. Zárjuk két ötlettel a továbbfejlesztésre vonatkozóan:

  • A 2. megoldás két függvénye megoldható egyetlen függvénnyel, amely hasonlóan paraméterezhető, mint az 1. megoldás függvénye. Ezáltal univerzális(abb)nak tekinthető megoldás is készülhetne. Aki kellően motivált és végiggyakorolja a fentieket, biztosan meg tudja oldani. Várjuk hozzászólásban, vagy az ILIAS-ban a megoldást!
  • A csoportosítás egyben hierarchiát jelent, amiből fa szerkezet építhető. A fa vizuális komponensen is megjeleníthető, ahogyan blogoltunk is róla: Fát építünk.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladat a Java SE szoftverfejlesztő tanfolyam, a Java EE szoftverfejlesztő tanfolyam és a Java adatbázis-kezelő tanfolyam szakmai moduljának több alkalmához és az orientáló moduljának 1-4. óra: Programozási tételek alkalmához is kötődik. A Stream API-val és a lambda kifejezésekkel sokszor foglalkozunk.

A TIOBE Java kódolási szabályokról

A TIOBE Java Coding Standard aktuális verziója a 3.10. Java programozási nyelven írt/karbantartott forráskódra vonatkozó szabályokat/ajánlásokat tartalmaz. Célja: a kódolási hibák elkerülése, az elavult vagy implementációfüggő nyelvi funkciók használatának elkerülése, illetve a következetes, konzisztens kódolási stílus kialakítása.

A TIOBE Java Coding Standard dokumentáció szerkezete

A TIOBE Java kódolási szabályok 19 kategóriába soroltak, 1-8-ig szint alapján csoportosítottak, továbbá ellenőrzött és nem ellenőrzött állapotban vannak. Az alábbi Sankey-diagram segít áttekinteni a dokumentációt:

A TIOBE Java kódolási szabályok kategóriánként

A továbbiakban néhány kategóriából emeltem ki néhány szabályt/ajánlást – amiket fontosabbnak tartok.

  • 34 db alapszabály van. Ezek olyan jó gyakorlatok, amiket mindenkinek követnie kell. Nem írunk üres if, switchutasításokat. Nem írunk üres while, try, finally, synchronized, static blokkokat. Nem írunk tesztelős ciklust számlálósként, így: for (;true;). Nem módosítjuk a for ciklus változóját a ciklusmagban. Ne használjunk felesleges public, static, finalmódosítókat és (eljárásokban) return utasítást.
  • 8 db kódmérethez kötődő szabály van. Ne írjunk hosszú, sok utasításból álló metódusokat. Ne használjunk túl sok paramétert metódusok, konstruktorok esetén. Ügyeljünk a forráskód ciklomatikus komplexitására, amely a tesztelési nehézségek egyik mutatószáma. Ne tervezzünk túl sok publikus metódust és mezőt/tulajdonságot egy osztályba. A limitek a fentiek sorrendjében: 100 utasítás, 10 paraméter, 1000 kódsor, 10-es komplexitású metódus, 45 metódus, 15 mező/tulajdonság.
  • 4 db kommentekre vonatkozó szabály van. Ezek forrásfájlokra, annotációkra, TODO-kra és speciális JavaDoc-ra érvényesek.
  • 4 db ellentmondásos/vitatott szabály van. Például ne importáljunk a sun.* csomagokat, illetve ne használjunk felesleges kerek zárójelpárokat, értékadással egybeépített összehasonlítást egy feltételben.
  • 42 db tervezési szabály van. Függvényben lévő if-then-else utasításben lévő két return helyett adjuk vissza közvetlenül a logikai kifejezés értékét. Logikai kifejezésekben ne legyenek felesleges összehasonlítások. A switch utasításban hiányzó break utasítás tervezési hibára utal (bár nem szintaktikai követelmény, hogy legyen). A switch utasításban kellene default ágnak lennie (és egyben álljon az utolsó helyen). Ne definiáljuk felül egy metódus bejövő paraméterét. Az equals() összehasonlító metódust ne hívjuk meg null paraméterrel. Ne használjunk idempotens műveleteket, például ne adjunk értékül egy változót/objektumot saját magának. A SimpleDateFormat osztály és String.toLowerCase()/toUpperCase() metódusok használata során mindig állítsuk be a Locale objektumot. A synchronized kulcsszót ne kívülről, metódusra, hanem belülről, blokkban használjuk. Konstanst ne inicializáljunk null-ként. Kollekciók esetén a size()==0 vagy size()!=0 helyett hívjuk meg az isEmpty() függvényt. Az instanceof operátor használata előtt nem kell ellenőrizni, hogy az objektum nem null. A megnyitott erőforrásokat mindig zárjuk le a close() metódussal.
  • 7 db véglegesítéshez kötődő szabály van. Ha írunk finalize() metódust, akkor az ne legyen üres és ne legyen paramétere sem. Inkább ne írjunk finalize() metódust, mert nincs garancia arra, hogy végrehajtódik (illetve szintén nem tudjuk, hogy mikor fut le).
  • 5 db importáláshoz kapcsolódó szabály van. Importáljunk pontosan. Ne importáljunk a java.lang csomagból (mert ez alapértelmezett). Ne importáljunk többszörösen. Ne maradjanak nem használt importok a végleges forráskódban.
  • 4 db logolásra vonatkozó szabály van. Egy osztályban egyetlen Logger legyen. A System.(out|err).print() metódus és kivételkezelés során printStackTrace() helyett inkább logoljunk.
  • 1 db szabály van a többszálúsághoz kötődően. Példányváltozó közvetlenül elérhető több szál számára. Az ehhez való megosztott hozzáférés szabályozása, szinkronizálása nehéz, ezért inkább hozzunk létre belőle annyi példányt, ahány szálon fut a program.
  • 10 db elnevezésre vonatkozó szabály van. Kerüljük a hosszú változóneveket és a rövid metódusneveket. Ne használjunk $ jelet a változók, metódusok, osztályok, interfészek elnevezése során. Ne használjunk a Foo osztályban Foo() metódusnevet (mert ez a konstruktor), és foo változónevet sem. Minden osztály és interfész tartozzon csomagba.
  • 8 db optimizáláshoz kötődő szabály van. Ha egy változó nem módosul és csak egyszer kap értéket, akkor legyen konstans. Ha tömbből generikus listát készítünk, akkor használjuk az Arrays.asList() metódust (ahelyett, hogy ciklust írunk az adatszerkezet konstrukciójához). Csomagolóosztályt csak szükség esetén alkalmazzunk (mert autoboxing van). A Calendar helyett használjunk inkább „olcsóbb” osztályokat.
  • 2 db kódbiztonsági szabály van. Ne égessünk a forráskódba kriptográfiához kötődő adatokat (kód, jelszó, hash). Ezeket a kulcsokat külső fájlokban tároljuk.
  • 11 db szabály vonatkozik a kötelező kivételkezelésre. Nem szabad catch (Throwable t) ágat használni, mert memóriaproblémát okozhat. Konstruktor/metódus ne dobjon általános kivételt ( Exception) – helyette dobjon szükség esetén speciálisabb/leszármazott kivételt. Ne kapjunk el általános kivételt; specializáljuk ezt is. Kivételkezeléssel ne valósítsunk meg vezérlést. Ne kapjunk el NullPointerException-t; inkább szüntessük meg a keletkezésének okát. Ha lehet, akkor a try-catch-finally blokk helyett alkalmazzunk erőforrás-kezelő kivételkezelést.
  • 14 db szabály vonatkozik a szövegkezelő String és StringBuffer osztályok használatára. Közvetlenül inicializáljuk a String típusú objektumokat, felesleges hozzá konstruktort használni. Csak akkor használjuk a toString() metódust, amikor feltételül szükséges. Összehasonlításnál az equalsIgnoreCase() metódus gyorsabb a toUpperCase/toLowerCase().equals() metódusoknál. Láncoljuk az append() függvényeket, amikor csak lehet. Ha nem szükséges, akkor ne használjuk a String.valueOf() függvényt. String objektumok összehasonlítát az equals() metódussal végezzük el.
  • 3 db típusrezolúciós szabály van. Használjunk ArrayList list=new ArrayList() helyett List list=new ArrayList() deklarációt (értékadás bal oldalán statikus típus (interfész), jobb oldalán dinamikus típus (implementáció)). Tömb létrehozásához használjunk int[] x=new int[] {1, 2, 3} helyett int[] x={1, 2, 3} inicializáló blokkot. Generikus lista létrehozásánál használjunk List<String> strings=new ArrayList<String>() dupla gyémánt operátor helyett csak egyet, így: List<String> strings=new ArrayList<>().
  • 5 db nem használt forráskódokra vonatkozó szabály van. Ezek privát változókra, lokális változókra, privát metódusokra, felesleges értékadásokra, üres utasításokra érvényesek.

Nem tértem ki a 2 db klónozáshoz, 2 db csatoláshoz (importáláshoz), az 1 db stílushoz kötődő szabályra. Továbbá van 5 db már elavult, tervezésre vonatkozó szabály.

A fentieket érdemes megfogadni, betartani, céges környezetben megfelelően kiegészíteni, testre szabni. A teljes angol nyelvű dokumentáció elérhető: Coding Standard Viewer. A weboldalon érdemes a Java programozási nyelvre vonatkozó szabályokat, ajánlásokat összehasonlítani más nyelvekre vonatkozó szabályokkal, ajánlásokkal. Összesen 8 programozási nyelvhez találhatók szabályok, ajánlások. Elérhetők a forráskód minőségét, karbantarthatóságát kifejező TQI szempontok, paraméterek dokumentációi is: TIOBE Quality Indicator (TQI), valamint a TIOBE TÜViT Trusted Product Maintainability ISO/IEC 25010 Quality Model. Egy szint felett már ezeket is figyelembe kell venni.

Korábbi blog bejegyzésünk a fenti saját készítésű ábra, grafikon elkészítéséről: Sankey-diagram készítése. Érdemes a hozzászólásokat is tanulmányozni a jó példákért.

Egy matematika érettségi feladat megoldása programozással 2024

érettségi logó

érettségi logóA 2024-es középszintű matematika érettségi feladatsorból az 12. feladata inspirált arra, hogy elkészítsem a grafikus ábrázolását Java nyelven. A korábbi Kígyókocka grafikus felületen esettanulmány kiváló alapot, „keretrendszert” adott a továbbfejlesztésre. Érdekes belegondolni, hogy mennyire más lehetne a problémamegoldás, ha programozhatnánk a matematika érettségi vizsgán. A teljes feladatsor letölthető az oktatas.hu-ról.

12. feladat

Egy piros, egy fekete és egy fehér szabályos dobókockával egyszerre dobunk. Határozza meg annak a valószínűségét, hogy a dobás eredménye három különböző szám lesz! Megoldását részletezze!

1. megoldás

A kedvező /összes eset száma ad választ a kérdésre. Az egymásba ágyazott ciklusok – i-j-k számhármasokként – előállítják az összes esetet. Ezek száma 216, rendre: 1-1-1, 1-1-2, …, 1-1-6, 1-2-1, …, 6-6-5, 6-6-6-ig. A összes eset között megtalálhatók a kedvező esetek. Ezek száma 120, rendre: 1-2-3, 1-2-4, 1-2-5, 1-2-6, 1-3-2, 1-3-4, 1-3-5, 1-3-6, 1-4-2, 1-4-3, 1-4-5, 1-4-6, 1-5-2, 1-5-3, 1-5-4, 1-5-6, 1-6-2, 1-6-3, 1-6-4, 1-6-5, 2-1-3, 2-1-4, 2-1-5, 2-1-6, 2-3-1, 2-3-4, 2-3-5, 2-3-6, 2-4-1, 2-4-3, 2-4-5, 2-4-6, 2-5-1, 2-5-3, 2-5-4, 2-5-6, 2-6-1, 2-6-3, 2-6-4, 2-6-5, 3-1-2, 3-1-4, 3-1-5, 3-1-6, 3-2-1, 3-2-4, 3-2-5, 3-2-6, 3-4-1, 3-4-2, 3-4-5, 3-4-6, 3-5-1, 3-5-2, 3-5-4, 3-5-6, 3-6-1, 3-6-2, 3-6-4, 3-6-5, 4-1-2, 4-1-3, 4-1-5, 4-1-6, 4-2-1, 4-2-3, 4-2-5, 4-2-6, 4-3-1, 4-3-2, 4-3-5, 4-3-6, 4-5-1, 4-5-2, 4-5-3, 4-5-6, 4-6-1, 4-6-2, 4-6-3, 4-6-5, 5-1-2, 5-1-3, 5-1-4, 5-1-6, 5-2-1, 5-2-3, 5-2-4, 5-2-6, 5-3-1, 5-3-2, 5-3-4, 5-3-6, 5-4-1, 5-4-2, 5-4-3, 5-4-6, 5-6-1, 5-6-2, 5-6-3, 5-6-4, 6-1-2, 6-1-3, 6-1-4, 6-1-5, 6-2-1, 6-2-3, 6-2-4, 6-2-5, 6-3-1, 6-3-2, 6-3-4, 6-3-5, 6-4-1, 6-4-2, 6-4-3, 6-4-5, 6-5-1, 6-5-2, 6-5-3, 6-5-4.

A megszámolás programozási tétel előállítja a szükséges változókat, amik hányadosa megadja a szükséges p valószínűséget és ezt a program ki is írja a konzolra: A keresett valószínűség: 0.5555555555555556. Az esetek/lehetőségek felsorolása egyben a megoldás részletezése. A megszámoláshoz használt sokféle feltétel természetesen átfogalmazható lenne. Az egyszerűsítés többféleképpen is elvégezhető, többek között a De Morgan-azonosságok alkalmazásával.

2. megoldás

A korábbi JavaFX alapon megvalósított program módosításával könnyen állítható a megoldás grafikus/vizuális reprezentációja. Íme egy képernyőkép az elkészült program felhasználói felületéről:

A 3 db dobókockával kapott számhármasok 3D-ben, térbeli pontként jelennek meg egy kockában. A nagy piros gömbök jelölik azt a 6 db esetet, amikor mindhárom kockadobás megegyezik. Ezek a kocka egyik testálójában találhatók. A közepes narancssárga gömbök jelölik azt a 90 db lehetőséget, amikor bármely (pontosan) két kockadobás megegyezik. Végül a kis szürke gömbök jelölik a megoldást. Ez a 120 db kimaradó eset, másképpen: amikor mindhárom kockadobás különbözik. Másféle lehetőség nincs és megvan a 216 esethez tartozó összes gömb.

A megoldás implementálása a korábbi programban szinte csak egy metódus frissítését, kiegészítését igényelte. Ez a korábbi tudatos, objektumorientált, MVC szerkezetnek köszönhető és egyben a forráskód újrafelhasználása is. A createCube() metódus az alábbiak valósítja meg a feladatot:

A belépési pont, a grafikus felület építése, a nyomógombok eseménykezelése, a geometriai transzformációk, és persze a 3D -> 2D leképezés a megjelenítés során megmaradt. A virtuális térben elhelyezett objektumok változtak (pozíció, nézőpont, anyagtulajdonság). További részletes magyarázat érhető el a Kígyókocka grafikus felületen esettanulmányban.

3. megoldás

Itt most csak ötletet szeretnék mutatni. A 2022-es 6. feladat 3-7. kombinatorikai megoldásai könnyen továbbfejleszthetők és sokféle hasznos apróság gyakorolható.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

Ajánljuk matematika érettségi feladat címkénket, mert a témában évről-évre blogolunk.

A feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 5-8. óra: Vezérlési szerkezetek, 9-12. óra: Metódusok, rekurzió, valamint 17-28. óra: Objektumorientált programozás alkalmaihoz kötődik.

Dr. Sheldon Cooper kő-papír-olló-gyík-Spock játéka

Sheldon, Agymenők

Sheldon, AgymenőkDr. Sheldon Cooper karakterét nem kell bemutatni. Ha a kockáknak döntéseket kell hozniuk, akkor az Agymenők (The Big Bang Theory) sorozatban többször is előkerül a kő-papír-olló-gyík-Spock játék.

A 2. évad 8. epizódjában – amelynek címe Fogd a nőt, és fuss! (The Lizard–Spock Expansion) – ismerjük meg a játékszabályt és rögtön alkalmazásra is kerül. Raj és Sheldon megpróbálja eldönteni, hogy melyik sci-fi sorozat a (leg)jobb, illetve Howard és Sheldon így próbálnak osztozni a vacsora maradékán. Végül az 5. évad 17. epizódjában – amelynek címe Itt a festmény, hol a festmény! (The Rothman Disintegration) – újra hallhatjuk a játékszabályt. Ekkor Kripke és Sheldon egy egyetemi iroda sorsáról (kié legyen) próbál dönteni.

A kő-papír-olló-gyík-Spock játékszabály

Vajon hogyan bővül ki a klasszikus kő-papír-olló játékszabálya további két kézjel/fegyver hozzáadásával? Íme a játékszabály videóban:

Íme a játékszabály szövegesen:

Az olló elvágja a papírt,
a papír bevonja a követ,
a kő agyonüti a gyíkot,
a gyík megmarja Spockot,
Spock eltöri az ollót,
az olló lefejezi a gyíkot,
a gyík megeszi a papírt,
a papír cáfolja Spockot,
Spock feloldja a követ,
a kő eltöri az ollót.

Ugye mi sem egyszerűbb? 🙂

A játékszabálynak számos grafikus ábrázolása is van. Ezeken többnyire irányított gráf csomópontjai mutatják a kézjeleket és a nyilak iránya mutatja, hogy mi mit győz le. Például a gyíktól Spock felé mutató jelzi, hogy a gyík megmarja (azaz legyőzi) Spock-ot. Íme az egyik ábra:

A kő-papír-olló-gyík-Spock játék szimulációja Java programmal

Az objektumorientált tervezés egyik lehetősége az öröklődés beépítése. Közös pontokat, funkcionalitást keresünk. Ezeket beépítjük az ősosztályba és az utódokban kiegészítjük, testre szabjuk. Kiindulunk az alábbi absztrakt Dontes ősosztályból:

A konstans DONTES tömb (indexelhető adatszerkezet) tárolja a kézjelek/fegyverek elnevezését. Ezek közül választ véletlenszerűen a  veletlenDontes() függvény. Az eredményt ki kell tudni írni a konzolra, illetve kezelni kell a döntetlent is. Ezekért közösen felelnek a dontesEredmeny() és a kiiras() függvények. A túlterhelt metódusokként létrehozott eredmeny() függvények kezelik a 2 illetve 3 játékos esetén a döntéseket. A háromparaméteres függvény visszavezet a kétparaméteres esetre. Utóbbi metódus – mivel absztrakt – csak az utódosztályban valósul meg. Így lehetővé válik a játékszabály többféle megvalósítása.

1. megoldás

Az első megoldás során adatszerkezet nélkül valósul meg a játékszabály a  KoPapirOlloGyikSpockV1 utódosztályban:

2. megoldás

A második megoldás során a játékszabályt konstansként deklarált MATRIX szomszédsági -, csúcsmátrix, kétdimenziós tömb adatszerkezet tárolja. Ez alapján döntést tud hozni a KoPapirOlloGyikSpockV2 utódosztály.

A játékmenetért felelős vezérlés

10 lépésből álló játékmenetet hoz létre az alábbi vezérlés:

Egyben tesztelés is: igazolja, hogy azonosan működik a két különböző megoldás.

Eredmény

Mivel minden véletlenszerűen alakul a játékban, ezért az alábbi csupán egy a sokféle lehetséges kimenet közül:

A bejegyzéshez tartozó teljes forráskódot – többféle változatban is – ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 5-8. óra: Vezérlő szerkezetek, 9-12. óra: Metódusok, rekurzió, 13-16- óra: Tömbök, illetve a 17-24. óra: Objektumorientált programozás 1. és 2. rész alkalmaihoz kötődik.

PDF fájl készítése

A PDF népszerű fájlformátum. Az Adobe cég 30+ éves szabványa. Hordozható: azaz minden eszközön, platformon ugyanúgy jelenik meg. Számos nézegető program támogatja, köztük böngészőprogramok is. A PDF rövidítés a Portable Document Format betűszava. Többnyire kimeneti formátumnak tekinthető. Az évek során folyamatosan fejlődött: ma már űrlapokat is tartalmazhat, elektronikusan aláírható, hitelesíthető, és hivatalos ügyek során is használják.

PDF fájl többféleképpen is készíthető. Például:

  • irodai szoftverek Mentés másként… menüpontjában,
  • Adobe Acrobat szoftverrel,
  • online alkalmazásokkal sokféle fájlformátum konvertálható PDF-be,
  • speciális célszoftverek is generálhatnak PDF fájlokat.

Utóbbi esetekre néhány példa:

  • online megvásárolt koncertjegyet e-mail csatolmányaként kapunk PDF-ben, ugyanígy számlát is róla,
  • online tanfolyamunk záró tesztjét követően letölthető tanúsítványt, badge-t, online IQ tesztünk eredményeként oklevelet kapunk PDF fájlként,
  • kérdőívek kitöltése során egyéni válaszainkat visszaigazolásként PDF-et kapunk, vagy a kérdőív kitöltési időszakának végén összesített eredményt, PDF riportot kapunk.

Java program készít PDF fájlt

Adatokra van szükség. Korábbi Munkakör, létszám, névsor lekérdezése blog bejegyzésünkben az Oracle HR sémából kétféleképpen is lekérdeztük a szükséges adatokat. Ezt érdemes előzetesen tanulmányozni, hogy a további tartalom könnyebben érthető legyen. A Java SE szoftverfejlesztő tanfolyam megközelítése alapján, az egyszerűbb SQL paranccsal előállított eredménytáblát a PDF generálása előtt még csoportosítani kell (munkakörönként). A Java adatbázis-kezelő tanfolyam megközelítése alapján, az összetettebb SQL paranccsal elkészített, denormalizált eredménytábla közvetlenül felhasználható.

A cél egy táblázat elkészítése, amely 3 oszlopból áll: munkakör, létszám és névsor. Az azonos munkakörű alkalmazottak névsora egy táblázat egyetlen cellájában legyen megjeleníthető. Az elkészült táblázatból készüljön PDF fájl.

A teendők lépésenként

Szükséges az iText csomag importálása: com.itextpdf.text. Korábbi változata az 5-ös, aktuális változata a 8-as. Előbbi nagyon elterjedt, utóbbi még kevésbé ismert. A továbbiakban a kötelező kivételkezeléshez kötődő forráskód-részletek bemutatásától eltekintünk.

Tehát adott az összes szükséges adat egy  ArrayList<MunkakorLetszamNevsor> lista generikus listában. A POJO mindhárom szükséges és összetartozó tulajdonságot tárolja: String munkakor, int letszam, String nevsor.

Hasznos egy általánosan használható cella() függvény elkészítése, amely képes adott szöveget, adott betűmérettel, adott betűstílussal, adott igazítással „megjeleníteni”:

Létre kell hozni a pdfFajl objektumot, beállítani a méretét és a margókat, illetve fájlba kell irányítani:

Létre kell hozni a táblázat előtt megjelenő szöveget (ez nem a szövegszerkesztés szerinti valódi fejléc):

Létre kell hozni a táblázatot, megfelelő beállításokkal:

Létre kell hozni a táblázat fejlécét:

Végig kell haladni az adatokon és elő kell állítani a szükséges táblázatcellákat, végül le kell zárni a fájlt:

A PDF fájl és a belekerülő táblázatobjektum szerkezete DOM-szerű, illetve azonos a grafikus felhasználói felület felépítése során használt AWT/swing konténerszemlélettel.

A felhasznált programozási tételek: sorozatszámítás, kiválasztás, megszámolás, kiválogatás, illetve kombináltan: csoportosítás, rendezés.

Az eredmény

Az elkészült PDF fájl másfél oldalas, itt letölthető, megtekinthető. A dokumentumról készült képernyőkép:


Továbbfejlesztési lehetőségek

Igényeinktől függően, illetve előzetes tapasztalatainkra és a meglévő tudásunkra építve számos ötlet merülhet fel. Mindhárom tanfolyam esetén testre tudjuk szabni azt az SQL parancsot, ami a szükséges adatokat lekérdezi. Az iText csomag helyett felfedezhetjük a PDF Clown, a PDFBox, illetve a Spire.PDF csomagok funkcionalitását is.

  • A Java SE szoftverfejlesztő tanfolyam tematikájához kötődve egyszerűbb dolgokat tudunk megvalósítani. Használhatunk további stílusokat: betűre, bekezdésre, cellára, táblázatra vonatkoztatva, színeket, szegélyeket. Többoldalas dokumentum esetén hozzáadhatunk oldalszámot, oldalszám / oldalak száma mezőt, tényleges fej- és láblécet, generálásra vonatkozó időbélyeget, képezhetjük szabály alapján a PDF fájl nevét, illetve tallózhatjuk annak helyét (hol jöjjön létre).
  • A Java EE szoftverfejlesztő tanfolyam tematikájához kötődve az előzőeken felül elhelyezhetjük a generált fájlt egy szerveren és elküldhetjük e-mailben a letöltéséhez szükséges URL-t. A letöltés korlátozható darabszámmal és időben is (például max. 3 db letöltés lehetséges a következő 48 órán belül). A PDF fájlba belekerülhet szöveges vízjel, céges logó és saját képként dinamikusan előállított grafikon. Például a JFreeChart grafikon készítése projekt swing-es GUI felületéből néhány utasítással készíthetünk JPG vagy GIF formátumú képet, ami könnyen beilleszthető PDF-be. Online, webes API szolgáltatás használatával az előállított PDF fájl tömöríthető, illetve belekerülhet QR kód, vonalkód is.
  • A Java adatbázis-kezelő tanfolyam tematikájához kötődve az előzőeken felül a JDBC alapú back-end kicserélhető JPA alapúra. A PDF láblécébe beleírhatjuk, hogy az adatbázis-szerveren kinek a nevében futott (DB User) az a lekérdezés, ami előállította a szükséges adatokat. Megoldható a generált PDF egyedi azonosítója, azaz kétszer nem állítható elő „ugyanaz”. Modulárisan továbbfejlesztve gyakorolhatjuk a tudatosan felépített MVC architekturális tervezési minta használatát. Limit feletti méretű PDF fájlt több kisebbre szétdarabolhatunk.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.