Java fejtörők – csapdák, buktató, és szélsőséges esetek. Ez egy könyv címe, amelynek szerzői J. Bloch és N. Gafter. Magyar nyelven a Kiskapu Kft. jelentette meg. A 2010-es magyar kiadás a 2005-ös angol nyelvű kiadás fordítása. A könyv weboldaláról (http://www.javapuzzlers.com), letölthető a 95 fejtörőhöz tartozó mintapéldák gyűjteménye, és elérhető a 270 oldalból minta fejezetként 28 oldalnyi tartalom 9 fejtörővel és azok részletes magyarázataival.
A két részre bontott blog bejegyzés a könyv anyagából válogatva készült el. Az első rész a bevezetés. Ez a második rész, haladó szintű példákkal. Néhány példát továbbfejlesztettem.
7. fejtörő: Mit ír ki program a konzolra?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
publicclassTest{
staticvoidworkHard(){
try{
workHard();
}
finally{
workHard();
}
}
publicstaticvoidmain(String[]args){
workHard();
System.out.println("Hello World!");
}
}
Kivételkezelés nélkül arra számítanánk, hogy a
Hello World! nem jelenik meg a konzolon, mert a
wordHard() metódus feltétel nélkül rekurzív módon folyamatosan újrahívja önmagát és az emiatt keletkező
StackOverflowError hibával elszáll a program. A kivételkezelés természetesen módosítja a program működését.
Ha azt feltételezzük, hogy minden
Throwable utódosztályból futás közben létrehozott objektum kivételkezeléssel elkapható, akkor végtelen ciklusnak tűnik a vezérlés, hiszen a
try blokkban hibát okozó metódushívásra a
finally blokkban újra ugyanannak a metódusnak a meghívásával reagálunk, amelyik korábban a hibát kiváltotta. Ez a gondolatmenet tévút. A kulcsszó a rekurzív vezérlést megvalósító verem adatszerkezet mérete. Részletes indoklás a blog bejegyzés végén található.
8. fejtörő: Mit ír ki program a konzolra?
1
2
3
4
5
6
7
8
9
publicclassNull{
staticvoidgreet(){
System.out.println("Hello World!");
}
publicstaticvoidmain(String[]args){
((Null)null).greet();
}
}
Természetesen
NullPointerException-re gyanakszunk, pedig a program hibátlanul működik. A kulcsszó a statikus metódusok minősítése, vagyis annak jelölése, hogy melyik osztálytól vagy objektumtól kérjük annak végrehajtását. Részletes indoklás a blog bejegyzés végén található.
Arra számítunk, hogy a kiírás
1999-12, de ehelyett
20001-et látunk a konzolon. Tudjuk, hogy a
Date osztály jó része már deprecated és ezen próbáltak javítani a
Calendar osztállyal. Bár ne tették volna. A kulcsszó az ős dátumkezelést megvalósító API rejtelmeiben van. Részletes indoklás a blog bejegyzés végén található.
10. fejtörő: Mit ír ki a program a konzolra?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
classX{
staticclassY{
staticStringZ="Black";
}
staticCY=newC();
}
classC{
StringZ="White";
}
publicclassTest{
publicstaticvoidmain(String[]args){
System.out.println(X.Y.Z);
}
}
Nem tűnik egyértelműen eldönthetőnek a helyzet, ezért szintaktikai hibára gyanakodhatunk. Azonban a forráskód helyes, a program futás közben sem dob kivételt/hibát és a konzolon megjelenik a
White. Szokatlan, hogy nagybetűvel konstansokat szokás jelölni, pedig nincs erre utaló
final a forráskódban. A kulcsszó a sorrendiségen van, ha ugyanabban a hatókörben/blokkban van azonos nevű változó és típus/osztály. Részletes indoklás a blog bejegyzés végén található.
11. fejtörő: Mit ír ki a program a konzolra?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
importjava.util.Random;
publicclassTest{
privatestaticRandomr=newRandom();
privatestaticvoidswap(Object[]a,inti,intj){
Objecttemp=a[i];
a[i]=a[j];
a[j]=temp;
}
publicstaticObject[]shuffle(Object[]a){
for(inti=0;i<a.length;i++)
swap(a,i,r.nextInt(a.length));
returna;
}
publicstaticvoidmain(String[]args){
String[]s1={"alma","körte","barack","dinnye"};
for(Objecto:shuffle(s1))
System.out.print(o+", ");
System.out.println();
}
}
A program helyes és egyértelműnek tűnik. A konzolra az
s1 szövegtömb elemei kerülnek ki véletlenszerűen összekeverve. Finomítsunk a kérdésen. Vajon minden lehetséges permutáció azonos eséllyel fordul elő? Ha ez a kérdés egyáltalán felmerül, akkor a válasz nyilván nem. A kulcsszó most egy kis matematika. Részletes indoklás a blog bejegyzés végén található.
12. fejtörő: Mit ír ki a program a konzolra?
1
2
3
4
5
6
7
8
9
10
importjava.util.Arrays;
publicclassTest{
publicstaticvoidmain(String[]args){
Integer[]array={3,1,4,1,5,9};
Arrays.sort(array,
(Integeri1,Integeri2)->i1<i2?-1:(i2>i1?1:0));
System.out.println(Arrays.toString(array));
}
}
Ez a forráskód nem úgy működik, ahogyan a könyv írja. Meglepő módon nem a
[3,1,4,1,5,9]-et adja, hanem az
[1,1,3,4,5,9]-et. Némi indoklás a blog bejegyzés végén található.
Részletes indoklások
7. fejtörő: ha a
try blokkban folyamatosan meghívja saját magát a
workHard() metódus, akkor előbb-utóbb betelik a verem. Ekkor a
finally blokkra kerül a vezérlés, ahonnan újra hívja saját magát a
workHard() metódus. Persze követni kell, hogy a rekurzió végrehajtása során a lefelé haladó vagy a felszálló ágon vagyunk és nem mindegy, hogy melyik szinten. A háttérben egy teljes bináris fa bontakozik ki, amelynek mélysége azonos a verem méretével, mélységi korlátjával. Ezt a teljes bináris fát járja be a program, azaz mélységi fabejárás. Egy n mélységű teljes bináris fa elemeinek száma 2n-1. A verem mérete a virtuális gép beállításaitól függ, több ezer mélységű is lehet. Végtelen ciklusról tehát nincs szó. Ugye milyen izgalmas? További részletek a könyv 100-102. oldalán találhatók.
8. fejtörő: a végrehajtás kiértékeli a statikus
greet() metódus hívásának minősítő kifejezését, de figyelmen kívül hagyja a kapott értéket. A metódust végrehajthatnánk
Null.greet()-ként vagy közvetlenül (minősítés nélkül) meghívva is. További részletek a könyv 122-124. oldalán találhatók.
9. fejtörő: a
Date osztály a hónapokat nulla bázissal kezeli, ezért csak 0-11-ig „van értelme”. Számíthatnánk a tömb vagy szöveg túlindexelésénél tapasztaltakhoz hasonlóan kivételre, de nem ez történik. A 12. hónap a következő év első/nulladik hónapját jelöli. Ezért látjuk a konzolon a
2000-et, amit egy kötőjel követ. A
Date.getDay() deprecated metódus pedig a dátumobjektumban tárolt nap adott héten (nem hónapban!) elfoglalt helyét adja meg, ami nullával, azaz vasárnappal indul. Tehát a konzolon megjelenő
1 nem a 2000. januárt jelenti, hanem azt, hogy a 2000. január 31. hétfőre esik. Aki ezek után meri használni a régi dátumkezelő API-t, magára vessen. További részletek a könyv 141-143. oldalán találhatók.
10. fejtörő: ha ugyanabban a hatókörben/blokkban van azonos nevű változó és típus/osztály, akkor a változó neve az elsődleges. Ha betartjuk a névadási konvenciókat (
ClassName,
objectName,
CONSTANT_NAME), akkor nem adódhatnak ilyen gondok. Még egy csavar van: ha az előző elnevezési módosításokat megtesszük, akkor a program a
Black-et írja ki a konzolra. További részletek a könyv 161-163. oldalán találhatók.
11. fejtörő: konkrét esetből általánosítunk. 4 elemre a ciklus 4-szer hajtódik végre és minden lépésben kiválaszt egyet a 0 és az 3 indexű elemek közül, ami 44=256-féle lehetséges eredményt ad. Ha az
r objektum jól működik, akkor az egyes futások esélye/valószínűsége megegyezik. 4 elemű tömb elemeinek 4!=24 (faktoriális) féle permutációja (lehetséges sorrendje) van. Mivel a 256 nem osztható 24-gyel, így biztos, hogy a
shuffle() metódus bizonyos permutációkat gyakrabban állít elő, mint másokat. Általánosan: nn nem osztható n!-sal, ha n>2 egész szám. Vajon mi történik, ha egy 52 lapos pakli kártyát keverünk össze? Vajon milyen érdekességet vet ez fel? Minden poént nem lövünk le itt a blogban. További részletek a könyv 228-232. oldalán találhatók.
12. fejtörő: ez a tankönyv utolsó példája. A felvetett gondolat nagyon frappáns: az összehasonlító rész „ha fej, én nyerek, ha írás, te veszítesz” tüneteitől szenved. További részletek a könyv 232-233. oldalán találhatók.
Állásinterjúkon időnként visszaköszönnek hasonló fejtörők, de ezekkel óvatosan kell bánni. Egy programozási nyelv „joghézagainak”, buktatóinak, szélsőséges eseteinek ismerete a könyv szintjét elérő ismeretanyaggal nem lehet elvárt még egy meghirdetett senior pozíció esetén sem. Ezen fejtörők ismerete (vagy nem tudása) egy jelöltről nem árulja el a mindennapokban használható szakmai tudás meglétét/hiányát. De nyilván aki szakmailag folyamatosan fejlődik és mindenféle keretrendszert alkotó forráskódokban turkál, elemez, előbb-utóbb találkozik ezekkel/ilyenekkel.
Tanfolyamainkon nem kifejezetten foglalkozunk hasonló problémákkal, de azért időnként feszegetjük a határokat. Természetesen részletesen indokoljuk, ha előkerül valamilyen hasonló eset. Általánosságban nem célunk, hogy extrém eseteken keresztül, a programozási nyelv gyenge pontjaira kihegyezve oktassuk a Java programozási nyelvet.
Ajánljuk a Java SE szoftverfejlesztő tanfolyam kategóriából
Java program memória használatának mérése
Programozási alapok K-MOOC online kurzus az Óbudai Egyetemen
Weboldalunkon cookie-kat (sütiket) használunk, melyek célja, hogy teljesebb szolgáltatást nyújtsunk látogatóink részére. További böngészésével hozzájárul ezek használatához. ElfogadAdatkezelési szabályzat
Privacy Overview
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
Nekem nagyon tetszett ebből a gyűjteményből az a példa is, amelyik Elvis övének hosszára épül:
Nem lőjük le a poént, tessék rákeresni!