2019. szeptember 18., szerda

Könyvtári katalógus létrehozása java programozási nyelven

A könyvek metaadatait a Rekord.java osztályban példányszintű mezőkben tároljuk:

public class Rekord { 

 /* példányszintű mezők */

 public String raktari_jelzet;
 public String cim;
 public String[] szerzok;
 public int kiadasi_ev;

 /* példányszintű metódusok */

 public void kiir() {
  if(raktari_jelzet==null || cim==null) {
   System.out.println("--- torolt rekord ---\n");
   return;
   }
  System.out.println(raktari_jelzet);
  System.out.print(cim);
  if(szerzok!=null) {
   if(szerzok.length>0) {
    System.out.print(" / "+szerzok[0]);
    }
   for(int i=1;i<szerzok.length;i++) {
    System.out.print(", "+szerzok[i]); 
    }
   }
  System.out.print(".");
  if(kiadasi_ev>0) {
   System.out.print(" "+kiadasi_ev+".");
   }
  System.out.println("\n");
  }

 /* konstruktorfüggvények */

 public Rekord() {
  raktari_jelzet=null;
  cim=null;
  szerzok=null;
  kiadasi_ev=0;
  }

 public Rekord(String r) {
  raktari_jelzet=r;
  cim=null;
  szerzok=null;
  kiadasi_ev=0;
  }

 public Rekord(String r,String c) {
  raktari_jelzet=r;
  cim=c;
  szerzok=null;
  kiadasi_ev=0;
  }

 public Rekord(String r,String c,int k) {
  raktari_jelzet=r;
  cim=c;
  szerzok=null;
  kiadasi_ev=k;
  }

 public Rekord(String r,String c,String s1,int k) {
  raktari_jelzet=r;
  cim=c;
  szerzok=new String[1]; //egy szerző van
  szerzok[0]=s1;
  kiadasi_ev=k;
  }

 public Rekord(String r,String c,String s1,String s2,int k) {
  raktari_jelzet=r;
  cim=c;
  szerzok=new String[2]; //két szerző van
  szerzok[0]=s1;
  szerzok[1]=s2;
  kiadasi_ev=k;
  }

 public Rekord(String r,String c,String s1,String s2,String s3,int k) {
  raktari_jelzet=r;
  cim=c;
  szerzok=new String[3]; //három szerző van
  szerzok[0]=s1;
  szerzok[1]=s2;
  szerzok[3]=s3;
  kiadasi_ev=k;
  }

 public static void main(String[] args) { 
  Rekord peld1=new Rekord();
  Rekord peld2=new Rekord("ISBN 963 7222 82 0",
                          "A fantom",
                          "Robert Ludlum",
                          1989);
  Rekord peld3=new Rekord("ISBN 963 03 9005 1",
                          "Java - start!",
                          "Veg Csaba", "Juhasz Istvan",
                          1999);
  peld1.kiir();
  peld2.kiir();
  peld3.kiir();
  }
 }



A katalogus metaadatait a Katalogus.java osztályban osztályszintű mezőkben tároljuk:



public class Katalogus {

/* osztályszintű mezők */

public static String katalogus_neve;
public static int rekordok_szama;
public static Rekord[] katalogus;

/* osztályszintű metódus */

public static void info() {
  System.out.println("Katalogus informaciok:");
  System.out.println("\t[katalogus neve: "+katalogus_neve+"]");
  System.out.println("\t[rekordok szama: "+rekordok_szama+"]");
  System.out.println();
  }

public static void main(String[] args) {
  katalogus_neve="DEENK";
  rekordok_szama=3;
  katalogus=new Rekord[rekordok_szama];
  katalogus[0]=new Rekord();
  katalogus[1]=new Rekord("ISBN 963 7222 82 0",
     "A fantom",
     "Robert Ludlum",
     1989);
  katalogus[2]=new Rekord("ISBN 963 03 9005 1",
     "Java - start!",
     "Veg Csaba", "Juhasz Istvan",
     1999);
  info();
  System.out.println("A katalogusban szereplo rekordok:\n");
  for(int i=0;i<katalogus.length;i++) {
   System.out.println((i+1)+". rekord");
   katalogus[i].kiir();
   }
  }
}




A feladatot egy leszármazott osztály segítségével valósítjuk meg! A programban előforduló legfontosabb nyelvi elemek:

public class Alap31 extends Alap3 {...} (az Alap31 osztály az Alap3 ősosztály vagy szülőosztály leszármazottja lesz)
super.kiir(); (a szülőosztály kiir() eljárását hívja meg)
this("Ismeretlen",null); (az aktuális, Alap31 osztály kétparaméteres konstruktorát hívja meg "Ismeretlen" és null aktuális értékekkel)
super(s); (a szülőosztály egyparaméteres konstruktorát hívja meg s paraméterrel)


A program utasításai:




public class Alap31 extends Alap3 {

public String becenev;

public static void beallit(String v) {
  vnev=v;
  }

public void kiir() {
  super.kiir();
  if(becenev!=null) {
   System.out.println("Hivhatlak ugy, hogy "+becenev+"?");
   }
  }

public Alap31() {
  this("Ismeretlen",null);
  }
public Alap31(String s) {
  this(s,null);
  }
public Alap31(String s,String b) {
  super(s);
  becenev=b;
  }

public static void main(String[] args) {
  Alap31 peld1=new Alap31();
  Alap31 peld2=new Alap31("Ilonka");
  Alap31 peld3=new Alap31("Kata","Katinka");

  beallit("Szep");

  peld1.kiir();
  peld2.kiir();
  peld3.kiir();
  }
}



Szülő és ősosztály


public class Alap3 {

public static String vnev;
public String knev;
public void kiir() {
 System.out.println("Hello "+vnev+" "+knev+"!");
 }

public Alap3(String s) {
 knev=s;
 }

public static void main(String[] args) {
 Alap3 peld1=new Alap3("Kata");
 Alap3 peld2=new Alap3("Szilvi");
 vnev="Nagy";
 peld1.kiir();
 peld2.kiir();
 }
}



Forrás:  http://bodaistvan.hu/prog/ 
https://silver.drk.hu/info-kvtar/3felev/zsu/peldaprogramok.html
http://java.progtanulo.hu/book/export/html/162
http://users.atw.hu/nagyimi/prog/egyszeru_Java_programok.html
http://java.inf.elte.hu/java-1.2/awt/awtprog.html
http://java2.uw.hu/
http://www.petrik.hu/files/tamop/SZINFO13/SZINFO13_TJ.pdf
https://users.iit.uni-miskolc.hu/~vargae/Segedlet/ElekT_Java2_kezdo.pdf
https://www.tutorialspoint.com/compile_java_online.php




 

2019. szeptember 17., kedd

The life

My dear friend,
Time is.. too slow for those who wait; too swift for those who fear; too long for those who grieve; too short for those who rejoice - but for those who love, time is nothing,  life is too much important to be taken seriously, in life there aren't failures, just lessons that need to be learned, wanna be happy? Then do 3 things: be with who makes you smile, laugh as much as you breath, and love as long as you live, in the end it's not the years in your life that count; it's the life in your years! They laugh at me because I'm different, but I laugh at them because they're all the same! smile: such spinline which can right everything, if a man doesn't remember his past, he has no future, live your life & love every second of it…

2019. szeptember 9., hétfő

J.F.Cooper A kém könyvajánlója

Ezt a könyvet elősször 3 forintos könyvben olvastam 15 évesen. Amikor beleuntam a sok indián regénybe, kerestem egy jó kémkönyvet. A kém című könyv a függetlenségi háborúban játszódik.  A Kongresszus kinevez egy titkos bizottságot hogy kémkedjenek az angoloknál, egy házalóként. Harvey Birch – a regény főszereplője. Az ő sorsa fonódik össze az előkelő délvidéki Wharton család történetével. Henry Wharton királypárti kapitány, testvére azonban gyermekkori barátjába, Dunwoodie ezredesbe szerelmes, aki Washington és az ifjú köztársaság szolgálatában áll. A királypárti kapitányt a megvetett „házaló-kém” menti meg a törvény halálos ítéletétől, és szökteti biztonságos helyre. Hogy ki is tulajdonképpen Harvey Birch, azt csak a mintegy fél évszázadot átívelő történet végén tudhatjuk meg. A „kém” meghal a végén a hazájáért. Olvassátok el...

2019. szeptember 6., péntek

A láthatatalan cyberhadsereg

https://threatmap.fortiguard.com/
A kémkedés és hírszerzés hagyományos módszerei elavultak mára, a jelenkor a cyberhírszerzésé. Óriási globális cybertámadás zajlik éppen, ami egyes elemzések szerint minden idők legnagyobb támadása lehet a digitális világban. Minden órában több ezer számítógépet támadnak szerte a virtuálisvilágon. Zsarolóvírusok százai amikről sokszor nem szerzünk tudomást. Egy múlticégnek nem érdeke, hogy napvilágra kerüljön hogy rendszerét feltörték, ezért inkább fizet titokban néhány százezer bitcoint és békén hagyják. Az injektálás módszerével fertőzik meg a gépeket Nagy-Britannia,  Egyesült Államok(Sony Pictures), Kína, Oroszország, potenciális támadók és áldozatok is egyben. A WannaCry névre keresztelt kártevő különféle variánsai támadták meg a Windows egy biztonsági résén keresztül a számítógépeket. Az amerikai kémügynökség számára kifejlesztett Eternal Blue nevű program, ami fájlmegosztó protokollokon keresztül terjedjen szervezetek között, a Shadow Brokers névre hallgató hackercsoport lopta és alakította át saját céljaira.A következő célpont a WannaCrypt program, amit már elloptak és ha átalakítják egy garázsban, milliárdokat kereshetnek vele. A cyber-támadás egy hackerek általi kísérlet egy számítógépes hálózat vagy rendszer megsértésére vagy tönkretételére. Rendszerint az adatok megsértésével jár, ami akkor történik, ha érzékeny vagy bizalmas adatok megtekintésre, használatra vagy ellopásra kerülnek egy illetéktelen személy által. Egy cyber-támadás történhet identitás lopás, vírusok, rosszindulatú programok, csalás és zsarolás formájában. 
https://www.fireeye.com/cyber-map/threat-map.html
A leggyakoribb cyber támadások a ransomware (zsarolóprogram) támadások. Ezek adatokat titkosítanak, amik csak pénz befizetése ellenében válthatók ki. A WannaCry és a Petya két újabb példa a ransomware támadásokra. Egy másik formája a cyber-támadásoknak a sniffer (nyomkövető program), amit arra fejlesztettek ki, hogy begyűjtse a számítógépünkbe beáramló és onnan kimenő forgalmat. Habár ez lényegében ártalmatlannak tűnik, ez a cyber-támadás fajta képes a válallatok kizsákmányolására. Számos útja van, hogy a hackerek hozzáférést szerezzenek a hálózatunkhoz, de a mai támadások között sok a kisebb és csendesebb fajta, amelyeket nehezebb detektálni. A Cyber-támadások rendszerint adathalász emaileken, mobil támadásokon vagy az adatforgalom eltérítésén keresztül történnek. A minapi Petya támadás egy olyan számlázási rendszer frissítésén keresztül szivárgott ki, amelyet az ukrán kormányzattal dolgozó összes vállalatnak használnia kell. Van a támadásnak egy sokkal nyersebb módja is, amit ddos-nek, azaz szolgáltatásmegtagadással járó támadásnak hívnak, amely nagymennyiségű adatforgalmat generál, a rendszer összeomlasztása céljából.
https://threatbutt.com/map/
A rendszer összeomlasztása által, lehetetlenné teszi a felhasználóknak a weboldalunk vagy a szolgáltatásunk elérését. (Ez történt a Twitterrel, Spotify-jal, és a Reddittel 2016 októberében). De a nagy felhasználói bázissal nem rendelkező kisebb vállalatok esetében rendszerint az adathalász emaileké a főszerep. Mivel az adathalász emaileket úgy tervezték, hogy biztonságos emaileknek nézzenek ki, igen nehéz detektálni őket. Tim Bandos, a Digital Guardian cyberbiztonsági igazgatója szerint, a legjobb útja a cybertámadások általi adattitkosítás és adatrongálás megelőzésének az alkalmazottak képzése és tréningje arra vonatkozólag, hogy miként néz ki egy adathalász email. Az adathalász emailek rendszerint néminemű sürgetést és egy fájl kiterjesztést tartalmaznak. Némely hacker hónapokat tölt egy vállalat analízisével, mielőtt elküldene egy olyan adathalász emailt, amely egy belső emailnek van álcázva.
https://cybermap.kaspersky.com/
 Habár ezt nehéz detektálni, a megfelelően oktatott alkalmazottak tudni fogják, hogyan szűrhetik ki az ilyesmit. Több cég hiszi azt, hogy őket nem támadják majd meg, mégis megéri a befektetést ennek megelőzése. Installáljunk egy antivírus szoftvert Habár a cyber-támadások rendszerint vállalatokra irányulnak, a vírusok véletlenszerűen bukkanhatnak fel és sokkal gyakoribbak. Habár egy vírus talán nem titkosítja az adatainkat, még mindig ellophatja azokat és megfertőzheti a számítógépünket, lelassítva a produktivitásunkat. A legjobb antivírus szoftverek is gyakran csak a vírusok 99%-ával képesek megbirkózni. Megvédhet minket a kémprogramok ellen is, amelyeket arra terveztek, hogy beleskelődjenek a vállalati tevékenységekbe és rögzítsék az adatainkat. A kéretlen spamek ellen is védelmet nyújthat, amelyekkel senki se szeretne foglalkozni. Keressünk egy napi ellenőrzéseket és frissítéseket futtató antivírus szoftvert, amely segít megvédelmezni az adatainkat és számítógépünket.
Míg egy anti-virus szoftver rendszerint képes a vírusok detektálására és a tőlük való megszabadulásra, egy tűzfal azt akadályozza meg első körben, hogy a számítógépünkhöz férkőzhessenek a vírusok. Egy tűzfal alapvetően egy rostát jelent, a számtógépünk és az internet között. A neten böngészés közben szüntelenül információcsomagokat küldünk előre és vissza. Egy tűzfal megszűri ezeket a csomagokat és védelemként van jelen minden ártalmas csomaggal szemben. Mindazonáltal, ha egy vírus mégis átjutna, a tűzfal nem képes eltávolítani azt.
https://threatmap.bitdefender.com/
Használjunk egy VPN-t Ha kicsi vagy közepes méretű vállalat vagyunk, megvan az esélye, hogy némely alkalmazottunk távolról dolgozik. A fejlett okostelefonok és táblagépek egyszerűvé teszik, hogy az irodán kívülről dolgozzunk vagy akár ingázás közben. De anélkül, hogy garantálni tudnánk, hogy alkalmazottaink egy biztonságos hálózatot használnak, megvan a kockázata, hogy a vállalatot hackertámadás éri. Különösen, ha nyilvános WiFi hálózatot használunk, a hackerek könnyedén lefigyelhetik, hogy az alkalmazottak milyen adatokat küldenek.Egy VPN, ami szinte bárhol és bármilyen készülékről használható, titkosítja az adatokat, jelentősen nehezebbé téve a hackerek számára a lefigyelést. A VPN-ek, vagy Virtuális Magánhálózatok, eredetileg nagyvállalatok és kormányzatok számára lettek kifejlesztve, hogy a távoli alkalmazottak biztonságosan kapcsolódhassanak a vállalati hálózatokhoz, anélkül, hogy veszélyeztetnék az adatokat. Egy VPN egy csatornát képez a dolgozó készüléke és a cég szervere között, megvédve a hackerektől és másoktól, akik adatlopásra vetemednének. Titkosítja is az adatokat, így még ha el is lopnák őket, majdhogynem lehetetlen a titkosítás megfejtése. A támadás nyomai kínai szerverekhez vezetnek vissza.
https://www.deteque.com/live-threat-map/ Minden ország arra törekszik, hogy egy láthatatlan cyberhadsereget hozzon létre a legnagyobb titokban és mindenki mindenki ellen mehet az adathalászat erkölcsök normák törvények semmibevételével.

2019. szeptember 4., szerda

A kvantummechanika titkai

Paradigmaváltások tucatjaira volt szükség a kvantumszámítógépek előállítására. A nem mérhető folyamatokat át kell alakítani metrikussá, hogy a számítógép értékelhesse. A jelfeldolgozás a digitális számítógépek elterjedésével nagyságrendekkel felgyorsult, és lehetővé vált a valós idejű és online kiértékelés, vezérlés és irányítás. A folyamatokat jellemző jelek általában nem alkalmasak digitális számítógépen történő feldolgozásra. A folyamatok többségét jellemző analóg folytonos jelek digitális jellé történő átalakítása kvantálással történik. Jó példa erre, a bakelit lemez hangjának digitalizálása Sunforge programmal.
Neumann János 1927-1928-ban Göttingenben David Hilbert mellett a funkcionálanalízis terén végzett kutatásokat, míg Wigner Jenő Hilbert asszisztenseként  az atomok spektrumának értelmezésére a csoportelmélet módszereit kutatta. Együtt publikáltak Neumann Jánossal, akivel a csoportelméleti módszert kiterjesztették az elektronspinre is. A kvantummechanika a fizika azon ága, amelyik a nanoszkopikus méreteknél történő jelenségeket vizsgálja; így az elemi részecskék viselkedését vagy például az olyan alacsony hőmérsékletű makrojelenségeket, mint a szuperfolyékonyság és a szupravezetés.
A név abból a megfigyelésből származik, hogy bizonyos fizikai tulajdonságok egységi mennyiségenként (latin: kvantum), nem pedig folyamatos (analóg) módon változnak. A kvantummechanika alapvetően négy jelenségre szolgáltat magyarázatot, amikre a klasszikus mechanika és a klasszikus elektrodinamika nem:    kvantálás,    a hullám-részecske kettősség,    a határozatlansági reláció és    a kvantum-összefonódás. A kvantumfizika és kvantumelmélet kifejezéseket gyakran a kvantummechanika szinonimájaként használjuk, máskor viszont bővebben beleértjük a kvantummechanika előtti régebbi kvantumelméleteket is, vagy amikor a kvantummechanikát egy sokkal szűkebb értelemben használjuk (a klasszikus mechanika mintájára), akkor beleértjük az olyan elméleteket például, mint a kvantumtérelmélet vagy annak első kidolgozott változatát, a kvantum-elektrodinamikát.
A kvantummechanika egy rendszer pillanatnyi állapotát a hullámfüggvénnyel ábrázolja, ami a mérhető tulajdonságok – másképpen megfigyelhető mennyiségek – valószínűségi eloszlását írja le. Megfigyelhető mennyiség például az energia, térbeli helyzet (a nem relativisztikus elméletben), impulzus, impulzusmomentum stb. Neumann János, aki a Hilbert-tér (ez az elnevezés is tőle származik) operátorainak spektrálelméletével foglalkozott, azonnal észrevette, hogy a matematikának ez a fejezete kiválóan megfelel arra a célra, hogy a kvantummechanikát korrekt és szigorú matematikai alapokra helyezze. 1927-1929 folyamán több fontos cikket jelentetett meg a kvantummechanika matematikai alapjairól
 A kvantummechanika általában nem rendel határozott értékeket a megfigyelhető mennyiségekhez, hanem becsléseket ad a valószínűségi eloszlásukra. Egyes eloszlások csak diszkrét értékeit engedik meg a megfigyelhető mennyiségeknek, az ilyen mennyiségeket kvantáltnak nevezzük. A hullámfüggvény az időben fejlődhet. Például az üres térben mozgó részecske ábrázolható egy átlagos helyzet körül el nem tűnő hullámcsomaggal. Az idő múlásával ez az átlagos pozíció eltolódhat a térben, ahogy a hullámcsomag változik, és a részecskét nagy valószínűséggel máshol fogjuk megtalálni, mint annak előtte. Másrészt vannak olyan hullámfüggvények, amelyekhez időben állandó valószínűség-eloszlás tartozik. Sok rendszer, amit a klasszikus fizika dinamikusan ír le, a kvantummechanikában ilyen statikus hullámfüggvénnyel írható le. Például a klasszikus kép szerint a nem gerjesztett atomban az elektron kering az atommag körül, míg a kvantummechanikában az elektront egy középpontos szimmetriával rendelkező valószínűségi függvény („elektronfelhő”) írja le.
Egy megfigyelhető mennyiség tényleges megmérése megváltoztatja a rendszert és a hullámfüggvényét. Közvetlenül a mérés után a hullámfüggvény teljesen kompatibilis a méréssel, azaz olyan, amelyik 100% valószínűséget ad az éppen kapott eredményre. Ez a jelenség a hullámfüggvény összeomlása. Egy adott hullámfüggvénybe való összeomlás valószínűsége függ a mérés típusától és kiszámolható a mérés előtti hullámfüggvényből. Nézzük az üres térben mozgó részecske fenti példáját. Ha megmérjük a részecske helyzetét, véletlenszerű eredményt kapunk. Általában lehetetlen megjósolni a kapott x értéket, bár valószínű, hogy a hullámcsomag centrumához – ahol a hullámfüggvény amplitúdója nagy – közeli értéket kapunk. Közvetlenül a mérés után a hullámfüggvény egy olyan hullámfüggvénybe omlik össze, ami élesen a mért x érték körül összpontosul. A részecske sebességének a mérése egy teljesen más hullámfüggvényhez vezetne. Neumann János a mátrixmechanika dinamikai egyenleteit bizonyos szempontból az integrálegyenletekkel állította analógiába, amelyek elmélete Fredholm kutatásainak köszönhetően már igen magas fejlettségi szintet ért el. Ennek megfelelően kutatásaiban kiterjedten alkalmazta a funkcionálegyenletek, például integrálegyenletek elméletének módszereit.
Érdekes módon Neumann János e felismerését igazolja a modern kvantum-szóráselmélet, amelyben az integrálegyenletek elméletének matematikai apparátusa kiemelkedően fontos szerephez jut. A hullámfüggvény időfejlődése determinisztikus abban az értelemben, hogy adott időben, adott hullámfüggvényből kiindulva határozott becslést kapunk arra, hogy bármely későbbi időben milyen lesz a hullámfüggvény. Nem relativisztikus esetben ezt a folytonos időfüggést írja le a Schrödinger-egyenlet, amit relativisztikus esetben a Dirac-egyenlettel kell helyettesítenünk. Mérés közben a hullámfüggvény változása viszont valószínűségi, nem determinisztikus. A kvantummechanika valószínűségi jellege tehát a mérés folyamatában rejlik. Mint a bevezetés is említi, több olyan jelenség van a kvantummechanikában, aminek nincs klasszikus megfelelője. Ezeket gyakran kvantumeffektusoknak hívjuk. Az egyik kvantumeffektus bizonyos mennyiségek kvantálása. Láttuk, hogy bizonyos megfigyelhető mennyiségek a kvantummechanikában diszkrét értékeket vesznek fel, mint például az impulzusmomentum, vagy egy kötött állapot energiája vagy adott frekvenciájú elektromágneses sugárzás energiája, bár nem minden kvantummechanikában előforduló mennyiség kvantált.
Egy másik kvantumeffektus a határozatlansági reláció. Bizonyos mennyiségpárok egyidejű (szimultán) mérése elvi hibahatáron kívül lehetséges csak. Ilyen pár például egy részecske helyzete és impulzusa. Hasonló reláció érvényes az energiára és az időre is olyan értelemben, hogy két egymást követő energiamérés hibája nő, ha a két mérés közötti idő csökken. Az ilyen mennyiségpárok a klasszikus fizikában egymás kanonikus konjugáltjai.
A Kétrés-kísérlet során kialakuló interferenciakép 8, 270, 2000 és 60000 egyedülálló elektron esetén, ami az elektron hullámtulajdonságát mutatja.  Egy másik kvantumeffektus a hullám-részecske kettősség. Erre példa az, hogy bizonyos kísérleti körülmények között az elektronok részecskeszerű (például szórás), mások között hullámszerű (például interferencia) viselkedést tanúsítanak. Egy másik kvantumeffektus a kvantum-korreláció, vagy más néven kvantum-összefonódás.
Bizonyos esetekben egy összetett rendszer hullámfüggvénye nem szeparálható az elemek független hullámfüggvényeire. Az így összefonódott részecskék klasszikus szempontból rendkívül furcsa viselkedést mutathatnak. Például az egymástól egyébként távoli részecskéken végzett helyi mérések eredményeinek korrelációi a megszokott klasszikus statisztikákkal nem egyeztethetők össze. Az ilyen jelenséget felmutató kísérletek a kvantummechanika legmélyebb bizonyítékai, ilyen az alagúteffektus is. alagúteffektus Kvantummechanikai folyamat, amelynek során az elemi részecskék bizonyos valószínűséggel olyan akadályokon is átjuthatnak, amelyeken a klasszikus mechanika törvényei szerint biztosan nem hatolnának át.
A jelenség az anyagi részecskék hullámtulajdonságával magyarázható.
Az alfa-bomlás, az alagút-elektronmikroszkóp működése és a Josephson-átmenet is az alagúteffektussal magyarázható. Ahogy nagyapám mondaná, amikor már magyarázkodni kell, akkor régen vége.  A klasszikus fizika szerint pl. egy golyó nem hatolhat át egy vékony, de áttörhetetlen falon. A kvantummechanika szerint a falhoz érkező részecske, nagyon kis valószínűséggel, de átjuthat a fal túloldalára is. Ez azt jelenti, hogy az esetek csekély számában a részecske megjelenhet a falon túl, anélkül, hogy a falat akár megmászta, akár áttörte volna. Az egydimenziós dobozba zárt elektron tárgyalásakor feltételeztük, hogy a dobozt végtelen magas „potenciálfal” határolja. A magánvéleményem, hogy ha egy tudomány sok axiómára épül az lehet csak hókuszpókusz. Ekkor az elektron megtalálási valószínűsége az adott 0 < x < L tartományon kívül zérus, s az elektront a doboz belsejében állóhullám reprezentálja. Az állóhullám képhez úgy is eljuthatunk, hogy a mechanikai, illetve fényhullámok analógiájára feltételezzük, hogy az elektronhullám a doboz falának ütközve visszaverődik, és önmagával interferálva alakítja ki az időben stabilisan fennmaradó állóhullámot.
A fényről azonban tudjuk, hogy új közeg határára érve csak részben verődik vissza, s a hullám bizonyos mértekben mindig behatol az új közegbe is. Ez csekély mértékben még teljes visszaverődés esetén is bekövetkezik. A részletes kvantummechanikai számítások azt mutatják, hogy amennyiben a bezárt részecske mozgását csak véges magasságú és szélességű potenciálgát korlátozza, akkor az anyaghullámok véges valószínűséggel olyan potenciálgátakkal határolt területre is behatolhatnak, amelyek magassága jóval nagyobb a részecske összenergiájánál, s amennyiben a gát keskeny, akkor a hullám át is hatolhat rajta. A hétköznapi tapasztalataink szerint ezt a különösnek tűnő jelenséget alagúteffektusnak nevezzük. Az elnevezés onnan ered, hogy a klasszikus mechanikában egy test nem juthat át az előtte tornyosuló hegy (potenciálgát) túloldalára, ha nincs elegendő energiája a hegy megmászására,[1] csak ha a hegybe fúrva alagutat talál. Ez a viselkedés a klasszikus fizika szabályai szerint teljesen lehetetlen. Amennyiben hasonló mozgás makroszkopikus körülmények között is végbemenne, akkor az azt jelentené, hogy a hegyoldalon felfelé gurított golyó estenként akkor is átkerülne a szomszédos völgybe, ha a mozgási energiája a hegy lábánál kisebb, mint a hegytetején a helyzeti energia.
Az áthatolás azonban nem mindig következne be, hanem csak véletlenszerűen, s a hegy magasságának és szélességének növekedtével egyre ritkábban. Továbbá növelné az ilyen ritka események furcsaságát az, hogy a szomszéd völgyből a hegyen átjutó golyót sohasem a hegy tetején. Ilyenkor úgy képzelhetjük, mintha a potenciálgáton áthaladó részecske nem a gátat megmászva, hanem egy alagúton keresztül került volna át az akadályon. Az alagútjelenség jellegzetesen kvantummechanikai természetét a határozatlansági reláció segítségével érthetjük meg pontosabban.  Az alagúteffektus hatékonysága a potenciálgát szélessége mellett az alagutazó részecske tömegének, illetve a potenciálgát magasságának növekedésével csökken. Az alagúteffektus általában a könnyű elektronok mozgásakor jelentős, de szerepet játszik az alfa-sugárzás kibocsátásakor is.Relativisztikus kvantummechanika Induljunk ki Heisenberg határozatlansági relációiból. Az egyik azt állítja, hogy nem lehetséges az impulzus és a helykoordináta együttes tetszőleges pontosságú mérése, a másik pedig azt, hogy nem lehetséges az energia mérése úgy kétszer egymás után, hogy a két mérés tetszőleges rövid idővel követi egymást, és a két energiamérés tetszőleges pontossággal ugyanazt az értéket adja. Az utóbbi esetben nagyon fontos tehát hangsúlyozni, hogy nem az energia és idő együttes mérésének tetszőleges pontosságáról van szó, fizikai, pontosabban kvantummechanikai értelemben ugyanis az időt nem lehet mérni, az egy külső paraméter. Amikor időmérésről beszélünk, azt mindig klasszikus newtoni, vagy speciális einsteini – ami ugyanaz – értelemben tesszük.
A helyre és időre vonatkozó határozatlansági relációban ténylegesen a sebesség lép fel, ebből származódik a klasszikus impulzus, ahol egyikre sincs semmilyen felső határ. A relativisztikus esetben viszont a sebességnek van felső határa, a fénysebesség, ezért ott az impulzusnak is van felső határa. Nagyon fontos megjegyezni, hogy az impulzusra ez a felső határ csak a határozatlansági relációban létezik, ahol az impulzust a sebességből származtatjuk. Egyébként az impulzusnak nincs felső határa, ahogy az energiának sem, amivel az impulzus négyesvektort alkot, hacsak nem a Planck-energia és a Planck-impulzus. A határozatlansági relációban fellépő felső impulzushatár miatt viszont a koordinátamérés pontosságára abszolút alsó határ lép fel, azaz a relativisztikus kvantummechanikában a koordinátamérés elveszti értelmét. A koordinátareprezentáció helyett kizárólag az impulzusreprezentációt használhatjuk, azaz a kölcsönhatások és mérések során az energia és impulzus változásait tudjuk csak pontosan követni, implicit módon feltételezve, hogy elég hosszú ideig mérünk. A tökéletes méréshez végtelen hosszú ideig kellene mérnünk, de a klasszikus mérőeszközeinknek amúgy is van egy mérési hibája, és a mérési idő elég hosszú ahhoz, hogy az elvi hiba ezen gyakorlati hibán belül legyen.

A megtalálási valószínűségben a hullámfüggvény abszolútérték-négyzete, azaz a hullámfüggvény és komplex konjugáltjának a szorzata lép fel. A nem relativisztikus elméletben ez, a sűrűség-eloszlás, egy skalármennyiség, a relativisztikus elméletben viszont a négyes áramsűrűség időszerű komponense. A komplex konjugált viselkedése ezért a nem relativisztikus elméletben tökéletesen meghatározott az eredeti hullámfüggvény viselkedése alapján, a relativisztikus elméletben viszont a komplex konjugált önálló életre kel, önálló szabadsági fokokká válik. Matematikailag ez azt jelenti, hogy a nem relativisztikus elmélet kétkomponensű komplex spinorjai helyett négykomponensű Dirac-spinorok tudják leírni a részecskéket, s fizikailag a részecskék száma megduplázódik, mert megjelenik (majdnem) mindegyiknek az antirészecskéje is.
Az antirészecskék létezése a Lorentz-invariancia egyenes következménye. Másrészt az antirészecskék kísérleti megfigyelése a Lorentz-invariancia és a speciális relativitáselmélet egyik kísérleti bizonyítéka. A relativisztikus kvantummechanika Dirac első értelmezésében állandóan jelenlevő végtelen sok részecskét (Dirac-tenger) követelt meg az antirészecskék leírására, amelyek betöltötték az összes lehetséges alsó energiájú állapotot. Ez az értelmezés még fermionok esetén is kicsit kényelmetlen, bozonok esetén viszont, ahol egy állapotban akárhány részecske lehet, értelmetlen. Olyan elméletre volt szükség, ami le tudja írni a részecskék számának változását. A megoldást a második kvantálás, az eddig függvény vagy matematikai vektor hullámfüggvény operátorosítása jelentette.
A hullámfüggvény részecskekeltő és eltüntető operátorok lineáris kombinációjává vált, s ezek az operátorok a részecskeszám-téren (Fok-tér) hatottak. Az így megszületett kvantumtérelmélet ezen leírási módszerét Fok-reprezentációnak nevezzük a kezdeményező Vlagyimir Alexandrovics Fok orosz fizikus, matematikus után. Az első ilyen elmélet, a kvantum-elektrodinamika, az elektromágneses kölcsönhatás kvantumtérelméletének sikere ösztönzőleg hatott a kvantumtérelmélet további általánosításai irányában. A téridő szimmetriái után az ún. belső szimmetriák felfedezése, amiknek legrégebben ismert példája az elektrodinamika mértékinvarianciája vezetett a mértéktérelméletek kifejlesztéséhez. Ezek igen gyümölcsözőnek bizonyultak az anyag olyan kölcsönhatásainak, mint az elektromágneses, gyenge és erős kölcsönhatás kvantumtérelméleti leírásában. A kvantummechanika szigorú, formális matematikai felépítésében, mely többek közt Paul Dirac és Neumann János nevéhez fűződik, a kvantummechanikai rendszerek lehetséges állapotait egységvektorokkal  („állapotvektorok”) reprezentáljuk, melyek a komplex szeparábilis Hilbert-tér egységgömbjét alkotják (az „állapotteret”). A Hilbert-tér pontos meghatározása az adott fizikai rendszertől függ, például ha egy elektronburok elemeinek a tér adott pontjában való tartózkodási valószínűségét, az elektronfelhő „intenzitását” akarjuk leírni, akkor célszerű a négyzetesen integrálható függvények Hilbert-terét használni ennek leírására, míg egyetlen elektron spinjének állapotterét pusztán két komplex sík direkt szorzata is leírhatja.
A kvantumállapotok időbeli változásait nem relativisztikus esetben a Schrödinger-egyenlet – másodrendű differenciálegyenlet –, relativisztikus esetben a Dirac-egyenlet – elsőrendű differenciálegyenlet – írja le, melyben a Hamilton-függvény, a rendszer összenergiáját leíró operátor felelős az időbeli változásért (a Dirac-egyenlet csak a feles spinű részecskéket írja le). Minden megfigyelhető mennyiséget egy sűrűn definiált hermitikus (ejtsd: ermitikus) lineáris operátor reprezentál. Egy megfigyelhető mennyiség minden saját állapotához az operátor egy sajátvektora tartozik, és az ehhez tartozó sajátérték a mennyiség értékét adja az illető saját állapotban. Ha az operátor spektruma diszkrét, a mennyiség csak ama diszkrét sajátértékeket veheti fel. Ezeket a sajátértékeket hívjuk kvantumszámoknak. Például a szabad részecske energia-operátorának spektruma folytonos, míg például a harmonikus oszcillátor energia-spektruma diszkrét.
Egy mérési eljárás alatt annak a valószínűsége, hogy a rendszer hullámfüggvénye valamelyik saját állapotba omlik össze, a sajátállapotvektor és az állapotvektor skaláris szorzatának abszolútérték-négyzete. A mérés lehetséges eredményei az operátor sajátértékei, melyek Hermite-féle operátorok esetén valós számok – ez magyarázza, hogy miért hermitikus operátorokat használunk. Egy megfigyelhető esemény valószínűség-eloszlását egy adott állapotban a megfelelő operátor spektrális dekompozíciójával számíthatjuk ki. A Heisenberg-féle határozatlansági reláció azzal a formális állítással írható le, hogy bizonyos megfigyelhető eseményekhez tartozó operátorok nem felcserélhetőek.
Nagyon fontosak az olyan fizikai mennyiségekhez tartozó operátorok, amelyek egymással felcserélhetők. Az ilyen fizikai mennyiségek egyszerre tetszőleges pontossággal mérhetők, ezért alkalmasak egy fizikai rendszer állapotának a jellemzésére. Az egymással felcserélhető operátoroknak ugyanis van közös saját állapotrendszere, amihez az említett összes felcserélhető operátornak határozott sajátértéke, azaz az illető fizikai mennyiség határozott értéke tartozik. Mindezen operátorok közül a Hamilton-operátor kitüntetett helyzetű, ennek sajátértékei az energia lehetséges értékei. A Hamilton-operátorral felcserélhető operátorok megmaradó fizikai mennyiségeket írnak le. Alapvető fontosságú annak megértésében, hogy az egyes atomok hogyan állnak össze molekulákká. A kvantummechanika kémiai alkalmazását kvantumkémiának hívjuk. A kvantummechanika kvantitatív rálátást nyújt a kémiai kötések mibenlétére, arra, hogy mely molekulák kedvezőbbek energetikailag melyekhez képest, és kb. mennyivel. A számítási kémia legtöbb számolása a kvantummechanikán alapul. A modern technológia jórészt olyan skálán működik, ahol a kvantumeffektusok jelentősek. Ezekre példa többek között a lézer, az elektronmikroszkóp és a mágnesesrezonancia-képalkotás (MRI). A félvezetők tanulmányozása vezetett a dióda és a tranzisztor kifejlesztéséhez, amik nélkülözhetetlenek az elektronikában.
A kutatók ma a kvantumállapotok erőteljes befolyásolásának módszereit keresik. Erőfeszítéseket tesznek a kvantumkriptográfia kifejlesztésére, ami az információátadás garantáltan biztonságos módját jelenti majd. Egy távlatibb cél a kvantumszámítógép kifejlesztése, ami a várakozások szerint bizonyos számolásokat exponenciálisan gyorsabban végezne el, mint a klasszikus számítógép. Egy másik aktív kutatási terület a kvantum-teleportáció, ami kvantumállapotok tetszőleges távolságra való átvitelével foglalkozik. A kezdetek óta a kvantummechanika ösztönökkel ellenkező eredményei erős filozófiai vitát keltettek és sok interpretációhoz vezettek. Még az olyan alapvető dolgoknak, mint Max Born valószínűségi amplitúdókat és valószínűségi eloszlásokat érintő alapszabályainak is évtizedekre volt szükségük ahhoz, hogy elfogadják őket. A nagyrészt Niels Bohrnak köszönhető koppenhágai értelmezést ma a fizikusok nagy többsége elfogadja. Eszerint a kvantummechanikai jóslatok valószínűségi természete nem magyarázható más, determinisztikus elméletek segítségével, és nem egyszerűen a mi korlátozott tudásunkat jeleníti meg. A kvantummechanika azért nyújt valószínűségi jóslatokat, mert a világegyetem természete maga valószínűségi és nem determinisztikus. Albert Einstein, aki maga is a kvantumelmélet egyik megalapozója volt, nem szerette a determinisztikusságnak a mérés során való elvesztését. Úgy tartotta, hogy lennie kell egy helyi rejtett változós elméletnek a kvantummechanika alatt, s ennélfogva a jelen elmélet nem teljes.
Az elmélethez ellenvetések sorozatát gyártotta, amelyek közül a leghíresebb Einstein–Podolsky–Rosen-paradoxon (EPR-paradoxon) néven vált ismertté. John Bell megmutatta, hogy az EPR-paradoxon kísérletileg tesztelhető különbségre vezet a kvantummechanika és a lokális rejtett változós elméletek között. Kísérleteket végeztek és kimutatták, hogy a kvantummechanika a helyes és a világ nem magyarázható ilyen rejtett változókkal. A kísérletekben lelt bizonyos "rések" azonban azt mutatják, hogy a kérdés még nincs teljesen lezárva. Hugh Everett sokvilág-interpretációja, amit 1956-ban fogalmazott meg, azt állítja, hogy a kvantummechanika által megengedett lehetőségek mind együtt megjelennek egy multiverzumban, ami sok független, párhuzamosan létező univerzumból áll. Ez nem jelenti új axióma bevezetését a kvantummechanikában, hanem éppen ellenkezőleg, egynek, a hullámcsomag összeomlásának axiómájának az elvetését jelenti. Az összes lehetséges konzisztens állapot és a mérőberendezés (beleértve a megfigyelőt is) is egy valódi fizikai (nemcsak formális matematikai, mint más interpretációkban) kvantum-szuperpozícióban vannak. Különböző rendszerek konzisztens állapot-kombinációinak ilyen szuperpozícióját összefonódott állapotnak hívjuk. Míg a multiverzum determinisztikus, mi nem determinisztikus, valószínűségi viselkedést érzékelünk, mivel mi csak az univerzumot tudjuk megfigyelni, azaz csak a mi általunk lakott világnak az említett szuperpozícióhoz való konzisztens állapot hozzájárulását.
Everett interpretációja tökéletes összhangban van John Bell kísérleteivel, és ösztönösen is érthetővé teszi őket. 1900-ban Max Planck bevezette az energia kvantálását, hogy levezessen egy, a feketetest által kisugárzott energia frekvenciafüggését helyesen leíró képletet. 1905-ben Einstein a fotoelektromos hatást azzal a feltételezéssel tudta magyarázni, hogy a fény részecskékből, fotonokból áll. Az ötlet, miszerint a foton energiájának kvantumokból kell összeadódnia, jelentős eredmény volt, mivel megszüntette a lehetőségét annak, hogy a feketetest-sugárzás végtelen nagy energiát vigyen magával, ahhoz képest, ha kizárólag csak hullámokkal kellett volna a jelenséget magyarázni. 1913-ban Bohr megmagyarázta a hidrogénatom színképvonalait, ismét a kvantumosság feltételezésével, 1913 júliusában megjelent Az atomok és molekulák szerkezete c. cikkében. 1924-ben terjesztette elő Louis de Broglie anyaghullám-elméletét, mely szerint minden anyag rendelkezik hullámtulajdonsággal és megfordítva.
Ezek az elméletek, bár sikeresek, de szigorúan véve fenomenologikusak (jelenségszintűek) voltak, a kvantálásnak nem létezett precíz bizonyítása. Ezeket együtt a régi kvantumelmélet néven ismerik. A modern kvantummechanika 1925-ben született meg, amikor Heisenberg kifejlesztette a mátrixmechanikát, Schrödinger pedig a hullámmechanikát, majd felírta a Schrödinger-egyenletet. Schrödinger utána megmutatta, hogy a két megközelítés egyenértékű. (Valamivel Schrödinger előtt Lánczos Kornél Heisenberg egyenleteiből kiindulva integrálalakban fogalmazta meg a kvantummechanikát[3]). Heisenberg határozatlansági relációját 1927-ben fogalmazta meg, és a koppenhágai értelmezés is nagyjából ekkor öltött formát. Az 1927-es évet követően Paul Dirac egyesítette a kvantummechanikát a speciális relativitáselmélettel, felfedezve az elektron Dirac-egyenletét. Ő volt az első abban is, hogy operátorelméletet használt, és bevezette a nagy hatású braket-jelölést, amit 1930-as híres könyvében tett közzé. Ugyanebben az időben Neumann János lefektette a kvantummechanika precíz matematikai alapjait, mint a Hilbert-terek lineáris operátorainak elméletét, és ezt közzétette hasonlóképpen híres 1932-es könyvében. Ezek a munkák, mint sok más is az alapító időszakból, azóta is érvényesek és széles körben használják őket.
A kvantumkémia úttörői Walter Heitler és Fritz London voltak, akik 1927-ben tették közzé tanulmányukat a hidrogénmolekula kovalens kötéséről.
A kvantumkémiát rengeteg tudós fejlesztette tovább, többek között az amerikai Linus Pauling. 1927-től kezdődően kísérletek folytak arra, hogy a kvantummechanikát egyes részecskék helyett mezőkre alkalmazzák, amivel megszülettek a kvantumtérelméletek. A korai munkákban többek között Dirac, Pauli, Weisskopf és Jordan vett részt. A kutatások a kvantum-elektrodinamika megfogalmazásában csúcsosodtak ki az 1940-es években, melyben Feynman, Dyson, Schwinger és Tomonaga játszott nagy szerepet. A kvantum elektrodinamika az elektron, a pozitron és az elektromágneses mező kvantumelmélete, és a többi kvantumtérelmélet modelljéül szolgált. A kvantum-színdinamika elméletét az 1960-as évek elejétől kezdve öntötték formába. Ma ismert alakját Politzer, Gross és Wilzcek munkássága következtében 1975-ben nyerte el. Schwinger, Higgs, Goldstone, Glashow úttörő munkájára építve, Weinberg és Salam egymástól függetlenül megmutatták, hogyan lehet a gyenge kölcsönhatást és a kvantum-elektrodinamikát egyetlen elektrogyenge kölcsönhatásban egyesíteni.A kvantumszámítógép olyan számítóeszköz, amelyik úgy végez számításokat, hogy kvantummechanikai jelenségeket használ, mint a kvantum-szuperpozíció és a kvantum-összefonódás.
Egy kvantumszámítógép képes lehet olyan számítások hatékony végzésére, amik a hagyományos, digitális számítógépekkel gyakorlatilag megoldhatatlanok. Kutatását és későbbi megvalósítását elsősorban kormányszervek támogatják. A kvantumszámítógép gyakorlati megvalósítása a kezdeti lépéseknél tart, egyelőre kísérleti fázisban van. A kvantumszámítógép a számításokat egymással párhuzamosan hajtja végre, ezért programozásához speciális programozási módszer szükséges. A kvantummechanikai hatások miatt a rendszert közel abszolút nulla fokra kell folyamatosan hűteni. Vezetékezése koaxiális kábelekkel történik, amik szupravezető tulajdonságúak (ezek szintén igen alacsony hőmérsékleten működnek).
A bemenetet mikrohullámú impulzusok jelentik, amik befolyásolják a részecskék állapotait. A kimenő jeleket magas szintű kvantummechanikai ismeretekkel rendelkező operátorok értelmezik. Nagyobb a hűtő mint a számítógép. Általában, amikor a fizikusok összefonódást váltanak ki részecskék között, akkor ettől függetlenül a részecskék valamilyen módon még ezután is megkülönböztethetőek. Csak mostanában sikerült bemutatni, hogy lehetséges olyan összefonódást kiváltani, ami ténylegesen teljesen azonos részecskéket eredményez. Érdekes módon ez az összefonódás a részecskék megkülönböztethetetlensége miatt létezik – anélkül hogy kapcsolat lenne közöttük. Most a legújabb kísérletükben a fizikusok még egy lépéssel tovább mentek és demonstrálták, hogy az azonos részecskék közötti összefonódás felhasználásának a kvantum technológiában is lehetnek felhasználási területei.
A fizikusok magyarázata szerint az egymástól függetlenül előkészített azonos részecskék összefonásához, a részecskéknek térben fizikailag közel kell lenniük egymáshoz – a részecskék hullámfüggvényeinek térben legalább részben egybe kell esniük. Ha ez a térbeli egybeesés nem áll fenn, akkor nem is lehet összefonódás, hogyha részleges egybeesés áll fenn, akkor az egybeeső térrészen folytatott mérésekkel feltételes összefonódás váltható ki egy bizonyos valószínűséggel.
Csak, abban az esetben áll fenn teljes összefonódás, amikor a hullámfüggvények teljesen egybeesnek – viszont az összefonódás mértéke függ a mérésektől és a hullámfüggvények alakjától is. A kvantum bitekkel exponenciálisan nagyobbak az algoritmusok. (Grover algoritmus) A Shor-algoritmus (kvantumszámítógépekre tervezett) kvantumalgoritmus, amellyel polinomiális időben végezhető el az egész számok prímfelbontása. Az algoritmust feltalálójáról, Peter Shor amerikai matematikusról nevezték el. Ha N jelöli a számot, amelynek prímtényezőit keressük (tehát a bemenet mérete log N), akkor az algoritmus O((log N)3) időben fut le. Ez azt jelzi, hogy a prímfelbontási probléma a BQP bonyolultsági osztályba tartozik. A Shor-algoritmus hatékonysága a kvantum Fourier-transzformáció és az ismételt négyzetre emelésekkel végrehajtott moduláris hatványozás hatékonyságán alapszik. Gyors szimulációra, hatékony titkosításra egy RSA prímszámfaktorizációval kivállóan alkalmas, két prím szám szorzata.

Java programozás egyszerűen 13B osztály



Bármilyen bonyolult programot veszünk szemügyre és bontunk részekre, a végén ugyanaz a 4 építőelem marad:

szekvencia (utasítások egymás utáni sorozatának végrehajtása)
változóhasználat
elágazások
ciklusok
Vezérlés
Algoritmusok
Lássunk akkor néhány alap algoritmust:

Megszámlálás
Összegzés
Eldöntés
Kiválasztás
Keresés
Minimum/maximum keresés
Rendezés
Kiválogatás
Szétválogatás
Metszet
Unió

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 interface 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;
 }
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. A catch ágakból több is lehet, de egy try blokk végén csak egy finally lehet.

A könnyebb try-catch blokkot, úgy lehet, hogy a "|" (Alt Gr + W billentyű) megnyomva teszünk két kivételt egy helyre.

try {
    utasítás(ok)
} catch (kivételtípus | kivételtípus) {
    utasítás(ok)
}
Feltétel nélküli ugróutasítások
A Java nem támogatja a goto utasítást, mivel ennek használata pongyola kó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:

Változó típusa     Leírás Példa
byte   8 bites előjeles egész      byte largestByte = 127;
short 16 bites előjeles egész     short largestShort = 32767;
int     32 bites előjeles egész     int largestInteger = 2147483647;
long   64 bites előjeles egész     long largestLong = 9223372036854775807L;
float  32 bites egyszeres lebegőpontosságú (IEEE 754 szabvány)      float largestFloat = 3.4028235E38f; //(E38 = {\displaystyle 10^{38}} {\displaystyle 10^{38}})
double        64 bites kétszeres lebegőpontosságú (IEEE 754 szabvány)       float largestFloat = 1.7976931348623157E308; //(E308 = {\displaystyle 10^{308}} {\displaystyle 10^{308}})
char   16 bites Unicode-karakter        char aChar = 'S';
boolean      logikai érték (igaz / hamis)       boolean aBoolean = true;
A tömb és a karakterlánc nem egyszerű típusok, hanem objektumok. A long és float változók inicializálásánál külön meg kell adni, hogy a begépelt szám melyik típusba tartozik: az egész szám literál végére L vagy f betűt írunk. A forráskódba begépelt, ilyen megjelölés nélküli egész számokat integer-ként, a lebegőpontos számokat pedig double-ként kezeli.

Karakterek
A Java a 16 bites Unicode kódolást (az UTF-16-ot) használja. Ez tartalmazza a szabványos ASCII-karaktereket, de ugyanakkor tartalmazza más nyelvek karakterkészletét is (pl: görög, cirill, kínai, arab stb.). A Java programok mindezeket a karakterkészleteket képesek használni, habár a legtöbb szerkesztőprogram csak a hagyományos ASCII karakterkészletet támogatja.

Interfészek és osztályok
A Java egyik fontos tulajdonsága, hogy lehetővé teszi interfészek létrehozását, amiket az osztályok megvalósíthatnak. Példa egy interfészre:

 public interface Torolheto {
    public void torol();
 }
Ez az interfész csak annyit határoz meg, hogy minden, ami törölhető, biztosan rendelkezik torol() eljárással. Ennek a fogalomnak több haszna is van, mint például:

 public class Fred implements Torolheto {
     @Override
     public void torol() {
         //Itt kötelező megvalósítani a torol() eljárást
     }
 }
Más osztályban lehetséges a következő:

 public void torolMindent(Torolheto[] lista) {
      for (int i = 0; i < lista.length; i++)
           lista[i].torol();
 }
Léteznek továbbá jelölő interfészek, amelyeknek az implementálása nem jár metódus megvalósításával, csak egy bizonyos tulajdonsággal ruházzák fel az őket implementáló osztályt. Ilyen pl. a Serializable interfész. Az interfészek között is fennállhat öröklődési reláció. Ilyenkor ugyanúgy minden átöröklődik, ahogyan az osztályok esetében.

Egy absztraktként megjelölt osztálynak lehet nem megvalósított (csak deklarált, de nem implementált) metódusa. Példa:

 // Kötelező kulcsszó az abstract, ekkor az osztálynak lehet absztrakt metódusa, de nem lehet példánya
 public abstract class Elvont {
     private int adat;
     public Elvont(int adat) {
         this.adat = adat;
     }
     public int getAdat() {
         return adat;
     }
     // Kötelező kulcsszó az abstract, ekkor nem szabad implementálni a metódust
     public abstract void manipulal();
 }
Ennek értelmében az interfész egy olyan osztály, amely teljesen absztrakt, mert nem lehet megvalósított metódusa. Egy absztrakt osztálynak illetve egy interfésznek nem létezhetnek példányai, mert akkor futásidőben nem lenne adott a konkrét viselkedése (a hívott metódus törzse). Egy kivétel azonban mégis létezik, a névtelen osztály. Ez az absztrakt osztály (típus) egyszeri példányosítása, az absztrakt részének a példányosítás helyén történő kötelező megvalósításával. Példa:

 ...
 Torolheto obj = new Torolheto() {
     @Override
     public void torol() {
         //Itt kötelező megvalósítani a torol() eljárást
     }
 };
 ...
 obj.torol(); // Ez itt így már érvényes
 ...
Ha egy osztály implementál egy vagy több interfészt, akkor az az(ok) által előírt (deklarált) minden metódust kötelezően meg kell valósítania (implementálnia kell), kivéve, ha az illető osztály absztrakt. Ekkor a megörökölt, de nem implementált metódusok az osztály meg nem valósított részét képezik. Példa:

 public abstract class TorolhetoElvont extends Elvont implements Torolheto {
     // A következő kikommentezett rész mind megöröklődik
     /*
     private int adat;
     public Elvont(int adat) {
         this.adat = adat;
     }
     public int getAdat() {
         return adat;
     }
     // Kötelező kulcsszó az abstract, ekkor nem szabad implementálni a metódust
     public abstract void manipulal();
     public abstract void torol();
     */

     // Célszerű létrehozni konstruktort, amely lehetővé teszi a megörökölt adat inicializálását
     public TorolhetoElvont(int adat) {
         super(adat);
     }
 }
Lehetséges az öröklési lánc megszakítása; azaz egy osztály mondhatja magáról, hogy végleges. Ekkor belőle nem lehet örököltetni. Példa:

 public final class Vegleges {
    ...
 }
Ki- és bemenet
A következő kódrészlet bemutatja egy karakter beolvasását a felhasználótól, majd ennek kiíratását:

 public static void main(String[] args) throws java.io.IOException {
    char a;
    System.out.println("Üdvözlöm! Kérem írjon be egy betűt.");
    a = (char) System.in.read();
    System.out.println("A beütött betű: " + a);
 }
Objektumorientált programozás megvalósítása
A származtatott osztály megadása extends segítségével:

 public class Alaposztaly {
    protected int i;
    public void eljaras(){
       i++;
    }
 }

 public class Szarmaztatott extends Alaposztaly {
    //eljaras felulirasa
    @Override
    public void eljaras() {
        i+=2;
    }
 }
A származtatáskor az alaposztály minden elemét átvette a származtatott osztály, de az eljaras() metódusát felüldefiniáltuk.

Alaposztály konstruktor meghívása a super segítségével

 public class Szarmaztatott extends Alaposztaly {
    private int masikValtozo;
    //Konstruktor
    public Szarmaztatott(int i){
        //Alaposztaly konstruktoranak atadjuk a parametert
        super(i);
        masikValtozo = i;
    }
 }

Alap algoritmusok, avagy mindenki tud programozni
A programozással sokszor az a baj – főleg ha kötelező tantárgy és nem szeretjük – hogy gondolkodni kell. Igaz, mondhatnám ezt a matematikára, fizikára is, de egyik tantárgy sem annyira szerteágazó a helyes megoldások tekintetében, mint a programozás. Itt ugyanazt a problémát sokféleképp meg lehet oldani, és minden megoldás helyes. Mégis, a megoldások között az árnyalatnyi különbségek azok, amelyek eldöntik azt, hogy helyes-e a megoldás, vagy sem.

Bármilyen bonyolult programot veszünk szemügyre és bontunk részekre, a végén ugyanaz a 4 építőelem marad:

szekvencia (utasítások egymás utáni sorozatának végrehajtása)
változóhasználat
elágazások
ciklusok
A sorrend nem véletlen, ebben a sorrendben kell ezeket megtanulni használni, mert ezek egymásra épülő darabok a programozásnak nevezett kirakó játékban. Ha nem az építőelemeit nézzük a programoknak, akkor is találhatunk olyan sablonokat, olyan már tanult megoldásokat, amelyek újra és újra előfordulnak a programjainkban. Ezeket a sablonokat, kész megoldásokat nevezzük programozási tételeknek.

Ezek valójában betanulható kész algoritmusok, melyek egy adott problémára kész megoldást adnak. Nem mindig fordulnak elő tiszta formában, vagyis néha apró változtatásokra szükség van, hogy ezeket az algoritmusokat egy adott feladathoz igazítsuk, de ha ezeket ismerjük és biztosan használjuk, akkor sokféle programozási feladatot meg tudunk oldani.

Ezek az alap algoritmusok tömbökhöz kapcsolódnak, vagyis sok egyforma adattal végeznek valamit. Megkeresik egy tömbből a legnagyobb értéket, sorba rendezik a számokat, eldöntik, hogy benne van-e egy adott érték a tömbben, megadják két halmaz metszetét, stb. Lássunk akkor néhány alap algoritmust:

Megszámlálás
Összegzés
Eldöntés
Kiválasztás
Keresés
Minimum/maximum keresés
Rendezés
Kiválogatás
Szétválogatás
Metszet
Unió
Ezen algoritmusok mindegyikére igaz, hogy ciklusokhoz kapcsolódnak, hiszen ha tömbökkel dolgozunk, akkor mindenképpen ciklusra van szükség, hogy az elemeket egyenként megvizsgálhassuk, összehasonlíthassuk, stb. Ezek az algoritmusok kicsit leegyszerűsítik a programozást, hiszen ezekkel a megtanulható kész receptekkel sokféle feladatot megoldhatunk. A probléma az, hogy a feladatban fel kell ismerni, hogy valójában mit is akarunk eredményként megkapni, és az melyik algoritmusnak felel meg. Ha ez megvan, onnantól szinte csak gépelési feladattá sikerült egyszerűsíteni a programozási feladatot.

Az alap algoritmusok valamennyi fajtájához létezik pszeudokód, olyan általános leírás, amely programozási nyelvtől független. Ráadásul, mivel 3 fajta ciklus létezik, ezért alapból szerteágazó megoldásokat adhatunk ugyanarra a feladatra. Az alap algoritmusokat nagyon sok helyen ugyanazzal a megoldási formával adják meg, és biztos vagyok benne, hogy több tanár csak így fogadja el megoldásként. Én azt vallom, hogy bármilyen jó megoldás elfogadható, a lényeg, hogy a diák alkalmazni tudja azt, amit tanult. Léteznek lecsupaszított, hatékony és egyszerű megoldások, de sokszor én sem azt alkalmazom, mert nem írunk olyan szintű programokat, hogy ennyire optimalizált és gyors algoritmusra lenne szükség. Aki esetleg az alap algoritmusaimban hibát talál, mondván, hogy ő ezt nem így tanulta, az nem feltétlenül hiba, egyszerűen más a megoldás. Az példáknál sok helyen kész ténynek veszem azt, hogy rendelkezésre áll az a tömb a megfelelő adatokkal, amelyekkel dolgozni kell. Ezeknek a tömböknek a feltöltésével, ellenőrzésével nem foglalkozok. Vegyük akkor sorra ezeket az algoritmusokat:

Megszámlálás
Kezdjük valami egyszerűvel. Az alapfeladat az, hogy számoljuk meg, hogy egy adott tömbben hány darab adott tulajdonságú elem van. Ez jelentheti azt is, hogy nincs ilyen tulajdonságú elem a tömbben, akkor a darabszám nyilván 0. Ennél a feladatnál minden esetben végig kell menni a tömbön, hiszen minden elemről meg kell állapítanom, hogy rendelkezik-e a tulajdonsággal, vagy sem. Mivel megszámolunk, ezért valahol tárolnom kell, hogy éppen hol járok a számolásban, hány olyat találtam, ami megfelelt a feltételemnek. Ehhez szükség van egy úgynevezett gyűjtőváltozóra. Az adott algoritmus egy darabszámot ad eredményül minden esetben, ami a [0;méret] intervallumban lesz, vagyis lehet, hogy egy elem sem felel meg a feltételnek, de az is előfordulhat, hogy mindegyik. Nézzünk pár példát, hogy mikor alkalmazható ez az algoritmus:

Hány 180 cm-nél magasabb diák jár az osztályba?
Hány napon esett az eső tavaly?
Hány férfi tanár tanít az iskolában?
Láthatjuk, hogy minden esetben egy darabszámra kíváncsi minden kérdés. Lássuk akkor azt az algoritmust, ami ezekre a kérdésekre választ ad. A példában az első kérdésre keressük a választ.

int szamlalo = 0;

for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i] > 180 )
  {
    szamlalo = szamlalo + 1;
  }
}

System.out.println("Az osztalyba "+szamlalo+" db 180 cm-nel "
                   "magasabb diak jar.");
Nézzük akkor részletesebben, mi történik.

Deklarálunk egy gyűjtőváltozót, ahol a feltételnek megfelelő elemek darabszámát tároljuk.
A gyűjtőváltozót 0 kezdőértékre állítjuk be. Ez egyébként általános szabály, hogy minden gyűjtőváltozót legkésőbb a használata előtt (a ciklus előtt) nullázni kell!
Indítunk egy ciklust, ami a tömb összes elemén végigmegy.
Megvizsgáljuk, hogy az adott elem megfelel-e a feltételnek
Ha megfelel, a számlálót eggyel megnöveljük.
A ciklus után kiírjuk az eredményt.
A kiemelt sorban a változó növelését kicserélhetjük a már tanult inkrementáló operátorra. Azért, mert lusták vagyunk, és nem akarunk sokat gépelni 🙂

szamlalo = szamlalo + 1;
helyett
szamlalo++;
A többi feladatnál gyakorlatilag ugyanezt kell begépelni, igazából az egyetlen dolog ami változik az maga a feltétel, ami alapján megszámolunk.

Összegzés
Az összegzés tétele kísértetiesen hasonlít a megszámlálásra. Egyetlen különbség van csak, a gyűjtőváltozó növelése. A feladatok is hasonlóak, de az összegzés csak számszerű adatokra vonatkozik. Néhány példa ilyen kérdésekre:

Mennyi a tömbben található páros számok összege?
Mennyi a negatív számok összege?
Mennyi a páratlan számok átlaga?
Lássuk akkor mondjuk az első megoldását:

int osszeg = 0;

for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i] % 2 == 0 )
  {
    osszeg = osszeg + tomb[i];
  }
}

System.out.println("A tombben levo paros szamok osszege: "+osszeg);
Láthatjuk, hogy az összegzés algoritmusa szinte ugyanaz, mint a megszámlálásé.

Deklarálunk egy gyűjtőváltozót, ahol a feltételnek megfelelő elemek összegét tároljuk.
A gyűjtőváltozót 0 kezdőértékre állítjuk be.
Indítunk egy ciklust, ami a tömb összes elemén végigmegy.
Megvizsgáljuk, hogy az adott elem megfelel-e a feltételnek
Ha megfelel, az összeghez hozzáadjuk az aktuális elemet.
A ciklus után kiírjuk az eredményt.
A lényegi különbséget kiemeltem. Látható, hogy szinte ugyanaz. Ettől függetlenül ne keverjük a két algoritmust, mert teljesen más a feladatuk!

A kiemelt sorban a változó növelését kicserélhetjük már tanult összeadással kombinált értékadó operátorra. Ismét csak azért, mert lusták vagyunk, és nem akarunk sokat gépelni.

osszeg = osszeg + tomb[i];
helyett
osszeg += tomb[i];
A harmadik feladat kilóg a többi közül, ez nem csak tiszta összegzés. Itt egyszerre kell az előzőleg ismertetett megszámlálást és összegzést elvégezni. Szükségünk van a páratlan számok összegére, valamint a darabszámára is az átlagoláshoz:

int osszeg = 0;
int db = 0;

for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i] % 2 != 0 )
  {
    osszeg = osszeg + tomb[i];
    db++;
  }
}
double atlag = (double)osszeg/db;
System.out.println("A tomb paratlan szamainak atlaga: "+atlag );
Láthatjuk, hogy a ciklussal ugyanúgy végigmegyünk az egész tömbön. Ha találunk egy megfelelő számot, akkor hozzáadjuk az összeghez és növeljük a darabszámot is. Az átlag már csak egy osztás. De nem egyszerű osztás. Az osszeg és db változók egész típusok. Mi lenne az eredménye annak, ha mondjuk az összeg 11 a darabszám pedig 5? 11/5 = ?

Ne felejtsd el! Ha két egész számot osztunk egymással, az egész osztás! Az eredmény nem a sokszor várt 2,2 lenne, hanem 2,0. Az osztás akkor nem egész osztás, ha legalább az egyik műveletben részt vevő szám nem egész. Előzőleg már mutattam egy trükköt, írhatnánk így is:

osszeg/(db+0.0)
Helyette azonban legyünk elegánsabbak, használjunk típuskényszerítést, amit a véletlen számok témakörben már bemutattam:

(double)osszeg/db
A típuskényszerítés során az összeg változóból kiolvasott értéket lebegőpontos számmá alakítjuk, majd osztjuk egy egésszel. Ennek eredménye már megfelelő: 2,2.

Fontos, hogy ez a típuskényszerítés nem az eredeti összegváltozóban tárolt értéket változtatja meg, nincs értékadás! Nem is változtathatja meg az összegváltozó tartalmát, mivel annak típusa egész. Csak a változóból felhasznált értéket alakítja át a megadott típusra.

Eldöntés
Ennél a feladattípusnál azt vizsgáljuk, hogy egy tömbben található-e egy bizonyos tulajdonságú elem. Nem érdekel, hogy hány ilyen elem van, csak az a fontos, hogy van-e benne ilyen. Itt logikai eredményt kapunk, vagyis a válasz igaz vagy hamis lehet. Lássunk pár példát olyan kérdésekre, amelyekre ezzel az algoritmussal kaphatunk választ:

Van-e az osztályban lány?
Van-e az osztályban 190 cm-nél magasabb diák?
Volt-e melegebb 38 foknál tavaly nyáron?
Van-e 30 évnél fiatalabb tanár az iskolában?
Ezekhez a feladatokhoz természetesen szükség van tömbökre, melyek azokat az adatokat tárolják, amelyek között keressük azt a bizonyos tulajdonságú elemet, azok közül is a legelsőt. Emlékezz, nem érdekel hány ilyen elem van, csak az számít, hogy van-e ilyen, és ez nyilván a legelső megtalált elem lesz. Az első példához szükség van egy tömbre, amely a tanulók nemét tárolja, akár logikai típusként (lány – true, fiú – false). A második esetben kell egy tömb, ami az osztályba járó diákok magasságait tartalmazza, a harmadikban egy tömb, ami a nyári napok maximum hőmérsékletét tartalmazza, a negyediknél egy tömb, amiben benne van az iskolában tanító tanárok életkora. Maradjunk a második példánál, és vegyük úgy, hogy rendelkezésre áll egy „tomb” nevű tömb, ami az osztályba járó diákok magasságait rögzíti.

int i = 0;

while( i < tomb.length && tomb[i] <= 190 )
{
  i++;
}

if( i < tomb.length )
{
  System.out.println("Van az osztalyban 190 cm-nel magasabb diak.");
}
Na de mit is csinál ez pontosan?

Először deklarálunk egy ciklusváltozót, amit arra fogunk használni, hogy indexelhessük (hivatkozhassunk) az egyes tömbelemekre, jelen esetben a diákok magassági adataira. Ez a sorszám természetesen 0-tól indul, mert a Java nyelvben a tömbök indexei 0 számmal kezdődnek.
Aztán indítunk egy ciklust, melynek az a feladata, hogy végigmehessünk egyenként a tömb elemein. A ciklus feje viszont egy összetett feltételt tartalmaz. Ennek első fele azt vizsgálja, hogy végigértünk-e már a tömbön – vagyis, hogy az index kisebb-e, mint a tömb mérete. Ha az i egyenlő lenne a tömbmérettel, az már azt jelentené, hogy túljutottunk az utolsó elemen, tehát a ciklus megáll. Mivel a tömbök indexe 0-val kezdődik, ebből következik, hogy az utolsó elem indexe tömbméret-1. A feltétel másik része a tulajdonság vizsgálat, amelyre csak akkor kerül sor, ha még nem értünk a tömb végére. Itt azt vizsgáljuk, hogy a tomb[i] – vagyis az aktuális diák magassága – NEM RENDELKEZIK a keresett tulajdonsággal. Ez fura, mert nem pont ennek a fordítottját keressük? De igen, ez az algoritmus lényege. Addig kell keresni, amíg NEM találtuk meg, amit kerestünk, hiszen ha megvan, akkor megállhatunk. Ha ez a két feltétel egyszerre igaz (nem értünk még a tömb végére ÉS nem rendelkezik az aktuális diák a keresett tulajdonsággal), akkor lépünk be a ciklusba, ami semmi mást nem csinál, csak lépteti a számlálót, vagyis jöhet a következő vizsgálandó diák. Az algoritmus nagyon fontos része az, hogy a ciklus két feltételének sorrendje kötött! Először kell azt vizsgálni, hogy nem értünk-e a végére, és ha nem, csak akkor szabad megvizsgálni, hogy az aktuális elem nem rendelkezik-e a keresett tulajdonsággal. Hiszen ha már végignéztük a tömböt, akkor már nincs mit vizsgálni.
A ciklus befejeződése után már csak értelmeznünk kell a kapott eredményt. Az i változó értéke az, ami a megoldást tartalmazza. Ha találtunk olyan diákot, aki rendelkezett a keresett tulajdonsággal, akkor a ciklus idő előtt megállt, vagyis az i értéke kisebb, mint a tömb mérete. Ha egyetlen diák sem volt 190 cm-nél magasabb, akkor a ciklus azért állt meg, mert az i változó már nem kisebb a tömb méreténél (vagyis egyenlő), tehát nem találtunk olyat, aki a feltételnek megfelelt volna
Természetesen a többi feladatra is hasonló a megoldás, lássuk mondjuk a negyedik feladatot:

int i = 0;

while( i < tomb.length && tomb[i] >= 30 )
{
  i++;
}

if( i < tomb.length )
{
  System.out.println("Van az iskolaban 30 evnel fiatalabb tanar.");
}
Nagyon fontos eleme tehát az eldöntésnek, hogy második részfeltételnek azt adjuk meg, hogy az aktuális elem a keresett tulajdonsággal nem rendelkezik! Mivel a feltételek többsége relációt tartalmaz, itt a relációk ellentettjét kell használni!

// 30 évnél fiatalabbat keresünk
while( ... && tomb[i] < 30 )
helyett

// 30 évnél nem fiatalabb kell a feltételbe
while( ... && tomb[i] >= 30 )
Írhatnám úgy is, hogy valóban tagadom az eredeti állítást:

// 30 évnél nem fiatalabb
while( ... && !(tomb[i] < 30)
Az eredeti állítás valódi tagadását tomb[i] < 30 -> !( tomb[i] < 30) én inkább a reláció ellentettjével helyettesíteném, mivel ott egy reláció marad csak, így csak egy műveletet kell végrehajtani. Valódi tagadás esetén ott marad az eredeti reláció, majd a reláció logikai értékének tagadása is kell, ami két művelet, de ezekből az egyik megspórolható. Itt visszautalnék a relációs operátoroknál arra a táblázatra, ahol ismertettem a relációk tagadásait. Ne feledd: a kisebb tagadása nem a nagyobb!

Mi az, amit még észrevehettél ebben az algoritmusban? Ezzel vissza is kanyarodtunk egy nagyon fontos részhez, a logikai kifejezéseknél. Láthatod, hogy a while ciklus fejében egy összetett kifejezés szerepel. Ennek az első fele az, hogy elértünk-e már a tömb végéig, a második pedig az, hogy az aktuális elem nem rendelkezik a keresett tulajdonsággal. Látható, hogy a második feltétel kész tényként veszi azt, hogy ott csak valódi elemet vizsgálhatok. Egy tömbnek, ha emlékszel, fix tulajdonsága a mérete. Vagyis csak akkora indexet lehet használni, amilyen elem még szerepel a tömbben. Egy 10 elemű tömbben nem lehet pl a tomb[12] elemre hivatkozni, mert ilyen elem nem létezik.

Ez futási hibát eredményez. Na de itt hol ellenőrzöm azt, hogy nehogy túl nagy indexet használjak? Az első feltételben. Ez egy logikai rövidzár. Ha az első részfeltétel, hogy az i számláló kisebb, mint a tömbméret (vagyis az i lehet a tömb egy indexe) teljesül, csak akkor vizsgálja meg a második részfeltételt, az adott elem keresett tulajdonságának hiányát. Ha az i elérte a tömbméretet (vagyis nem kisebb), akkor a logikai rövidzár miatt a második feltételt logikai és esetén már meg sem vizsgálja. Nem fog olyan elemet vizsgálni, ami nem létezik! Nagyon fontos eleme az algoritmusnak az, hogy a két részfeltételnek pontosan ilyen sorrendben kell szerepelnie, mert így oldja meg a rövidzár azt az ellenőrzést is, hogy csak valódi emelet vizsgáljunk meg, és ne kapjunk futási hibát.

Kiválasztás
Ezzel az algoritmussal azt adhatjuk meg, hogy egy adott elem pontosan hol szerepel a tömbben. Ez természetesen az adott elem indexét jelenti, amellyel a tömbben hivatkozunk rá. Ez az algoritmus feltételezi azt, hogy az elem tényleg benne van a tömbben, ez ugyanis nem keverendő össze a keresés algoritmusával, amit következőként fogok ismertetni. Lássunk erre egy pár kérdést.

Válasszuk ki a tömbből az 50-es számot (nem index, hanem érték!).
Hányadik a sorban az a diák, akinek a magassága 190 cm-nél nagyobb.
Lássuk az első példa megoldását:

int i = 0;

while( tomb[i] != 50 )
{
  i++;
}

System.out.println("Az 50-es szám indexe: "+i);
Ha megnézzük, ez egy lecsupaszított eldöntés algoritmusnak tűnik, amikor ciklusban működési feltételként furcsa módon azt adjuk meg, hogy a ciklus addig menjen, amíg az aktuális elem NEM rendelkezik a tulajdonsággal. Vagyis addig megyünk, amíg meg nem találjuk. Hiányzik viszont a eldöntéses algoritmus összetett feltételének első része, ami azt vizsgálja, hogy túlszaladtunk-e a tömb végén. Itt erre nincs is szükség, mivel abból indultunk ki, hogy a kiválasztandó elem biztosan benne van a tömbben.

Kiválasztásnál lehetséges, hogy több elem is megfelel a feltételnek, ez az algoritmus a legelső olyan elemet választja ki, akire a feltételünk igaz lesz. Viszonylag könnyen megoldható az is, hogy a legutolsó olyat válasszuk ki, ez csak a ciklus haladási irányától és az i kezdőértékétől függ.

Keresés
A keresés algoritmusa gyakorlatilag szinte ugyanaz, mint az eldöntés algoritmusa, mindössze az i változó ciklus utáni értelmezésénél van különbség. Azért szerepeljen itt újra az algoritmus egy konkrét példával. A feladatban azt keressük, hogy van-e 190 cm-nél magasabb diák és hogy ő hányadik a tömbben:

int i = 0;

while( i < tomb.length && tomb[i] <= 190 )
{
  i++;
}

if( i < tomb.length )
{
  System.out.println("A 190 cm-nél magasabb diák helye: "+i);
}
else
{
  System.out.println("Nincs ilyen diák.");
}
Látható az, hogy ez biztonságosabb algoritmus az előzőnél. Ez akkor is használható, ha nem tudjuk, hogy egyáltalán létezik-e ilyen diák, ezért eggyel több a feltétel is, mert azt is figyelni kell, hogy a tömb végén ne szaladjunk túl. A ciklus után pedig az i értékéből határozhatjuk meg a keresett elem helyét, ha ugyanis az i kisebb a tömb méreténél (vagyis nem szaladtunk túl rajta, tehát benne van), akkor az i már a keresett elem helyét jelenti. Ha nem így van, akkor nincs benne. Itt is logikai rövidzárat használunk, tehát a két feltétel sorrendje nagyon fontos. Az első feltétel biztosítja azt, hogy a második nem lehet hibás. Keresési algoritmusból többféle létezik, ez csak a legegyszerűbb lineáris keresés algoritmusa.

Minimum/maximum keresés
Nagyon gyakori feladat az, amikor egy tömbből meg kell határozni a legkisebb/legnagyobb elemet. Ez nem csak egyszerű típusoknál használható, akár objektumok (több tulajdonsággal rendelkező adattárolók) közül is kiválaszthatjuk a legkisebb/legnagyobb tulajdonságút. Technikailag az, hogy a minimum vagy maximum értéket keressük csak egy reláció megfordítását jelenti. Nézzük akkor hogy néz ki ez az algoritmus. Keressük meg a tomb nevű tömbben a legnagyobb értéket!

int max = 0;

for( int i = 1; i < tomb.length; i++ )
{
  if( tomb[i] > tomb[max] ) max = i;
}

System.out.println("A tombben levo legnagyobb szam: "+tomb[max]);
Nézzük akkor részenként a programot. Először is deklarálunk egy max nevű változót, amelynek azonnal adunk is egy 0 kezdőértéket. Fontos, hogy ez nem egy változó nullázás, mint a megszámlálás vagy összegzés algoritmusánál tettük. Ennek a 0 értéknek jelentése van. Azt jelenti, hogy a legnagyobb elem a legelső, vagyis a 0 indexű! A max változóban tehát nem a legnagyobb elem értékét, hanem a helyét (indexét) tároljuk. Mindjárt világos lesz, miért. Azt mondjuk tehát, hogy a legnagyobb elem a 0. helyen van, vagyis ez az első elem. Ez teljesen egyértelmű, hiszen amíg meg nem vizsgálom a tömböt, az első elem tekinthető a legnagyobbnak, mivel a többit még nem ismerem. A ciklust, amivel végigmegyek az egész tömbön természetesen a 2. elemtől indul (indexe 1) és a tömbméret-1 indexű az utolsó, amit vizsgálnom kell. Ha az éppen vizsgált elem (tomb[i]) nagyobb, mint az eddigi legnagyobb tomb[max], akkor az új maximum helye megváltozik az aktuálisra -> max = i.

Fura lehet, hogy miért a legnagyobb elem helyét tároljuk és nem az értékét. Mi van akkor, ha ez a kérdés: Hányadik elem a legnagyobb a tömbben? Ha a maximumban a legnagyobb elem értékét tárolnánk, azzal a helyét nem tudjuk megmondani, csak az értékét. A helyéből viszont meghatározhatjuk mindkettőt.

Ha a legkisebb elemet keressük, akkor a kiemelt sorban fordul meg a relációs jel, és máris a legkisebb elemet kapjuk meg a végén. Természetesen minimum keresésnél célszerű a max változó nevét min-re változtatni, hogy utaljon arra, mit is keresek.

Ne felejtsd el tehát, minimum és maximum keresésnél a helyet tároló változó kezdőértéke 0, mivel az első elem lesz először a legkisebb vagy legnagyobb, ha elkezdem a keresést.

Más oka is van annak, hogy a helyet és nem az értéket tároljuk. Tételezzük fel, hogy csak negatív számokat tartalmaz a tömbünk és a legnagyobbat keressük közülük. Létrehozunk egy max változót, azt nullázzuk, de ez most a legnagyobb elem értékét jelentené. Találhatunk negatív számok között olyat, ami nagyobb, mint 0? Könnyen belátható, hogy csak pozitív számokat tartalmaz a tömb és a legkisebbet keressük, akkor sem állja meg a helyét a nullázás. A nulla nem pozitív, tehát nem találsz ettől kisebb pozitív számot, vagyis a tömb egyik eleme sem kerülhet a helyére.

Rendezés
Nagyon gyakori a programjainkban az a típusfeladat, hogy sorba kell rendezni egy tömb elemeit. A Java nyelvben az egyszerű típusokra, és a Stringekre is létezik beépített rendezés, mégis ritkán használjuk őket, mert javarészt objektumokkal fogunk dolgozni, azokra pedig ezek nem működnek. Rendezési algoritmusból nagyon sokféle létezik, vannak egyszerűbb, de lassabb típusok, és vannak nagyon hatékonyak. A valódi helyzet az, hogy a rendezendő adatoktól mennyiségétől is függ az, hogy melyik rendezési algoritmus a hatékony, de középiskolai szinten mindegy hogyan rendezünk, csak oldjuk meg a feladatot. Két rendezési algoritmust fogok megmutatni, amelyeket használni/tanítani szoktam, ha ezeket tudod, akkor bármilyen típusú tömböt rendezni tudsz.

A rendezések legtöbbje összehasonlításokon és cseréken alapul. Összehasonlítunk két elemet, és ha azok sorrendje nem megfelelő, akkor megcseréljük őket. Az algoritmusok sokszor abban különböznek, hogy melyik kettőt hasonlítjuk össze és utána melyik kettőt, stb. Létezik olyan speciális rendezés is, amelyik nem használ összehasonlításokat és cseréket, de ezek csak bizonyos esetekben használhatóak, akkor viszont hihetetlen gyorsak.

A rendezés esetén már összetettebb módon kell bejárni a tömböt, amelynek elemeit rendezni szeretnénk. Itt is igaz az, hogy nem csak egyszerű típusú értékeket tartalmazó tömböket lehet rendezni, az elemek lehetnek összetett objektumok is, melyek többféle típusú értéket tartalmazhatnak.

A tömbök kezelésekor, és az alap algoritmusok használatakor minden esetben ciklusokat használunk arra, hogy bejárjuk az adott tömböt, és annak értékeihez egymás után hozzáférjünk. Abban vannak csak különbségek, hogy ténylegesen bejárjuk-e az egészet, vagy sem, esetleg a bejárás iránya változik. Itt azonban másról lesz szó. Itt találkozunk először az egymásba ágyazott ciklusokkal.

A rendezések, melyeket jellemzően használunk minden esetben azt az elvet követik, hogy a tömb bizonyos elemeit hasonlítják össze, hogy azok egymáshoz képest a kívánt sorrendben helyezkednek-e el. Ha ez nem így van, akkor ezt a két elemet meg kell cserélni. Itt azonban nem csak az egymás melletti szomszédokat vizsgáljuk,

Egyszerű cserés rendezés
Ezt a rendezést több néven is megtalálhatjuk az alap algoritmusok között, én ezt a nevet használom. Az elv, ami alapján dolgozik az az, hogy minden elemet összehasonlít az összes mögötte lévővel, és ha azok sorrendje nem megfelelő, akkor megcseréli őket. Két egymásba ágyazott ciklust igényel, ezeket tradicionálisan i és j ciklusváltozókkal használjuk. Lássuk akkor magát az algoritmust, ahol feltételezzük, hogy van egy tomb nevű tömbünk, amely véletlen számokkal van feltöltve és a meret nevű változóban a tömb méretét találjuk meg:

1
2
3
4
5
6
7
8
9
10
11
12
13
int csere;
for( int i = 0; i < tomb.length-1; i++ )
{
    for( int j = i+1; j < tomb.length; j++ )
    {
        if( tomb[i] > tomb[j] )
        {
            csere = tomb[i];
            tomb[i] = tomb[j];
            tomb[j] = csere;
        }
    }
}
A ciklus úgy dolgozik, hogy a j változó mindig az i utáni helyet jelöl, mivel a j kezdőértéke minden esetben i+1-ről indul. Éppen ezért az i soha nem mehet el a tömb végéig, mert akkor az utolsó elem utáni összehasonlítást is elvégezne, ami mindenképp hibás.

Tehát még egyszer a lényeg: az i van elöl, a j van hátul!

Lássuk a kiemelt részek magyarázatát:

1 – Kell egy csere változó az esetleges cserékhez segédváltozónak. A változó típusának meg kell egyezni a tömb elemeinek típusával, hiszen azon közül fogjuk az egyiket eltárolni benne.
2 – Az i változó soha nem mehet el a tömb végéig, vagyis i < tomb.length-1;
4 – A j mindig az i után áll, ezért int j = i+1;
6 – Mindig összehasonlítjuk az elöl és hátul lévő elemeket, és ha ezek sorrendje nem megfelelő…
8-10 – Akkor jön az elemek cseréje.
A rendezés iránya csak és kizárólag a 6. sorban megadott relációs jeltől függ. Ha az elöl lévő nagyobb és akkor cserélünk, akkor a nagyok kerülnek hátra, vagyis növekvő rendezést alkalmazunk. Ha az elől lévő kisebb és akkor cserélünk, akkor a kicsik kerülnek hátra, és csökkenő rendezést írunk. A fenti példa tehát növekvő rendezést valósít meg, mivel az első esetnek megfelelő a relációs jel.

A csökkenő rendezés ehhez képest tehát minimális változtatással jár:

1
2
3
4
5
6
7
8
9
10
11
12
13
int csere;
for( int i = 0; i < tomb.length-1; i++ )
{
    for( int j = i+1; j < tomb.length; j++ )
    {
        if( tomb[i] < tomb[j] )
        {
            csere = tomb[i];
            tomb[i] = tomb[j];
            tomb[j] = csere;
        }
    }
}
Minimum/maximum kiválasztásos rendezés
Ez a rendezés az előző továbbfejlesztett változata. Az előző algoritmus úgy dolgozik, hogy minden esetben megcseréli a két elemet, ha az aktuális két elem helyzete nem megfelelő. Ez azt eredményezi, hogy több csere is lesz, mire a legkisebb a tömb elejére kerül növekvő rendezés esetén. De ha már egyszer növekvő rendezést akarunk megvalósítani, akkor nem lenne jobb, hogy ha először megkeresnénk a legkisebb elemet, majd azt helyeznénk a lista elejére, majd utána megkeresnék a második legkisebbet, azt beraknánk az első után, és így tovább? Jóval kevesebb cserével járna, mint az előző. Természetesen megoldható, az előző rendezési algoritmusa tökéletesen kombinálható a már tanult minimum/maximumkeresési algoritmusokkal. Lássuk akkor hogyan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int csere;
int min;
for( int i = 0; i < tomb.length-1; i++ )
{
    min = i;
    for( int j = i+1; j < tomb.length; j++ )
    {
        if( tomb[j] < tomb[min] )
        {
            min = j;
        }
    }
    if( min != i )
    {
        csere = tomb[i];
        tomb[i] = tomb[min];
        tomb[min] = csere;
    }
}
Lássuk akkor a magyarázatot:

1 – Kell egy csere változó az esetleges cserékhez segédváltozónak. A változó típusának meg kell egyezni a tömb elemeinek típusával, hiszen azon közül fogjuk az egyiket eltárolni benne.
2 – Kell egy változó, ahol a legkisebb elem helyét tároljuk (mint a minimumkiválasztásnál), de ennek itt még nem adunk kezdőértéket.
5 – Mielőtt elkezdjük a belső ciklust, ami az elöl lévő elem mögöttiek indexén megy végig, az elöl lévő elemet feltételezzük a legkisebbnek. Itt a belső ciklus futását gyakorlatilag egy minimum kiválasztásnak írtuk meg. A tomb[i] az első elem, ezért ennek a helyét feltételezzük a legkisebb elem helyének,
8 – majd, ha az eddigi minimumtól valamelyik mögötte lévő (tomb[j]) tőle kisebb,
10 – akkor a hátul lévő elem helyét (j) jegyezzük meg, mint aktuális legkisebbet.
13 – Ha a belső ciklussal végeztünk, akkor a min változóban benne van a hátul lévő elemek közül a legkisebbnek a helye. Ha ez a hely nem egyenlő az elöl lévővel (vagyis nem önmaga a legkisebb), akkor találtunk az elöl lévő (i) elem mögött tőle kisebbet, melynek helyet a min változóban tároljuk.
15-17 – Ebben az esetben a két elemet (i és min helyen lévőket) megcseréljük.
Ezt az algoritmust inkább csak érdekességképp mutattam meg, érettségire tökéletesen elég, ha az egyszerű cserés rendezést megtanulod, mert csak az a követelmény, hogy rendezni tudj, teljesen mindegy, melyik algoritmussal. Nyilván a legegyszerűbbet célszerű megtanulni, a hatékonyság nem követelmény.

Kiválogatás
Szintén az alap algoritmusok közé tartozik az a feladattípus, amikor bizonyos tulajdonságnak, vagy tulajdonságoknak megfelelő elemeket kell egy tömbből egy másik tömbbe kiválogatni. Tegyük fel, van egy egészeket tartalmazó tömbünk, melyet a [-9;9] intervallumból töltöttünk fel. Hogyan oldhatjuk meg, hogy ebből a tömbből egy másik tömbbe kigyűjtjük a negatív számokat? Minden esetben létre kell hozni egy másik tömböt, amibe a megfelelő elemeket másoljuk. De mekkora legyen ez a tömb? Ez az ami alapvetően meghatározza, hogy milyen megoldási módot alkalmazunk. Kétféle esetet különböztetünk meg:

Létrehozunk egy eredeti tömbnek megfelelő méretű tömböt, azt feltételezve, hogy akár az összes elem lehet negatív, így mindet át kell másolni. Ha azonban nem minden elem negatív, akkor az új tömbben maradnak üres helyek, ahova nem rakunk át semmit. Így nyilván kell tartanunk, hogy hány elemet másoltunk át az új tömbbe, és mennyi maradt “üresen” a végén.
Megoldhatjuk úgy is, hogy először megszámoljuk, hogy hány elem felel meg a feltételnek, ami alapján a kiválogatást el akarjuk végezni, és az új tömböt pontosan akkorának állítjuk be. Így a megoldás végén az új tömbben csak azok az elemek lesznek benne, amelyeket mi helyeztünk el benne.
A két megoldásból a második nyilván picivel több munkával jár, mert kapcsolódik hozzá egy megszámlálás is, viszont utána már nem kell attól tartanunk, hogy az eredmény tömbben olyan elem is előfordul, ami nem felel meg a kiválogatás feltételének.

Lássuk akkor a két különböző megoldást. Mindkét esetben feltételezzük, hogy van egy tomb nevű tömbünk, amely véletlen számokkal van feltöltve. Az új tömbbe a páratlan számokat szeretnénk kiválogatni:

1
2
3
4
5
6
7
8
9
10
11
int[] paratlan = new int[tomb.length];

int db = 0;
for( int i = 0; i < tomb.length; i++ )
{
    if( tomb[i] % 2 != 0 )
    {
        paratlan[db] = tomb[i];
        db++;
    }
}
Lássuk akkor a kiemelt sorok magyarázatát:

1 – Létrehozok egy ugyanakkora tömböt, mint az eredeti, lehetőséget adva arra, hogy akár minden elemet kiválogathassak.
3 – Létrehozok egy db nevű változót, ami jelen esetben az első üres helyet fogja tárolni, ahova a következő kiválogatott elemet elhelyezhetem, a kiválogatás végeztével pedig tárolni fogja, hogy az új tömbbe hány elem került bele.
4 – Végigmegyek az eredeti tömbön,
6 – és ha az eredeti tömbben páratlan számot találunk,
8 – akkor az új tömbben a első üres helyre (db) elhelyezem az elemet,
9 – majd megnövelem a db-ot, hogy az esetleges következő átmásolt elem ne írja felül az előzőt.
Látható, hogy nem olyan bonyolult algoritmusról van szó, a kulcs az, hogy mindig tárolom egy változóban, hogy hol van az új tömbben az első üres hely, mert csak oda rakhatok bele a kiválogatás során elemeket. A gond csak annyi, hogy ha van egy 1000 méretű tömböm, amibe 3 elemet kellene csak kiválogatni, akkor is a memóriában foglalja az 1000 elemnyi helyet a 3 kedvéért.

Lássuk akkor a másik megoldást:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int db = 0;
for( int i = 0; i < tomb.length; i++ )
{
    if( tomb[i] % 2 != 0 )
    {
        db++;
    }
}

int[] paratlan = new int[db];

db = 0;
for( int i = 0; i < tomb.length; i++ )
{
    if( tomb[i] % 2 != 0 )
    {
        paratlan[db] = tomb[i];
        db++;
    }
}
Ha jól megnézed nem sokkal bonyolultabb, picit többet kell gépelni, és ki kellett egészíteni a megszámlálás alap algoritmusával:

1-8 – Megszámoljuk, hány elemet kell majd kiválogatni az új tömbbe.
10 – Létrehozunk egy ugyanakkora tömböt.
12-20 – Ez pedig pontosan az első megoldás.
Az egész algoritmus kulcs momentuma a db változó használata! Ennek több szerepe is van. Először a kiválogatandó elemek darabszámát gyűjtjük bele, utána a következő üres helyet jelöli az új tömbben, végül a kiválogatás végeztével az új tömb méretét jelenti, bár ezt a tömbből úgyis ki lehet nyerni a .length változóból.

Szétválogatás
A szétválogatás algoritmusa a kiválogatás kibővítése. Az alapfeladat az, hogy az eredeti tömb minden elemét két külön tömbbe kell elhelyezni. Feltételezzük, hogy minden elem bekerül valamelyik új tömbbe, vagyis nem hagyunk ki semmit sem. A kiválogatásnál ennek a feladatnak a felét gyakorlatilag megoldottuk. Amit egy kiválogatásnál kiválogatunk, az itt az egyik tömb elemeinek felelne meg. Az összes többi elemet a másik tömbbe pakoljuk. Így már nem is tűnik olyan nehéznek, igaz?

A szétválogatás feltétele minden esetben gyakorlatilag egyetlen feltétel.

Válogassuk szét a tömb elemeit 5-től nagyobb és nem nagyobb elemekre. (emlékezz a relációs jelekre!)
Válogassuk szét a tömb elemeit 5-tel osztható és nem osztható elemekre.
Válogassuk szét az elemeket egyjegyű és nem egyjegyű számokra
Válogassuk szét a tömb elemeit páros és páratlan elemekre.
Ha megfigyelted, a feladatok jó része úgy fogalmazza meg a feltételt, hogy szétválogatjuk valamilyen és NEM valamilyen elemekre. Egy feltétel és annak az ellentettje minden elemet le kell hogy fedjen. Ezért szétválogatás, nem maradhat ki egyetlen elem sem. És az utolsó esetben? Amelyik szám nem páros, az páratlan, tehát ez is lefed minden számot.

A szétválogatásnál is ugyanaz a dilemma lesz először, mint amit a kiválogatásnál írtam:

Nem foglalkozok az új tömbök méreteivel, a legrosszabb esetből indulok ki, hogy minden elemet be kell tennem az egyik tömbbe, a másik pedig üres marad. Ebben az esetben mindkét új tömb méretének az eredeti tömb méretét állítom be, így a két új tömb kétszer annyi helyet foglal majd, amennyire valóban szükség lenne.
Előre megszámolom, hány elem felel meg a szétválogatás feltételének, ezután beállítom a kívánt tömbméreteket, majd utána válogatom szét az elemeket. Ez a legtakarékosabb megoldás, mert mindkét tömb mérete pontosan akkora lesz, amekkorára szükségem lesz. Ha emlékszel, a kiválogatásnál itt egy megszámlálással bővítettem ki az alap megoldást.
Lássuk akkor az első esetet. Tételezzük fel, hogy van egy adott méretű tömböm, feltöltve elemekkel. Válogassuk szét az elemeket páros és páratlan elemeket tartalmazó tömbökbe. Vedd észre, hogy ez valójában egyetlen feltétel. Ami nem páros, az páratlan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int[] paros = new int[tomb.length];
int[] paratlan = new int[tomb.length];

int dbparos = 0;
int dbparatlan = 0;

for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i] % 2 == 0 )
  {
    paros[dbparos] = tomb[i];
    dbparos++;
  }
  else
  {
    paratlan[dbparatlan] = tomb[i];
    dbparatlan++;
  }
}
Ha a kiválogatás algoritmusát megértetted, akkor ezzel se lesz probléma. Nem véletlenül csak két részt emeltem ki. A kiválogatásnál kellett egy számláló, amelyben nyilvántartottam, hogy hány elemet válogattam ki, ami egyúttal azt is jelezte, hogy hol van az új tömbben a következő üres hely. Itt is hasonló a helyzet, csak itt két tömb esetén két külön változóban kell tárolni, hogy hány elem van az egyikben-másikban, és ezáltal melyik tömbben hol van a következő üres hely, ahova az elemeket pakolhatom. A belső feltétel sem sokat változott, ha a feltételnek megfelel az elem, akkor berakom az egyik tömbbe, ha nem, akkor mindenképpen (else) a másik tömbbe kell tennem. Emlékszel: minden elem bekerül valamelyik tömbbe, ha nem az elsőbe, akkor a másodikba, nem hagyhatok ki semmit sem.

Ne felejtsd el, a két új tömb mérete nagyobb, mint amennyi tényleges elemet tartalmaznak. Az algoritmus után a két darabszámot tároló változó az, amiből megtudhatod, hogy mekkora valójában a tömb, amit kezelned kell. Nem a paros.length lesz az a határ, ameddig be kell járnod egy ciklussal, hanem a dbparos változó.

Lássuk akkor a második megoldást. Emlékeztetőül: megszámolom hány elemet kell majd beraknom az egyik tömbbe, akkor meglesznek a megfelelő tömbméretek.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int parosdb = 0;

for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i] % 2 == 0 )
  {
    parosdb++;
  }
}

int[] paros = new int[parosdb];
int[] paratlan = new int[tomb.length-parosdb];

parosdb = 0;
paratlandb = 0;

for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i] % 2 == 0 )
  {
    paros[parosdb] = tomb[i];
    parosdb++;
  }
  else
  {
    paratlan[paratlandb] = tomb[i];
    paratlandb++;
  }
}
Lássuk akkor a kiemelt részeket:

1-9 – Megszámolom, hány elem felel meg a szétválogatás feltételének.
11-12 – Létrehozom a két megfelelő méretű tömböt. A páratlan tömb méretét úgy kapom meg, hogy a tömb elemeinek darabszámából kivonom a párosok darabszámát, így megvan a páratlanok száma.
14-31 – Lenullázom a két számlálót, és elvégzem a szétválogatást az első megoldásnak megfelelően, csak itt már biztos lehetek benne, hogy mindkét új tömböt teljesen feltöltöm.
Az előzőhöz képest ez nyilván bonyolultabb megoldás. Cserébe takarékosabb, másrészt nem kell külön tárolni, hogy a tömbök valójában meddig vannak feltöltve, mivel a méretük pontosan megfelel a szétválogatott elemek darabszámának.

És ha nem mindent válogatok szét?
Ez az algoritmus csak abban az esetben használható, ha minden elemet szét kell válogatni. Ez mondjuk a szétválogatás elvéből is következik, mivel nem hagyhatunk ki elemeket, különben nem szétválogatásnak neveznénk. Mégis a példa kedvéért tételezzük fel, hogy egy tömbből szeretnénk a pozitív és negatív számokat két másik tömbbe átpakolni. Ebben az esetben már figyelnünk kell arra, hogy mi a helyzet a nullákkal. Természetesen ezt is meg kell oldani, csak itt az elemek megszámolásánál figyelembe kell venni, hogy kihagyunk elemeket, valamint a tényleges válogatásnál is ügyelni kell rájuk. Szándékosan kerültem a szétválogatás szót, mert ez valójában a kihagyott elemek miatt nem az lesz. Lássunk akkor erre egy példát.

Válogassuk ki egy tömb elemei közül a pozitív és negatív számokat. (Észrevetted? Kiválogatás)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int pozitivdb = 0;
int negativdb = 0;

for( int i = 0; i < tomb.length; i++ )
{
  if( tomb[i] > 0 )
  {
    pozitivdb++;
  }
  else if( tomb[i] < 0 )
  {
    negativdb++;
  }
}
int[] pozitiv = new int[pozitivdb];
int[] negativ = new int[negativdb];

pozitivdb = 0;
negativdb = 0;

for( int i = 0; i < tomb.length; i++ ) { if( tomb[i] > 0 )
  {
    pozitiv[pozitivdb] = tomb[i];
    pozitivdb++;
  }
  else if( tomb[i] < 0 )
  {
    negativ[negativdb] = tomb[i];
    negativdb++;
  }
}
1-13 – Egy ciklusban megszámolom a pozitív és negatív számokat.
15-16 – Létrehozom nekik a megfelelő méretű tömböket.
És kiválogatom őket egyetlen ciklusban.
Ez gyakorlatilag két kiválogatás egy ciklusba pakolva, a két feltételnek (pozitív vagy negatív) lényegében semmi köze egymáshoz, a számlálóik is teljesen függetlenek, mert nem tudom, hogy a két feltétel lefedi-e az összes eredeti elemet vagy sem. Ha a két feltétel minden elemet besorol valahova, akkor szétválogatás, egyébként két egymástól független kiválogatásról beszélünk.

Metszet
A metszet algoritmus egy kis magyarázatot igényel. Az alap algoritmusok metszetképzése nem egyezik meg a halmazelméletben tanult metszettel. A halmazt elemek sokaságának tekintjük, ahol az elemeknek nincs sorrendje, és minden elem csak egyszer szerepelhet a halmazban. Ez a tömböknél nyilvánvalóan nem áll fenn. A halmazoknál metszetként azon elemek halmazát vesszük, amelyek mindkét halmazban megtalálhatóak.

Tömbök esetén ez azt jelenti, hogy az egyik tömbből vesszük azokat az elemeket, amelyek benne vannak a másikban. Ezzel az algoritmussal csak az a bajom, hogy nem mindegy, hogy melyik tömb oldaláról kezdjük ez a dolgot. Lássuk a következő példát, hogy miről is van szó.

{2,2,3,4}
{3,5,2,6,6}
Ha az első tömb elemeiből hagyjuk meg azokat, amelyek benne vannak a másodikban, akkor ezt az eredményt kapjuk:

{2,2,3}
Ha a második tömb elemeiből hagyjuk meg azokat, amelyek benne vannak az elsőben, akkor ezt az eredményt kapjuk:

{3,2}
Nyilván látszik mi a gond. Ez pedig abból fakad, hogy egy elem többször is lehet egy tömb eleme. A sorszámozás miatt ezek egyértelműen megkülönböztethetőek. A halmazban viszont az elemek nem sorszámozottak, ezért két azonos értékű elemet nem különböztethetnénk meg. Az algoritmus nem foglalkozik ezzel a problémával, és nekünk sem kell. Más kérdés, hogy meg tudnánk oldani azt is, hogy minden elem egyszer szerepeljen csak a metszetben, később ezt is megmutatom.

Mint már fent említettem, az algoritmus annyiból áll, hogy az vesszük az egyik tömb elemei közül azokat, amelyek benne vannak a másikban. Nézzük meg jobban, mi is ez? Kiválogatjuk az egyik tömb elemei közül azokat, amelyek megfelelnek annak a feltételnek, hogy benne vannak a másik tömbben. Kiválogatás, amiben van egy eldöntés. A metszetképzés tehát két tanult algoritmus kombinációja.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int[] t1 = new int[] {2,2,3,4};
int[] t2 = new int[] {3,5,2,6,6};
int[] metszet = new int[t1.length];

int j;
int db = 0;
for( int i = 0; i < t1.length; i++ )
{
  j = 0;
  while( j < t2.length && t2[j] != t1[i] )
  {
    j++;
  }
  if( j < t2.length )
  {
    metszet[db] = t2[j];
    db++;
  }
}
Lássuk a kiemelt részek magyarázatát:

3 – A metszet tömb mérete akkora, mint az első tömb mérete, hiszen lehet, hogy annak minden eleme megtalálható a másikban. Természetesen a kiválogatáshoz hasonlóan itt is ügyelni kell arra, hogy nem feltétlen kerül minden elem a metszet tömbbe, ezért majd a db változó fogja tárolni a metszet tömb valódi elemeinek számát.
7 – Ebben a sorban elkezdünk egy kiválogatást, vagyis elindulunk az első tömbön azt keresve, hogy ezek közül melyiket kell majd átrakni a metszetbe.
9-14 – Ez gyakorlatilag az eldöntés algoritmusa, addig haladunk a második tömb elemein, és addig megyünk, amíg nem találunk egyezést a második tömb eleme és az első tömb éppen aktuális eleme között. Ezt az algoritmust most nem magyaráznám el újra, de ami a lényeg: ha az elemet megtaláltuk, akkor visszatérünk a kiválogatáshoz
16-17 – Ha találtunk olyan első tömbbeli elemet, ami megfelelt a feltételünknek (benne van a másodikban is), akkor berakjuk a metszet tömbbe, és növeljük a számlálóját. Ez a kiválogatás algoritmus vége.
Metszet egyedi elemekkel
Mi van akkor, ha valóban csak annyit szeretnénk megtudni, hogy mik azok a számok, melyek mindkét tömbben megtalálhatóak? Ha valami többször szerepel a tömbben, attól mint szám csak egyszer szerepel. Ez nem alap algoritmus, hanem az eddig tanultakat kell alkalmazni. Akár teljesen eltérő megoldásokat is adhatunk:

A két tömb közül az elsőből létrehozok egy olyan tömböt, ami az eredetiben szerepelő számokat csak egyszer tartalmazza. Majd ha erről az oldalról metszetet képzek, akkor a metszetben is minden elem csak egyszer fog szerepelni.
Az első tömbből csak akkor teszek be egy számot a metszetbe, ha benne van a másodikban, és még nincs benne a metszetben. Vagyis a kiválogatáson belül két eldöntésre van szükségem, melyeknek egyszerre kell teljesülnie. Azzal még finomíthatom, hogy ha a második tömbben nincs benne, akkor felesleges a metszetben ellenőrizni, mert akkor oda semmiképpen nem kerülhetett be.
Lássuk az első megoldást:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int[] t1 = new int[] { 2, 2, 3, 4 };
int[] t2 = new int[] { 3, 5, 2, 6, 6 };
int[] metszet = new int[t1.length];

int[] egyedi = new int[t1.length];
int dbe = 0;

int j;
for( int i = 0; i < t1.length; i++ )
{
  j = 0;
  while( j < dbe && t1[i] != egyedi[j] )
  {
    j++;
  }
  if( j == dbe )
  {
    egyedi[dbe] = t1[i];
    dbe++;
  }
}

int db = 0;
for( int i = 0; i < dbe; i++ )
{
  j = 0;
  while(j < t2.length && t2[j] != egyedi[i])
  {
    j++;
  }
  if( j < t2.length )
  {
    metszet[db] = t2[j];
    db++;
  }
}
Mit is csinálunk pontosan?

5 – Létrehozom azt a tömböt, ahova kiválogatom az első tömb számait. Ennek mérete az eredetivel megegyező, mert lehet, hogy egyik szám sem szerepel többször, akkor mindet át kell pakolni.
6 – Létrehozok egy számlálót, hogy nyilvántartsam, valójában hány elem lesz az egyedi tömbben.
8-21 – Kiválogatom az egyedi számokat. (kiválogatásban egy eldöntés) Fontos, hogy akkor rakom bele az egyedi tömbbe a számot, ha az eldöntés hamis eredményt ad, vagyis nincs benne: if( j == dbe )
23-36 – Ez pedig a metszetképzés algoritmusa, de az egyedi tömb és a második között. A 24-es sorban fontos a feltétel, hogy az egyedi tömbnek nem az összes elemét kell vizsgálni, hanem csak addig, ameddig valóban vannak benne elemek. Ezt a saját dbe számlálója tárolja.
A két részfeladat (egyedi tömb előállítása, majd metszetképzés) ugyanarról a tőről fakad, hiszen mindkét esetben egy elemről akarom eldönteni, hogy benne van-e egy tömbben. A különbség csak az, hogy egyedi elemek válogatásakor akkor rakom bele, ha nincs még benne, metszetképzésnél pedig akkor rakom bele, ha benne van.

Nézzük a másik megoldást, amikor a két eldöntést teszek a kiválogatásba:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int[] t1 = new int[] { 2, 2, 3, 4 };
int[] t2 = new int[] { 3, 5, 2, 6, 6 };
int[] metszet = new int[t1.length];

int j;
int jm;
int db = 0;
for( int i = 0; i < t1.length; i++ )
{
  j = 0;
  while( j < t2.length && t2[j] != t1[i] )
  {
    j++;
  }
  if( j < t2.length )
  {
    jm = 0;
    while( jm < db && metszet[jm] != t1[i] )
    {
      jm++;
    }
    if( jm == db )
    {
      metszet[db] = t1[i];
      db++;
    }
  }
}
Lássuk a lényegi részeket:

10-14 – Eldöntjük, hogy az első tömb eleme benne van-e a másodikban.
15 – Ha igen, akkor
15-27 – Eldöntjük, hogy benne van-e a metszetben.
22 – Csak akkor tesszük be a metszetbe, ha még nincs benne. Ha már egyszer betettünk ilyen számot, akkor nem tesszük bele még egyszer.
Ez a megoldás talán rövidebb és egyszerűbb is, mint a másik, és minden esetben egyedi elemeket tartalmazó metszet tömböt kapunk.

Természetesen ez a metszetképzés algoritmus több hasonló feladatnál is használható, hiszen ha metszetet tudunk képezni, akkor olyan kérdésekre is választ kaphatunk ennek segítségével, hogy van-e két tömbnek azonos eleme, hány közös eleme van két tömbnek, stb.

Komplex feladat
Lássunk egy komplexebb feladatot. Adott egy 10 elemű tömb melyet véletlen számokkal töltöttünk fel a [-9;9] intervallumból. Írjuk ki növekvő sorrendben a tömbben szereplő páros számokat.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 *
 * @author http://webotlet.hu
 */
package webotlet_alapalg_komplex;

public class Webotlet_alapalg_komplex
{

    public static void main(String[] args)
    {
        int[] tomb = new int[10];

        for (int i = 0; i < tomb.length; i++)
        {
            tomb[i] = (int) (Math.random() * 19) - 9;
        }

        for (int i = 0; i < tomb.length; i++)
        {
            System.out.print(tomb[i] + " ");
        }

        System.out.println();

        int db = 0;
        for (int i = 0; i < tomb.length; i++)
        {
            if (tomb[i] % 2 == 0)
            {
                db++;
            }
        }

        int[] paros = new int[db];

        db = 0;
        for (int i = 0; i < tomb.length; i++)
        {
            if (tomb[i] % 2 == 0)
            {
                paros[db] = tomb[i];
                db++;
            }
        }

        int csere;
        for (int i = 0; i < db - 1; i++)
        {
            for (int j = i + 1; j < db; j++)
            {
                if (paros[i] > paros[j])
                {
                    csere = paros[i];
                    paros[i] = paros[j];
                    paros[j] = csere;
                }
            }
        }

        for (int i = 0; i < db; i++)
        {
            System.out.print(paros[i] + " ");
        }
        
        System.out.println();
    }
}
Ez egy tökéletes feladat arra, hogy az eddig tanultakat összefoglalja. Sok ismerős részletet láthatunk benne, de lássuk akkor részenként:

12-17 – Adott méretű tömb létrehozása, majd feltöltése véletlen számokkal.
19-22 – A kisorsolt tömb kiíratása.
24 – Sordobás a sorsolt tömb kiíratása után, hogy ne folyjon egybe majd a rendezett tömb kiíratásával.
26-33 – A kiválogatáshoz megszámoljuk, hány elemet kell majd átrakni az új tömbbe.
35 – Létrehozzuk az új tömböt.
37-45 – Kiválogatjuki (átmásoljuk) a páros számokat az új tömbbe.
47-59 – Rendezzük az új tömböt.
61-64 – Kiírjuk a kiválogatott és rendezett új tömböt.
66 – Egy bónusz sordobás a végére, hogy ha bővíteném a programot, akkor az új kiíratás új sorban kezdődjön.
Adott tehát egy elsőre bonyolultnak tűnő feladat, amit szétbontottuk olyan részekre, melyeket már külön-külön meg tudunk oldani. Ezeket a kész megoldásokat (tömb feltöltés, kiíratás, megszámlálás, kiválogatás, rendezés, stb) megfelelő sorrendben hibátlanul összerakjuk, és kész a feladat teljes megoldása. Ugye így jobban belegondolva nem is olyan nehéz? Feltéve hogy az eddigi tananyagokat már készségszinten alkalmazni tudod. Sokszor az a legnehezebb feladat, hogy felismerjük azt, hogy az aktuális feladat milyen kisebb alkotóelemekre bontható, melyekre már kész megoldásaink vannak. Ha ez a részekre bontás megy, akkor gyakorlatilag sokszor gépelési feladattá tudjuk egyszerűsíteni a feladatok nagy részének megoldását.

A feladat: a program beker egesz szamokat, mig -1-et nem olvas, es kiirja a -1 elotti szamok atlagat! Az eredmenyt ket tizedesjegyre kerekiti. (A bemenet mindig egesz szam.)

Scanner sc = new Scanner(System.in);
double n = 0;
double bekert;
double atlag;
System.out.println(“Kérem a számokat (-1-re kilép):”);
bekert = sc.nextInt();

while (bekert != -1) {
n += bekert;
bekert = sc.nextInt();
}
if (bekert == -1) {
// atlag = na ez az a resz, ahol nem jovok ra a helyes kepletre, noha tudom hogy kell atlagot szamolni
System.out.print(“Az összeg: “+atlag+”.”);
} else {
System. out.print(“Az összeg: 0.0”);
}
}
}


Először leírom a megoldást:
int szam;
int osszeg = 0;
int db = 0;
Scanner sc = new Scanner(System.in);

do
{
szam = sc.nextInt();
if( szam != -1 )
{
osszeg += szam;
db++;
}
}
while( szam != -1);

if( db == 0 )
{
System.out.println(“Nem adtal meg szamot.”);
}
else
{
System.out.println((double)osszeg/db);
}

A lényeg, hogy ha a ciklusban nem -1 számot olvasol be, akkor gyűjteni kell a bekért számokat egy összegváltozóba, a darabszámukat meg egy darabba. Ebből tudsz összeget számolni, ha szükséges.

Az összegváltozód megvan, de nem számolod a beolvasásokat, ezért nem tudsz átlagot számolni.


Logikai műveletek, logikai kifejezések, avagy a feltételvizsgálatok alapjai
Logikai kifejezésnek nevezzük azt, amelynek az eredménye igaz vagy hamis (true – false) lehet. Ezek valójában eldöntendő kérdések:

a szám páros?
a szám osztható 3-mal?
a szám kisebb, mint 100?
A logikai kifejezések előfutáraként az operátorokat bemutató leckében szót ejtettem a különféle logikai operátorokről:

Negálás: Egy logikai értéket az ellenkezőjére állít (ami true volt, false lesz, és fordítva)
Logikai és: Akkor igaz az összetett kifejezés, ha minden részfeltétele igaz (ha bármelyik hamis, hamis az egész)
Logikai vagy: Akkor hamis az összetett kifejezés, ha minden részfeltétele hamis (ha bármelyik igaz, igaz az egész)
Kizáró vagy: Akkor igaz összetett kifejezés, ha a részfeltételek közül csak egy igaz (ha több részfeltétel igaz, vagy mind hamis, akkor hamis az egész)
Jöjjön akkor pár kapcsolódó példa:

Adj meg olyan logikai kifejezést, mely igaz értéket ad pozitív páros számok esetén:

szám % 2 == 0 && szám > 0
Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám nagyobb, mint 10 és páratlan:

szám > 10 && szám % 2 != 0
Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám a 10 és 30 között van:

szám > 10 && szám < 30
Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám osztható 3-mal vagy 7-tel:

szám % 3 == 0 || szám % 7 == 0
Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám nem negatív vagy páros:

szám >= 0 || szám % 2 == 0
Adj meg olyan logikai kifejezést, mely a négyes vagy ötös dolgozatjegyre ad igaz értéket:

jegy == 4 || jegy == 5

Rövidzár kiértékelés

A logikai kifejezésekkel kapcsolatban fontos megemlíteni az úgynevezett rövidzár kiértékelést. Ez a szabály a logikai és, valamint a logikai vagy esetén érvényes. A rövidzár kiértékelés picit másképp működik a két esetben, de teljesen logikus lesz, ha megérted.
Logikai és műveletnél emlékszel arra, hogy csak akkor igaz az összetett kifejezés, ha minden részfeltétele igaz. Ez azt jelenti, hogy ha akár csak egyetlen hamisat találunk, akkor a többit felesleges is megvizsgálni. Nézzünk rá egy példát. Ha egy olyan feltételt szeretnénk megadni, amely olyan számokat fogad el, melyek 3-mal és 4-gyel is oszthatók, akkor a következőt tesszük:

szám % 3 == 0 && szám % 4 == 0
Mit is csinál a Java pontosan? A logikai és két oldalát a balról jobbra elv alapján vizsgálja meg. Ha a szám osztható 3-mal, akkor meg kell nézni a jobb oldali feltételt is, mert csak akkor igaz az egész, ha minden része igaz. És ha a bal oldal hamis? Akkor már nem is lehet soha igaz, és – ez a legfontosabb! – a jobb oldali feltételt már meg sem vizsgálja! Nagyon fontos ezzel tisztában lenni, mert sokszor használatos.

Ugyanez az elv létezik a logikai vagy esetén is, csak pont fordítva. Egy olyan feltételt szeretnénk megadni, amely olyan számokat fogad el, melyek 3-mal vagy 4-gyel is oszthatók (esetleg mindkettővel), akkor a következőt tesszük:

szám % 3 == 0 || szám % 4 == 0
Akkor egy kis deja vu. Mit is csinál a Java pontosan? A logikai vagy két oldalát a balról jobbra elv alapján vizsgálja meg. Ha a szám nem osztható 3-mal, akkor meg kell nézni a jobb oldali feltételt is, mert csak akkor igaz az ha van benne legalább egy igaz. És ha a bal oldal igaz? Akkor már igaz az egész kifejezés, és a jobb oldali feltételt már meg sem vizsgálja! Olyan ez, mint amikor amikor a kitűnő vagy bukott diákokat vizsgáljuk. Akkor kitűnő, ha minden jegye 5-ös, és akkor bukott, ha van 1-es érdemjegye. Feltételekkel ez hogy nézne ki? Egy későbbi példa kedvéért legyen csak két tantárgya:

jegy1 == 5 && jegy2 == 5
Ha már az első jegye nem 5-ös, akkor a többit meg se nézi a program, hiszen felesleges. Hasonlóan a bukott diák:

jegy1 == 1 || jegy2 == 1
Ha már az első jegye 1-es, akkor a többit meg se nézi a program, mert már igaz az összetett feltétel, ha van 1-es jegye, akkor megbukott.

Negálás
A negálás olyan terület, ahol könnyen hibázhat az ember. Ugyanazt a vizsgálatot két oldalról is meg lehet közelíteni, és mindkettő helyes. Vegyük például a már emlegetett kitűnő tanulónkat. Azt, hogy valaki kitűnő úgy definiáljuk, hogy minden jegye 5-ös. Igen ám, de azt is mondhatom, hogy nincs olyan jegye, ami nem 5-ös. Elsőre meredek lehet, a dupla tagadás amúgy kedvenc a magyar nyelvben. Lássuk akkor példával:

jegy1 == 5 && jegy2 == 5
Ez már ismerős volt, ő a kitűnő. Akkor nézzük meg így:

!(jegy1 != 5 || jegy2 != 5)
Mit is írtam itt pontosan? A vagy miatt, ha legalább az egyik jegye nem 5-ös, akkor igaz a zárójeles kifejezés – ami azt jelenti, hogy nem kítűnő – majd ezt az egészet negálva hamisat kapok, mégiscsak kitűnő. Nincs olyan jegye, ami nem 5-ös. A vaggyal összekötött részfeltételek együtt csak akkor hamisak, ha mindegyik hamis, vagyis minden jegye NEM 5-ös. Ha minden jegye NEM 5-ös és ezt tagadom, az pedig azt jelenti, hogy minden jegye 5-ös, vagyis kitűnő. Nem egyszerű példa, ez az egész a matematikai logikában és halmazelméletben ismert De Morgan azonosságokra vezethető vissza. Ami a lényeg az egészből: ugyanarra kétféle megoldás is létezik, melyek teljes mértékben megegyeznek, neked csak az a feladatod, hogy a számodra egyszerűbbet megtaláld. Hasonlóan immár magyarázat nélkül megmutatom két példával a bukott diák esetét is:

jegy1 == 1 || jegy2 == 1
vagy
!(jegy1 != 1 && jegy2 != 1 )
Na jó, egy kis magyarázat a második esethez. Ha egyik jegye sem 1-es, és ezt tagadom, az mit jelent? Nem azt, hogy minden jegye 1-es! Azt jelenti, hogy van legalább egyetlen olyan, ami 1-es!
Ha a kifejezésben csak ÉS vagy csak VAGY logikai kapcsolatot használsz, de egyszerre a kettőt nem, akkor általános formában ez az átalakítás a következőképp néz ki:

a logikai kapcsolatot változtasd át a másikra (és-t vagy-ra meg vagy-ot és-re)
a használt relációkat változtasd az ellenkezőjére (vigyázz, emlékezz a relációknál tanultakra!)
negáld az egész kifejezést
Na, még egy pár példa erre az átalakításra:

Írj kifejezést, ami a 3-mal és 5-tel nem osztható számokra ad igaz értéket:

szám % 3 != 0 && szám % 5 != 0
vagy
!(szám % 3 == 0 || szám % 5 == 0)
Írj kifejezést, ami csak a [10;30] intervallumba NEM tartozó számokat fogadja el:

szám < 10 || szám > 30
vagy
!(szám >= 10 && szám <= 30)
Írj kifejezést, ami csak a negatív páratlan számokat fogadja el:

szám < 0 && szám % 2 != 0
vagy
!(szám >= 0 || szám % 2 == 0)
Oké, mondhatnád, hogy itt bonyolítjuk a dolgot, hiszen a negálást, mint műveletet beletesszük egy kifejezésbe, ami egyénként nincs benne. És ha fordítva van?

!(szám % 5 != 0 || szám < 0) // ööö, ez mit csinál?
Egyszerűsítsük!

szám % 5 == 0 && szám >= 0 // 5-tel osztható nem negatív szám

Operátorok és operandusok, avagy műveleti jelek és szenvedő alanyaik
A programozási nyelvek fontos részét képezik az operátorok. Nevezzük őket műveleti jeleknek, habár nem a szó matematikai értelmében. Programozás során sokszor úgynevezett kifejezésekkel dolgozunk, amelyek valamilyen értékek és közöttük értelmezett műveletek. Megnövelünk egy számot, összeadunk két változót, hogy egy harmadiknak megkapjuk az értékét, összehasonlítunk egy változót egy számmal, hogy egyenlőek-e, stb. Operátornak magát a műveletet nevezzük, operandusnak pedig a kifejezés azon részét, amit változtatni akarunk vagy amit felhasználunk a számításhoz. Az operandus lehet egy megadott literál (egy direkt érték), változó vagy kifejezés.

a = b;
b == 2
c = a + b;
i++;
a += b * 2;
c = a == 3 ? 0 : a;
Az előző példákban pirossal emeltem ki az operátorokat, a maradékok pedig az operandusok. Igyekeztem minél több példát felsorolni, de operátor ennél sokkal több van és ezeket többféle elv mentén csoportosíthatjuk.

Csoportosíthatjuk az operátorokat annak megfelelően, hogy hány operandust kötnek össze. Ennek megfelelően megkülönböztetünk:

egyoperandusú,
kétoperandusú,
többoperandusú operátort.
Logikusabb azonban aszerint csoportosítani őket, hogy milyen jellegű műveletet hajtanak végre, bár vannak olyanok, amelyek nem sorolhatók be egyértelműen művelet alapján egy csoportba sem.

Aritmetikai operátorok
Relációs operátorok
Értékadó operátorok
Logikai operátorok
Inkrementáló (növelő) operátorok
Feltételes operátor
Bitléptető és bitenkénti operátorok (esetleg később kifejtem)
Aritmetikai operátorok
Ezek jellemzően valamilyen matematikai műveletet hajtanak végre két számértéken. Ezek az operátorok a következők:

+
*
/
%
Az első hármat nem kell nagyon megmagyarázni, ezek matematikai alapműveletek, de az utolsó kettő már érdekesebb. Változókból, mint az 5. leckében már olvashattad léteznek egész és lebegőpontos típusok. A / jel az osztás jele, azonban ez kétféleképpen működik.

Egész osztás

Amennyiben a műveletet két egész szám között hajtjuk végre, akkor egész osztásról beszélünk. Ez azt jelenti, hogy hányszor van meg az egyik szám a másikban és a maradékkal nem foglalkozunk.

int a = 10;
int b = 3;
System.out.println(a/b);
a = 12;
b = 5;
System.out.println(a/b);
Az első kiíratás 3-at, a második 2-őt fog kiírni, és nem érdekel minket a maradék.

Valós osztás

Az / operátor használatakor másfajta eredményt kapunk akkor, ha a két szám közül legalább az egyik nem egész:

int a = 10;
double d = 3.0;
System.out.println(a/d);
Az eredmény 3.3333333…
Na de mi van akkor, ha két egész számunk van, de a teljes valós eredmény érdekel minket? Az nem elég, hogy 10/3, mert az operátor csak a két szám típusa alapján tudja eldönteni, hogy egész vagy valós osztást szeretnénk. Ehhez egy kis trükköt kell alkalmazni:

System.out.println(10/3.0);
// vagy
System.out.println(10.0/3);
Lényegtelen melyiket bővítem ki lebegőpontos számmá, a lényeg, hogy legalább az egyik az legyen. De változók használata esetén ezt nem tehetem meg, mert annak semmi értelme, hogy a.0/b. Mit tehetünk ilyenkor?

int a = 10;
int b = 3;
System.out.println(a/(b+0.0));
Egyszerűen az egyik változó értékéhez hozzáadunk 0.0-t. Ettől az értéke nem változik meg, csak a típusa, tehát valós osztás lesz belőle. És minek a zárójel? Próbáld ki nélküle:

int a = 10;
int b = 3;
System.out.println(a/b+0.0);
Mi is matematikában a műveletek sorrendje? Először elvégzi az osztást, ami egész osztás lesz, annak eredménye 3. Majd ehhez hozzáad 0.0-t, ami miatt 3.0 lesz és nem 3.33333. Nagyon sokszor előfordul ez a hiba, amikor az a feladat, hogy átlagot kell számolni. Figyeljünk oda, hogy egész osztásra vagy valós osztásra van szükségünk, és ha valós osztásra van szükségünk egész számok között, akkor ne maradjon le a +0.0

Maradékos osztás

Amikor két szám osztásakor nem a hányados, hanem a maradék érdekel minket, akkor van szükségünk a % operátorra. Használni is egyszerű:

int a = 10;
int b = 3;
System.out.println(a%b);
a = 12;
b = 5;
System.out.println(a%b);
Az első kiíratás 1, a második 2 lesz. Az osztás elvégzése után ennyi a maradék. A maradékos osztást számok osztóinak keresésekor szoktuk használni. Ha egy szám például 5-tel osztva nulla maradékot ad, akkor mit tudtunk meg a számról? Hogy osztható 5-tel. Ha a szám % 3 nullával egyenlő? Akkor 3-mal osztható. Ez később még többször előfordul, emlékezzünk rá. A maradékos osztás egyébként nem csak egész számok között működik, akkor is helyes eredményt ad, ha nem egész mindkét szám. A lényeg, hogy ha az egyik szám nem egész, akkor az eredmény is a nem egész típusnak megfelelő lesz. A következő példákat érdemes kipróbálni:

10 % 3
10.0 % 3
10 % 3.0
10.0 % 3.0
10.5 % 3
10 % 3.5
10.0f % 3.0
Relációs operátorok
Az operátorok következő csoportja a relációs operátorok. Ezek a matematikában is ismeretes relációk, melyek a következők:

Reláció       Jele
kisebb         <
nagyobb     >
kisebb vagy egyenlő       <=
nagyobb vagy egyenlő    >=
egyenlő       ==
nem egyenlő         !=
A relációk első 4 fajtáját nem nagyon kell kifejteni, ellenben az == már magyarázatra szorul. Ez semmiképpen nem keverendő a = jellel. Nagyon sokszor keverik a kezdő Java programozók ezt a két operátort. Az == a két oldalon szereplő literál, változó vagy kifejezés egyenlőségét vizsgálja. Az = pedig az értékadást jelenti, amit lejjebb ismertetek. A relációk, így az egyenlőségvizsgálat is, egy logikai értéket adnak eredményül, ami igaz, vagy hamis lehet. Megjegyzésbe odaírtam a kiíratások mellé az eredményt is.

System.out.println( 5 >= 6 ); // false
System.out.println( 4 == 4 ); // true
System.out.println( 4 == 6 ); // false
System.out.println( 4 != 3 ); // true
System.out.println( 4 <= 5 ); // true
System.out.println( 6 < 3 );  // false
Értékadó operátorok
Ezek az operátorok valamilyen változónak adnak értéket. Az értékadás alapformája:

változó = kifejezés;

Az értékadás bal oldalán mindenképpen egy változónak kell szerepelnie, jobb oldalon pedig egy literál, változó, vagy olyan kifejezés (operátorok és operandusok összessége), amely egy értéket határoz meg, amit eltárolunk az értékadás bal oldalán lévő változóban. Az értékadó kifejezésben maga a bal oldali változó is szerepelhet. A kiemelt sorban egy olyan értékadás látható, ahol a kifejezésben is megtalálható a bal oldali változó, ebben a lépésben valójában a változót 1-gyel megnöveljük. Fontos, hogy a kezdőérték megadásakor (inicializáció) ilyen nem lehetséges, mert addig nem használható fel egy változó egy kifejezésben, amíg nincs kezdőértéke! Itt a kiemelt sor előtt a kezdőérték megadása megtörtént, tehát utána már növelhetem ilyen értékadással.

int a = 0;
a = a + 1;
Értékadó operátorból azonban több is van. Ezek többsége valamilyen matematikai művelettel van összekapcsolva:

+=
-=
*=
/=
%=
Ezek a típusok a már tanult aritmetikai operátorokkal kapcsolja össze a műveletet. Ilyen operátor használatakor kiértékelésre kerül a jobb oldal, és a bal oldali változó értékét az értékadáshoz kapcsolt műveletnek megfelelően végzi el. Megnöveli a változó értékét a jobb oldallal, csökkenti a változó értékét a jobb oldallal, szorozza a változó értékét a jobb oldallal, osztja a változó értékét a jobb oldallal, stb. Itt is igaz az, hogy ha a két oldalon egész értékek szerepelnek akkor a /= egész osztást jelent, ha legalább az egyik lebegőpontos érték, akkor valós osztás. Az utolsó típus a bal oldali változó eredeti értékét osztja a jobb oldallal és a maradékot tárolja el a bal oldali változó új értékének. Az utolsó esetben nem azonos típusok esetén tizedesjegy csonkolások is előfordulhatnak.

Logikai operátorok
A logikai operátorok feltételeket kapcsolnak össze. Ezek a feltételek rendszerint a már előzőleg ismertetett relációkhoz kapcsolódnak. Programozásban középiskolai szinten jellemzően 3 logikai műveletet használunk:

negálás (tagadás)
logikai és
logikai vagy
Ezek közül az első különbözik a másik kettőtől, mert ő nem feltételeket kapcsol össze, csak egy logikai kifejezés eredményét változtatja meg az ellenkezőjére.

Negálás:

A negálás (tagadás) egy logikai kifejezés értékét az ellenkezőjére változtatja. Ami igaz volt, az hamis lesz, ami hamis volt, az igaz lesz. Vagy egy eldöntendő kérdést fordíthatunk meg vele. A szám NEM páros? (tehát páratlan, mivel más lehetőség nincs)

!(szam % 2 == 0) // nem páros
!(szam > 5) // nem nagyobb, mint 5
!true // nem igaz, tehát hamis
Programozás során azonban a feltételek sokszor nem önmagukban állnak, hanem többet össze kell kapcsolni. Ezeket összetett feltételeknek nevezzük. Ha több feltételünk van, de azok együtt értendők, akkor azokat össze kell kapcsolni valamilyen logikai művelettel, erre szolgál a logikai és, valamint a logikai vagy művelet.

a szám páros és pozitív?
a szám nagyobb, mint 10 és páratlan?
a szám nagyobb, mint 10 és kisebb, mint 30?
a szám osztható 3-mal vagy 7-tel?
a szám nem negatív vagy páros?
Itt láthatóan összetett feltétellel dolgozunk, de nem mindegy, hogy azokat mi kapcsolja össze. Ráadásul a feltételek száma nem csak 2 lehet, bármennyi feltételt összekapcsolhatunk.

Logikai és:

A logikai és két vagy több feltételt kapcsol össze egyetlen összetett logikai kifejezéssé. Ha azt mondom, hogy a piros és gyors autókat szeretem, akkor szóba sem jöhetnek a kékek, zöldek, lassúak, stb, de egy tűzpiros Jaguar igen. A két feltételnek egyszerre kell teljesülnie. Definíció szerint ez a következőt jelenti: A logikai és művelettel összekötött részfeltételek akkor adnak együtt igaz értéket, ha a kifejezés minden részfeltétele igaz. Ebből következik, hogy ha egy részfeltétel hamis, akkor hamis az egész kifejezés. Természetesen több feltételt is megadhatok. Piros, gyors, Ferrari. Ettől kezdve az előző tűzpiros Jaguar is kiesett a kosárból, míg az előző két részfeltételes esetben még megfelelt volna. Minél több feltételt kötök össze, annál kevésbé kapok végeredményként igaz értéket. A logikai és művelet jele: &&

szam > 5 && szam % 2 == 0 // a szám 5-nél nagyobb ÉS páros
szám < 0 && szam % 2 != 0 // a szám negatív ÉS páratlan
szam > 10 && szam < 20    // a szám 10 ÉS 20 között van
Logikai vagy:

A logikai vagy szintén két vagy több feltételt kapcsol össze egyetlen összetett logikai kifejezéssé. Ha azt mondom, hogy a piros vagy gyors autókat szeretem, akkor ez jóval megengedőbb, mint az előző példa. Szóba jöhet a fekete Ferrari és a tűzpiros Trabant is, de természetesen a tűzpiros Ferrari is. A két feltételnek nem kell egyszerre teljesülnie ahhoz, hogy az összetett feltétel igaz legyen. A logikai vagy művelettel összekötött részfeltételek akkor adnak együtt igaz értéket, ha a kifejezés legalább egy részfeltétele igaz. Vagyis ha bármi igaz benne, akkor igaz az egész együtt is. Ha minden hamis, csak akkor hamis az egész kifejezés. A logikai és művelet jele: ||

szam > 0 || szam < 0 // a szám 0-nál nagyobb, VAGY 0-nál kisebb
szam > 10 || szam < 0 // a szám 10-nél nagyobb vagy negatív
Kizáró vagy:

Nem említettem meg egy logikai műveletet, ami még előfordulhat a programozási feladatokban, igaz ritkán. Ez a kizáró vagy. Nem győzöm eleget hangsúlyozni:

logikai vagy != kizáró vagy

Az igazi probléma a magyar nyelvvel van. Szeretem, használom, imádom, de a programozásban használatos gondolkodásmóddal sokszor szöges ellentétben áll:

Moziba menjek vagy tanuljak?
Négyes vagy ötös lesz a dolgozatom?
Fej vagy írás?
Fej vagy gyomor?
A magyar nyelvben nagyon sokszor a kizáró vagy műveletet használjuk. Vagy moziba megyek, vagy tanulok, a kettő együtt nem igazán működik. A dolgozatom vagy négyes vagy ötös lesz, de csak az egyik (jobb esetben). A kizáró vagy akkor igaz, ha pontosan egy részfeltétele igaz. Vagyis a két vagy több feltételből nem teljesülhet több egyszerre. De hogy a magyar nyelvben melyik vagy műveletet kell érteni a vagy szócskán ezt mindig a szövegkörnyezet és a feladat típusa határozza meg. Ha a két dolog egyszerre nem fordulhat elő, akkor csak a kizáró vagy jöhet szóba. De ha a barna hajú vagy szemüveges nők tetszenek, akkor a barna hajú és szemüveges is valószínűleg megfelel. A kizáró vagy művelet jele: ^

Relációk problémája
Térjünk vissza kicsit a relációkra. A tagadás, mint már említettem, megfordít valamit. Egy logikai értéket az ellenkezőjére változtat, de a relációkra is hatással van. Ez nem igazán a logikai kifejezésekhez kapcsolódó témakör, inkább logikai-szövegértési feladat, amivel kapcsolatban az a tapasztalat, hogy nagy problémák vannak ezzel a területtel.

Vegyük például a következőt: Mit jelent az, hogy nem nagyobb? A tipikus válasz: kisebb. NEM! A nem nagyobb azt jelenti, hogy kisebb vagy egyenlő. Hiszen, ha valami nem nagyobb, attól még vele egyenlő is lehet! Hasonlóan a nem kisebb jelentése: nagyobb vagy egyenlő. Lássuk akkor, hogy melyik relációnak melyik a tagadása:

Reláció       Tagadása
kisebb         nagyobb vagy egyenlő
nagyobb     kisebb vagy egyenlő
kisebb vagy egyenlő       nagyobb
nagyobb vagy egyenlő    kisebb
egyenlő       nem egyenlő
nem egyenlő         egyenlő
Inkrementáló operátorok
Létezik két speciális operátor, mely egy változó értékének 1-gyel való növelésére és csökkentésére szolgál:

változó++;
változó--;
Úgy tűnik, hogy maga a növelés vagy csökkentés a következő utasítást helyettesíti teljes egészében:

változó = változó + 1;
változó = változó - 1;
Ez a két eset valójában 4 esetet jelent, a példákból egyértelmű lesz, mire gondolok. Ezek az operátorok rendkívül sokszor fordulnak elő, és a kód átláthatóságát sem rontja akkora mértékben, hogy ez gondot jelentene. Ez a 4 eset a következőképp néz ki változó növelés/csökkentés esetén:

változó++;
++változó;
változó--;
--változó;
Az alaphelyzet tehát az, hogy a ++ operátor megnöveli eggyel a változó értékét, míg a — csökkenti azt. Ezek a példák önálló utasításként működnek, ezért zártam le ezeket ; jellel.

Látható azonban, hogy mindkét operátor szerepelhet a változó előtt és után. Amikor az operátor a változó mögött szerepel, azt postfix alaknak nevezzük, ha előtte, akkor prefix alakról beszélünk. Nyilván nem csak esztétikai jelentősége van, lássuk a gyakorlati hasznát. Az első két példában mivel ebben a sorban csak annyi szerepel, hogy a változó értékét növeljük meg, ezért nincs a két megoldás között különbség. Azonban amikor a növelés vagy csökkentés egy kiíratás vagy összetettebb kifejezés része, akkor már fontos különbség adódik:

int a = 10;
System.out.println(a++); // 10
System.out.println(a); // 11
int a = 10;
System.out.println(++a); // 11
System.out.println(a); // 11
Az első példában a növelés, mint művelet, a változó után található. Ez a gyakorlatban azt jelenti, hogy a kiíratás először felhasználja a változó eredeti értékét (10), majd ha minden művelet lezajlott ebben a sorban, utána megnöveli a változó értékét (11), vagyis a következő sorban, ahol már művelet nélkül írjuk ki, már a megnövelt értékét láthatjuk.

A második példában a növelés, mint művelet, a változó előtt található. Ez azt eredményezi, hogy ebben a sorban először megnöveli a változó értékét, majd a változó már megnövelt értékét írja ki. A következő sorban is ugyanazt az értéket írja ki, mivel itt szintén az előzőleg megnövelt értéket használhatjuk. Ugyanez igaz a csökkentésre is.

Ezek összetettebb kifejezésben is így működnek. Amennyiben a változó előtt szerepelnek az inkrementáló operátorok, akkor ezeket hajtja végre, majd a megnövelt értékekkel dolgozik tovább. Ezek a műveletek keverhetők az aritmetikai operátorokkal is, tehát ennek is van értelme: a++ + ++b

A következő példákat tessék tesztelni, ezeken keresztül világos lesz ezen operátorok működése. Számold ki a tesztelés előtt, hogy melyik sorban mit kellene látnod eredményül. Ha elsőre nem sikerült, gyakorolj még egy kicsit.

int i = 4;
int j = 3;
System.out.println( i + ++j );
System.out.println( i++ + j++ );
System.out.println( ++i + j++ );
System.out.println( i + j );
Az ilyen operátorok gyakorlati felhasználása azonban jellemzően mégis inkább a ciklusokhoz kapcsolódik. Fontos azonban megjegyeznem, hogy használatuk sok esetben inkább önálló utasításként érdemes, mert a kód átláthatóságát nagyban rontják, ami programozáskor az egyik legfontosabb szabály!

Feltételes operátor
Ezt az operátort egyelőre nem fejteném ki részletesen. Abból a szempontból egyedi, hogy egyedül ő kapcsol össze 3 operandust. Alakja:

feltétel ? ha_igaz : ha_hamis;
Ez a forma így önmagában nem is fordulhat elő, ez valamilyen kifejezés része, legyen az egy értékadás, vagy egy szöveg összefűzés. Ez annyit jelent, hogy egy általunk megadott feltétel ha teljesül, akkor a ? utáni ha_igaz eredményt kapja a kifejezés, ellenkező esetben a ha_hamis helyre írtat. A feltételvizsgálatkor majd látni fogod, hogy ez voltaképp egy egyszerű if-else szerkezet jóval tömörebb formája is lehet. Nem használható minden if-else szerkezet kiváltására, és nem használjuk gyakran. Általában egysoros utasítások rövidítésénél fordul elő, de bonyolultabb kifejezésekben szinte mindig érdemes kikerülni. Vannak olyan programfejlesztéssel foglalkozó csapatok, ahol kifejezetten tiltják a használatát átláthatósági problémák miatt.

Operátorprecedencia – végrehajtási sorrend
Operátorból ettől azért sokkal több van, de ezeket a legfontosabb megemlíteni ahhoz, hogy értsük a működésüket, és a programozást elkezdhessük. Fontos azonban megemlíteni azt, hogy az operátorok között is létezik egyfajta erősorrend, csakúgy, mint a matematikai műveletek között. Ezt hívjuk az operátorok precedenciájának, más néven kiértékelési sorrendjének. Az értékadó operátorok például a lista legalján vannak, ahol a “leggyengébb” műveletek helyezkednek el.

Operátor     Precedencia
postfix operátor    változó++  változó- –
prefix operátor, előjel
operátorok, negálás        ++változó  – -változó  +változó  -változó  !
Aritmetikai operátorok
(multiplikatív)      *  /  %
Aritmetikai operátorok (additív)        + 
Relációs operátorok       <  >  <=  >=
Relációs operátorok
(egyenlőségvizsgálat)     ==  !=
Kizáró vagy ^
Logikai és   &&
Logikai vagy        ||
Feltételes operátor ? :
Értékadó operátorok       =  +=  -=  *=  /=  %=
Ha jobban megnézed, akkor a precedencia nagyrészt megegyezik a matematikai műveletek sorrendjével, valamint itt is igaz az, hogy zárójelezéssel felül lehet, és sokszor felül is kell bírálni azt. Egyetlen fontos szabályt hagytunk csak ki. Mi van akkor, ha azonos szinten lévő operátorok szerepelnek a kifejezésben? Akkor mi a sorrend? Ebben az esetben mindig a balról-jobbra kiértékelési sorrend az érvényes.

Itt is van azonban egy kakukktojás, igaz, ez inkább elméleti dolog. Emlékszel, hogy az értékadó operátoroknál mi a kiértékelési sorrend? Hiszen az is két operandust köt össze. A bal oldalon egy változó, a jobb oldalon pedig literál, változó vagy kifejezés állhat. Na de a két operandus közül melyiket kell először használni? A jobb oldalit, mert annak az eredménye kerül a bal oldali változóba. Akkor jöjjön az elméleti példa:

int a, b;
a = b = 2;
Mi lesz ennek az eredménye? Minden változó 2 lesz. De az előbb említettem, hogy azonos precedencia szintű operátorok esetén a végrehajtási sorrend balról jobbra halad. Igen, kivéve az értékadásnál. Itt mindig a jobb oldal kerül először kiértékelésre. Vagyis:

az a változó értéket kap: a = b = 2;
a jobb oldalon megint egy értékadás szerepel: b = 2;
a b változó jobb oldalán lévő érték bekerül a b változóba (tehát a b = 2 eredménye 2 lesz)
a b = 2 kifejezés eredménye (2) bekerül az a változóba
Vagyis: jobbról balra haladva értékelte ki a többszörös értékadást. Ritka, de előfordulhat és működik. És természetesen, mivel az átláthatóságot rontja, kerülendő

Ciklusok, avagy “na még egyszer”
Programozás esetén nagyon sok esetben előfordul az, hogy valamilyen tevékenységet (utasításokat) többször meg kell ismételni. Ilyenek a való életben is sokszor előfordulnak.

Szúrj be 5 üres sort a táblázatba.
Készíts 3 szendvicset
Dobj 3 kockával (egyszer dobunk, de 3 számot sorsolunk)
Írd le 100x, hogy nem felejtem el a házi feladatomat
Ezek a többször ismételt tevékenységek megegyeznek abban, hogy előre tudjuk, hányszor kell elvégezni őket. Persze olyan is előfordul, hogy addig kell végezni valamit, amíg lehet.

Hámozz meg 2 kg almát
Mosogass el
Készíts annyi szendvicset, amíg el nem fogy a felvágott
Ezeket a tevékenységeket is többször kell ismételni, de nem tudom hányszor. Lehetnek kisebb almák, abból többet kell hámozni, de ha nagyobbak, kevesebb darabból is kijön a 2 kg. Addig mosogatok, amíg van edény. Addig készítem a szendvicseket, amíg van mit rátenni.

A programozásban is ezek az elvek érvényesülnek. Ezek szerint 3 különféle ciklus típust különíthetünk el:

Növekményes ciklus
Elöl tesztelő ciklus
Hátul tesztelő ciklus
A működés alapelve szerint az első különbözik a többitől. Ebben az esetben előre tudjuk, hogy hányszor akarjuk ismételni a teendőinket, míg az utóbbi két esetben az ismétlés darabszáma feltételhez kötött. Ettől a kép valójában kicsit árnyaltabb, mert a Java nagyon rugalmas a ciklusaival, de az alapelvek ezek.

Növekményes ciklus – for
Kezdjük az elsővel, a növekményes ciklussal. Az ilyen típusú ciklus a következőképp néz ki formailag:

for( ciklusváltozó beállítása; futási feltétel; ciklusváltozó növelése )
{
  utasítás1;
  utasítás2;
  ...
  utasításN;
}
Konkrét példával:

for( int i = 0; i < 20; i++ )
{
  System.out.println(i);
}
A for kulcsszó vezeti be a ciklust. Ezután jön a ciklus feje, ahol 3 dolog állítható be:

a használandó ciklusváltozó kezdőértéke
a futási feltétel, vagyis mikor kezdődjön újabb “kör”
a ciklusváltozó növelése
A szép (vagy épp csúnya, de ez nézőpont kérdése) a dologban az, hogy ebből a 3 dologból semmi nem kötelező. Bármelyik, vagy akár mind elhagyható, az egyetlen megkötés, hogy a 3 részt elválasztó ; jelek mindegyike megmaradjon:

int i = 0;
for( ; ; )
{
  if( i == 20 ) break;
  System.out.println(i);
  i++;
}
Igaz, ez kicsit kifordítja a feladatot és eddig ismeretlen utasítást is tartalmaz, de látjuk azt, hogy lehetséges.

Nos, a for ciklus tehát alapesetben arra szolgál, hogy egyesével növelve egy változót valamilyen tevékenységet addig hajtsunk végre, ameddig azt az általunk megadott feltétel engedi. Példákon keresztül ez érthetőbb lesz:

Számoljunk el 1-től 50-ig és írjuk ki a képernyőre a számokat:

for( int i = 1; i <= 50; i++ )
{
  System.out.println(i);
}
Ha megnézzük a ciklusfejet, a következőket láthatjuk:

a ciklusváltozót 1-től indítjuk
addig megyünk, amíg el nem érjük az 50-et
a ciklusváltozót egyesével növeljük
Persze ezt így is írhattam volna:

for( int i = 0; i < 50; i++ )
{
  System.out.println(i+1);
}
0-tól megyek 49-ig, de mindig eggyel nagyobb számot írok ki.

Sorsoljunk ki 10 véletlen számot az [1;50] intervallumból és írjuk ki őket:

for( int i = 0; i < 10; i++ )
{
  System.out.println( (int)(Math.random()*50)+1 );
}
A fenti ciklusfej nagyon erős típusfeladat és egy alapszabályt láthatsz benne: Az i-t indítsd 0-ról és addig menj, amíg kisebb, mint az a szám, amennyiszer a ciklust futtatni akarod:

for( int i = 0; i < 10; i++ )  // 10-szer
for( int i = 0; i < 20; i++ )  // 20-szor
for( int i = 0; i < 100; i++ ) // 100-szor
Írjuk ki 2-től indulva 20 páros számot:

for( int i = 1; i <= 20; i++ )
{
  System.out.println(i*2);
}
Itt annyi trükköt alkalmazok, hogy 1-től számolok el 20-ig (ennyi szám kell), de ezeket 2-vel szorozva mindig páros számot kapok. Persze ha az alapszabályt tekintem, amikor 0-tól indítom a ciklust, és a határ-1-nél állok meg, akkor így is írhatnám ugyanezt:

for( int i = 0; i < 20; i++ )
{
  System.out.println((i+1)*2);
}
És ha az 1-től indulva kell 20 páratlan?

for( int i = 1; i <= 20; i++ )
{
  System.out.println(i*2-1);
}
A párosokból 1-et kivonva páratlanokat kapunk. Vagy 0-tól indulva:

for( int i = 0; i < 20; i++ )
{
  System.out.println(i*2+1);
}
De csak hogy lássuk milyen rugalmas is a for ciklus, lássunk a párosokra egy másik megoldást:

for( int i = 2; i <= 40; i += 2 )
{
  System.out.println(i);
}
Na jó, kicsit csaltam. Tudom, hogy a 40 lesz az utolsó, viszont nem szorozgatok, hanem a ciklusváltozót most nem 1-gyel, hanem 2-vel növelgetem. Itt egy jó példa a += operátorra.
Egy szó, mint száz, a for ciklus egy rugalmas és hatékony eszköz akkor, ha előre tudom, hogy hányszor akarok valamit végrehajtani. De az már egyértelmű, miért olyan szerteágazó az egész, mert ugyanarra a problémára rengeteg fajta megoldást adhatok, és mindegyik tökéletesen megoldja a feladatot. Annyira árnyalatnyi különbségek vannak közöttük, hogy ezzel középiskolai szinten egyáltalán nem kell foglalkozni, a lényeg: helyes megoldást adjon.

Elöl tesztelő ciklus – while
Az elöl tesztelő ciklust jellemzően akkor használjuk, ha nem tudjuk előre, hogy hányszor kell az ismétlődő tevékenységet végrehajtani. Azzal nincs gond, ha ki kell sorsolni 10 számot egy intervallumból. Ez egy for ciklusnak megfelelő típusfeladat. De ha az a feladat, hogy egy adott intervallumból 10 darab páratlan számot kell sorsolni? Akkor ha véletlenül páros számot kaptál azt figyelmen kívül kell hagyni. Lássuk először a while ciklus általános alakját:

while( feltétel )
{
  utasítás1;
  utasítás2;
  ...
  utasításN;
}
Mint láthatod itt is van egy ciklusfej, ami a futási feltételt tartalmazza. Ez működési szempontból azt jelenti, hogy a ciklus akkor fut le (hajtja végre a ciklusmagot), ameddig a feltétel igaz. Természetesen arra figyelni kell, hogy a feltétel egyszer teljesülhessen, vagy a ciklusmagban szakítsuk meg a futást, nehogy végtelen ciklusba fussunk. Ez azt jelenti, hogy soha nem állhat le, mert vagy nem állítjuk meg, vagy a futási feltétel soha nem lehet hamis. A legegyszerűbb véletlen ciklus:

while( true )
{
  System.out.println("fut");
}
Lássuk akkor az előző példát, sorsoljunk ki 10 páratlan számot egy adott intervallumból [1;100]

int db = 0;
int szam;
while( db != 10 )
{
  szam = (int)(Math.random()*100)+1;
  if( szam % 2 != 0 )
  {
    System.out.println(szam);
    db++;
  }
}
Nézzük akkor sorban, mit is csinál ez a program:

kell egy változó, ami azt számolja majd, hogy hány páratlan számot sorsoltunk, mert a párosokkal nem foglalkozunk
deklaráltam egy szam nevű változót, ahol az aktuálisan kisorsolt számot tároljuk
a ciklust futási feltétele az, hogy amíg nincs 10 páratlan szám, addig sorsolgasson
a ciklusban sorsolok egy számot, és eltárolom
miután kisorsoltam, megvizsgálom, hogy páratlan-e
ha páratlan, akkor kiírom a sorsolt számot, és növelem eggyel a számlálót
ha nem páratlan, akkor a ciklusmagból semmi nem hajtódik végre, mert nem megfelelő a szám és ismét próbálkozik egy sorsolással
Jöjjön egy másik jó példa az elöl tesztelő ciklusra. Számítsuk ki két egész szám osztóját. Nem, nem a prímtényezős alakra bontással oldjuk meg, hanem egy jól programozható megoldást adunk, mely a következő – egyébként már meglévő – algoritmust takarja:
Addig kell kivonni a két szám közül a nagyobból a kisebbet, amíg a két szám egyenlő nem lesz. Ha a két szám egyenlő, az az eredeti számok legnagyobb közös osztója. Az könnyen belátható, hogy megjósolhatatlan, hányszor kell az említett kivonást elvégezni, tehát for ciklust nem igazán alkalmazhatunk. (lehetne, de elég kitekert megoldás lenne)

int szam1 = 660;
int szam2 = 366;
while( szam1 != szam2 )
{
  if( szam1 > szam2 )
  {
    szam1 = szam1 - szam2 ;
  }
  else
  {
    szam2 = szam2 - szam1 ;
  }
}
System.out.println("A ket szam legnagyobb kozos osztoja: "+szam1);
Na, nézzük, mit is csinál ez a program:

deklarálunk 2 változót a vizsgált számoknak
kell egy ciklus azzal a futási feltétellel, hogy addig kell a kivonásokat ismételni, amíg a két szám nem egyenlő
ha a szam1 a nagyobb, akkor abból vonjuk ki a szam2-őt
fordított esetben a szam2-ből vonjuk ki a szam1-et
amikor a ciklus befejeződik, akkor a két szám bármelyike (mivel egyenlőek) a legnagyobb közös osztót jelenti, amit ki is íratunk
Ha észrevetted, az is előfordulhat, hogy a ciklus egyszer sem fut le. Mi van akkor, ha a két szám alapból egyenlő? Akkor is kiírathatom bármelyiket, vagyis a ciklus utáni sorra lép a program és kiírja az egyiket. Az elöl tesztelő ciklusnál lehetséges, hogy a ciklus egyszer sem fut le.

Hátul tesztelő ciklus – do-while
A do-while ciklus az előzőleg ismertetett while-ra hasonlít abban a tekintetben, hogy ezt a fajta ciklust is akkor használjuk, amikor nem tudjuk előre, hogy hányszor kell egy utasítás sorozatot végrehajtani. Azonban mégis van egy fontos különbség a kettő között. Lássuk az általános alakot, akkor egyértelmű lesz:

do
{
  utasítás1;
  utasítás2;
  ...
  utasításN;
}
while( feltétel );
Mint a neve is mutatja, itt a ciklus feje hátul van (a feltétellel együtt) és a ciklusmagba tartozó utasítások elöl. Ez azt jelenti, hogy a ciklusmag 1-szer mindenképpen lefut, mert ez a ciklus először végrehajt, utána vizsgálja meg, hogy szükséges-e többször! Jellemzően olyan feladatoknál használjuk, amikor egyszer mindenképp végre kell hajtani valamit, de utána ellenőrizni kell, hogy amit kaptunk megfelelő-e, mert ha nem, csináljuk meg újra. Ilyen például az a számsorsolás, ami valamilyen feltételhez kötött:

Sorsolj ki egy páros számot a [10;50] intervallumból. Azt még egyszerűen megoldjuk, hogy az adott intervallumból sorsoljunk, de azzal a plusz feltétellel már nem tudunk mit kezdeni, hogy ez páros is legyen. Ezért addig sorsolunk, hogy a feltételnek megfelelő számot kapjunk:

int szam;
do
{
  szam = (int)(Math.random()*41)+10;
}
while( szam % 2 != 0 );
Nézzük akkor a programot részenként:

sorsolunk egy számot
ha a szám 2-vel osztva nem 0 maradékot ad (páratlan), akkor a ciklus újraindul, vagyis megint sorsol egyet
a ciklus akkor áll meg, ha a feltétel hamis lesz (páros)
Azért jó itt a do-while ciklus, mert mindenképpen sorsolnom kell egy számot ahhoz, hogy megvizsgálhassam, meg kell-e ismételni a sorsolást. Természetesen összetett feltételt is megadhatok. Mondjuk olyan számot sorsoljunk az adott intervallumból, ami 2-vel és 5-tel is osztható:

int szam;
do
{
  szam = (int)(Math.random()*41)+10;
}
while( !(szam % 2 == 0 && szam % 5 == 0) );
Itt a ciklus futási feltételeként a kiemelt sorban egy összetett feltételt láthatsz, ami azért nem biztos, hogy annyira egyértelmű, mint amilyennek elsőre tűnik. A ciklus ugye akkor működik, ha a feltétel igaz. De itt eredetileg két részfeltételünk van, 2-vel és 5-tel osztható szám kell. Az már nem jó, ha esetleg egyik, vagy az sem, ha mindkét részfeltétel hamis. Igen ám, de a ciklus futási feltételeként nem azt kell megadni nekünk, amilyen számra nekünk szükségünk van, hanem pont az ellenkezőjét. Azt kell megadni, hogy milyen szám nem jó nekünk! Nézzük akkor lépésenként:

szerkesszük meg azt a feltételt, ami nekünk megfelelő (ami összetett feltétel is lehet)
negáljuk az egészet
Természetesen itt is igaz, hogy ha akarjuk, egyszerűsíthetjük az összetett feltételt a már tanult módon:

while( !(szam % 2 == 0 && szam % 5 == 0) ); // 1. verzió
helyett
while( szam % 2 != 0 || szam % 5 != 0 );    // 2. verzió
tehát
Ha tudom hányszor fusson a ciklus, akkor for ciklus.
Ha nem tudom hányszor fusson a ciklus ÉS lehet, hogy egyszer sem kell, akkor while ciklus.
Ha nem tudom hányszor fusson a ciklus ÉS egyszer mindenképpen kell, akkor do-while ciklus.

Metódusról

A Java programnyelv metódusait alapvetően két csoportba sorolhatjuk:

metódusok, melyek valamilyen értéket állítanak elő
metódusok, melyek valamilyen tevékenységet hajtanak végre
Az első csoport nagyjából olyan, mint egy táblázatkezelő program függvényei. Ezek a metódusok valamilyen bemenő adatok segítségével számítást végeznek, és adott típusú (szám, szöveg, karakter, stb) eredményt állítanak elő. Ez az eredmény a metódus visszatérési értéke. A bemenő adatok, melyeket innentől nevezzünk paramétereknek, valamilyen változók vagy literálok (a típusnak megfelelő formában megadott értékek), de az sem törvényszerű, hogy legyen bemeneti érték. Vannak metódusok, amelyek bemeneti egy előre meghatározott keretek közötti értéket adnak eredményül. A bemenő adatok száma is sokfajta lehet, de ebből egyelőre legyen elég ennyi.

A második csoportba tartozó metódusok valamilyen tevékenységet hajtanak végre, ide tartozik például a képernyőre való kiíratás.

Osztályok

Math osztály
A Math osztály matematikai témakörrel kapcsolatos metódusokat tartalmaz. A metódusok többsége sokféle számot is elfogad, beleértve egész és valós értékeket is, azok összes altípusával együtt. Sőt, több ezeket keverve is működik. A teljesség igénye nélkül álljanak akkor itt a legfontosabbak:

Math.min(a,b); // a két változó közül a kisebb értéket adja eredményül
Math.random(); // kisorsol egy lebegőpontos számot a [0;1[ intervallumból
Math.round(a); // matematikai szabály szerint kerekíti a változó értékét
Math.abs(a); // az adott változó értékének abszolút értékét adja vissza
Math.sqrt(a); // az adott változó négyzetgyökét adja vissza
Math.pow(a,b); // az a számot a b-edik hatványra emeli
Math.PI; // Pi értékét adja vissza
Math.E; // E értékét adja vissza

Az objektumokkal kapcsolatban alapvetően négy fontos dologról beszélhetünk:

Adat és kód egysége
Zártság
Öröklődés
Polimorfizmus

A nyelv tervezésekor fontos szempont volt az, hogy az objektumok többé-kevésbé állandóak, de a hozzájuk tartozó feladatok nem, ezért az objektumok kapnak nagyobb hangsúlyt. A mai programok nagyon sok, egymással kölcsönhatásban álló elemből állnak, így nem is igazán programokról, hanem programrendszerekről beszélhetünk.

Osztályok
Amikor egy Objektumot létrehozunk, azt valójában egy osztályból hozzuk létre. Az osztály egy megírt Java forráskód, aminek nagy vonalakban a következő részei vannak:

Változók
Metódusok
Konstrukciós műveletek
Az első kettőről már hallottál, az utolsó volt az, amit megígértem, hogy előszedjük. A konstrukciós műveletek olyan speciális részei az osztálynak, amelyben azt írjuk le, hogy az objektumot hogyan kell felépíteni, létrehozni a terv alapján.

Az osztály az objektumok terve!

public class Dog
{
// Változók
  String nev;
  String fajta;
  String szin;

// Metódusok
  public String getNev()
  {
    return nev;
  }

  public String getFajta()
  {
    return fajta;
  }

  public String getSzin()
  {
    return szin;
  }

// Konstruktor
  public Dog(String nev, String fajta, String szin)
  {
    this.nev = nev;
    this.fajta = fajta;
    this.szin = szin;
  }
}
Amikor az osztályból egy új példányt szeretnénk létrehozni, a konstruktor az, amit megkérünk, hogy építse fel nekünk. Kell egy kutya! Lássuk akkor újra azt a pillanatot, amikor tényleg létrehozzuk egy kutyát. A terv már megvan, már csak le kell gyártani.

d = new Dog("Buksi", "Tacsko", "Barna");
Tehát a new utáni rész a konstruktor, ami a példában az osztály végén látható. Amikor egy kutyát létre akarunk hozni, meg kell mondanunk a nevét, fajtáját és színét. Pontosan ebben a sorrendben. Ha ezt nem tesszük meg, nem lesz kutyánk!

Miért kell megadni mindhármat? Nem lehet ezt megadni később? Lehetne, de ha megnézed, a Dog osztály konstruktora 3 paramétert vár, mert csak akkor tudja a kutyádat felépíteni, ha ezeket megkapja. Mindet. Pontosan ebben a sorrendben! Ha ezekből akár egy is hiányzik (vagy több van), akkor már a fordítótól hibaüzenetet fogsz kapni, mert ő nyilvántartja, hogy melyik tervnek hány és milyen típusú bemenő adat kell ahhoz, hogy objektumot hozhasson létre.

Egy osztálynak lehet több konstruktora is!

A kiíratás egyszerű kommunikáció a program és a felhasználó között. Ennek használata egyszerű, de vannak fontos szabályok, melyeket be kell tartani.

System.out.println() és System.out.print()
Kezdetben ezt a két metódust fogjuk kiíratásra használni, az alapvető igényeinket teljesen ki fogják szolgálni. A Java nyelvben a szövegeket idézőjelek “” közé tesszük. Nem macskaköröm, ahogy többször is hallottam. Na még egyszer: idézőjel.

Amit ilyen jelek közé írunk, azt a rendszer szövegnek tekinti. A kiíratás során a két metódusnak ilyen szövegeket szoktunk megadni, de ezekhez sokszor hozzá is fűzünk valamit. Lássunk akkor erre példákat:

1
2
3
4
5
6
int szam1 = 10;
int szam2 = 20;
int osszeg;
osszeg = szam1 + szam2;
System.out.println( "A szamok osszege: " );
System.out.println( osszeg );
A két kiemelt sorban láthatod azt, hogy a println() metódusnak odaadhatsz egy szöveget is, valamint egy változót is. A változót a kiíratás során átalakítja szöveggé, így a megjelenítés nem lesz gond. A két sort azonban össze is vonhatod:

System.out.println( "A szamok osszege: "+osszeg );
Ebben az esetben az történik, hogy az összeg változó tartalmát, ami egy egész szám, hozzáfűzi a szöveghez úgy, hogy közben át is alakítja azt is szöveg típusúvá.

Abban az esetben, amikor a + jel valamelyik oldalán szöveg található, akkor a + jel nem az összeadás, hanem az összefűzés műveletét jelenti!

Fontos, hogy az átalakítás csak a kiíratásra korlátozódik, az összeg változó továbbra is azt az egész számot tartalmazza, amivel továbbra is végezhetsz számításokat.

Az összefűzés tekintetében teljesen mindegy, hogy mi az összefűzés sorrendje, maximum a kiíratásnak nem lesz értelme:

System.out.println( osszeg+ " a szamok osszege." );
Egy fontos problémára felhívnám a figyelmet, ami sokszor gondot jelent. Tömörítsük még a programunkat, ne számítsuk ki külön változóba az összeget, hanem magába a kiíratásba tegyük bele:

1
2
3
int szam1 = 10;
int szam2 = 20;
System.out.println( "A szamok osszege: "+szam1+szam2 );
A kiemelt sorban van egy nagyon fontos probléma, de egy picit félreteszem, és azonnal visszatérünk.

Nézzük meg a következő programot: adott egy egész szám, írjuk ki a kétszeresét.

int szam = 7;
System.out.println( "A szam ketszerese: "+szam*2 ); // 14
Ez a megoldás teljesen helyes, és semmi gond nincs vele. Most írjuk ki a számot úgy, hogy hozzáadunk kettőt:

1
2
int szam = 7;
System.out.println( "A szam kettovel megnovelve: "+szam+2 ); // 72???
Mi a gond? Azonos rangú műveletek esetén mi a műveleti sorrend? Balról jobbra haladunk. Vagyis:

kiírjuk a szöveget: “A szam ketszerese: “
hozzáfűzzük ehhez a szam-ot. “A szam ketszerese: 7”
hozzáfűzzük ehhez a 2-őt: “A szam ketszerese: 72”
Vagyis mivel a műveletek egyenrangúak, balról-jobbra haladva hatja végre. A szöveghez hozzáfűzi a a változót, majd az egészhez a 2-őt. Ezek alapján már értheted az átugrott feladatnál is mi a gond.

Mit tehetünk? Bíráljuk felül a műveleti sorrendet egy egyszerű zárójelezéssel.

1
2
int szam = 7;
System.out.println( "A szam kettovel megnovelve: "+(szam+2) ); // 9


Vezérlőkarakterek

n – sordobás (új sort kezd ennél a pontnál
\t – tabulátor (alapérték által meghatározott mezőnyit ugrik)
\b – backspace (balra egy karakter visszatörlés)
\r – visszaáll a kurzor a sor elejére, bármit írunk ezután, a sorban lévő szöveget törli
\a – néhány terminálon esetleg megszólaltatja a gép speaker-jét
\\ – maga a \ karakter
\” – idézőjel
Lássunk erre ömlesztett példákat, minden különösebb magyarázat nélkül:

System.out.println( "foo\bbar" );
System.out.println( "foo\rbar" );
System.out.println( "foo\nbar" );
System.out.println( "Gyakran hasznalt vezerlo karakterek:\n\\n \\\\ \\\"" );
System.out.println("Elso szam:\t"+10);
System.out.println("Masodik szam:\t"+20);
System.out.println("Harmadik szam:\t"+30);


Több elágazás

Switch szerkezete
switch( valtozo )
{
// case után a konkrét előfordulás
  case 1_tipus :
// az előforduláshoz kapcsolt egyetlen utasítás
    elso_tipus_utasitasa;
// lezárjuk a kapcsolt utasítást
  break;

// több előforduláshoz ugyanaz az utasítás is tartozhat
  case 2_tipus : case 3_tipus :
    masodik_vagy_harmadik_tipusok_utasitasa;
  break;

// sokszor a rovid egy utasitasos agakat egy sorba irjuk
// a tomorebb forma miatt, a break mehet a vegere
  case 5_tipus : otodik_tipus_utasitasa; break;

// irhattam volna a 2 case agat azonos sorba is, mint a 2-3-nal
  case 4_tipus :
  case 6_tipus :
// több előforduláshoz több utasítás is tartozhat
    negyedik_vagy_hatodik_tipusok_elso_utasitasa;
    negyedik_vagy_hatodik_tipusok_masodik_utasitasa;
    ....
  break;

// a 7-es agnal nem veletlenul hianyzik a break!!
  case 7_tipus : hetedik_tipus_utasitasa;
  case 8_tipus : nyolcadik_tipus_utasitasa; break;

// egy előforduláshoz több utasítás is tartozhat
  case 9 :
    kilencedik_tipus_elso_utasitasa;
    kilencedik_tipus_masodik_utasitasa;
  break;
...
...
// a default ag nem kotelezo! egyfajta else agkent ertelmezheto
  default :
    minden_mas_eset_utasitasai;
    ....
  break;
}
Akkor pár magyarázat ezzel kapcsolatban:

A switch után zárójelben meg kell adni azt a típust, amelynek a különféle értékeihez kapcsolódó ágakat a switch-en belül kezelni szeretnénk. Ezek a típusok jórészt primitív típusok lehetnek, valamint pár speciális típus. A lista nem teljes, de a lényeges elemek benne vannak:
byte
short
int
char
String(!) (java 7 óta)
enum
Az egyes ágakat case kulcsszóval vezetjük be, ami után odaírjuk a konkrét előfordulást, amihez a kettőspont utáni utasításokat kapcsolni szeretnénk. Ha egyetlen rövid utasítást használunk csak, akkor írhatjuk a példa ötödik előfordulásának megfelelő szerkezetben egy sorba.
Több különböző előforduláshoz tartozhatnak közös utasítás vagy utasítások, lásd 2-3 és 4-6 esetek. Az előfordulásoknak nem kötelező egymás utániaknak lenni, pl sorszámok esetén. Több előfordulás közös vizsgálatakor a case elofordulas : utasításokat egy vagy több sorba is írhatjuk (pláne ha sok van), de minden case-t kettőspont választ el az utána következő case-től vagy az utasításoktól!
Az egyes ágak utasításait break-kel zárjuk le a következő előfordulás vizsgálata előtt. Nagyon speciális esetekben a break elhagyható. A példában szereplő 7-es előfordulás esetén végrehajtja a hetedik_tipus_utasitasa-t, de mivel itt hiányzik a break, a 7-eshez végrehajtja a 8-as utasításait is, függetlenül attól, hogy a két előfordulás különbözik egymástól. Ez az utasításszerkezet nagyon elnézhető, éppen ezért csak nagyon speciális esetben szokás használni! Több mint 15 éves programozói munkám során emlékeim szerint egyszer használtam, ott is teleraktam kommentekkel még a környékét is, nehogy valaki jóhiszeműen kirakja az általam ott kihagyott break-et! Attól eléggé fejre állt volna a program 🙂
A default ágat egyfajta else-ként értelmezhetjük, sok esetben arra használjuk, hogy az egyes előfordulások vizsgálata figyelmeztessünk az esetleges hibás értékekre. Nem kötelező, de ha használjuk, mindenképp a switch szerkezet végén kell lennie.
Amilyen előfordulások nem szerepelnek a vizsgálatok között, azokat a switch figyelmen kívül hagyja.
Látjuk azt, hogy nagyon rugalmasan variálható szerkezetről van szó, amivel változók tartalmának direkt vizsgálatakor az esetleges sok esetet átlátható módon kezelhetjük. A helyzet az, hogy rugalmassága ellenére is viszonylag ritkán használom. Egyrészt amiatt, mert sok esetben valóban elég egy továbbmásolt if-else if-else alapú feltételvizsgálat, másrészt néhány esetben kifejezetten bonyolítja a switch a helyzetet. Kicsit olyan ez, mint amikor megtanulja az ember a while, do-while és for ciklusokat. Bármelyikkel kiváltható bármelyik, a helyzet azonban az, hogy mindegyiket akkor használjuk, amikor az a feladat azzal a szerkezettel oldható meg egyszerűbben vagy átláthatóbban. A switch esetében a rengeteg fajta testreszabási lehetőséggel együtt is azt javaslom, hogy akkor használjuk, amikor egyértelmű megoldásokat kaphatunk vele.

Switch példák
Hónapok
Tegyük fel, hogy a hónapok sorszámait szeretnénk átalakítani szöveges formává. Az if-else if-else szerkezetekkel ez a következőképpen nézne ki:

int honap = (int)(Math.random()*12)+1;
string honev = "";
if( honap == 1 )
{
  honev = "Januar";
}
else if( honap == 2 )
{
  honev = "Februar";
}
else if( .... )
...
...
else
{
  honev = "December";
}
Az általam szeretett ctrl-c és ctrl-v billentyűkombinációval ez viszonylag hamar összerakható, de valójában a legtöbb gépelést a hónapok nevei okozzák. A helyzet az, hogy a switch utasítás sem kímél meg a hónapok gépelésétől, de magát az elágazási szerkezetet leegyszerűsíti. Lássuk hogyan:

int honap = (int)(Math.random()*12)+1;
string honev = "";
switch( honap )
{
  case 1 : honev = "Januar"; break;
  case 2 : honev = "Februar"; break;
  case 3 : honev = "Marcius"; break;
  ....
  ....
// mivel a veletlen szam sorsolas csak 1-12-ot sorsolhat
// a default-ot nem hibakezelesre hasznalom, ez a december
  default : honev = "December"; break;
}
Láthatod, hogy a switch a sok case meg break miatt ez sem kevesebb gépelés, mint egy if-else if-else szerkezet, de természetesen megoldható ezzel is. Rád bízom melyiket tekinted egyszerűbbnek.

Napok
Mi van akkor, ha a hét napjának a sorszámából szeretnénk megkapni, hogy az hétköznap vagy hétvége:

int nap = (int)(Math.random()*7)+1;
switch( nap )
{
  case 1 : case 2 : case 3 : case 4 : case 5 :
    System.out.println("Hetkoznap");
  break;

  default :
    System.out.println("Hetvege");
  break;
}
És if-else if-else-szel hogy néz ki ugyanez?

int nap = (int)(Math.random()*7)+1;
if( nap <= 5 )
{
  System.out.println("Hetkoznap");
}
else
{
  System.out.println("Hetvege");
}
Itt a switch szerintem feleslegesen bonyolította is a megoldást.

Hiányzó break
Lássunk akkor példát arra, hogy mikor lehet elhagyni a break-et. Sorsoljuk ki egy nap sorszámát, írjuk ki a hét hátralévő napjainak nevét:

int nap = (int)(Math.random()*7)+1;
switch( nap)
{
  case 1 : System.out.println("Kedd");
  case 2 : System.out.println("Szerda");
  case 3 : System.out.println("Csutortok");
  case 4 : System.out.println("Pentek");
  case 5 : System.out.println("Szombat");
  case 6 : System.out.println("Vasarnap");
}
Itt sehol nincs break. Az előfordulások vizsgálatának sorrendje viszont megadja azt, hogy ha mondjuk 3-as napot sorsoltunk, akkor onnan kezdődően a hiányzó break-ek miatt az utasítások mindegyike végrehajtódik. Amelyik előfordulás vizsgálatnál nincs break, az addig végrehajtja az összes alatta lévő utasítást – az ottani case értékektől függetlenül -, ameddig bele nem szalad egy break utasításba, vagy el nem éri a switch végét. És mi a helyzet a 7-es nappal? Nincs sehol és nincs default ág. Semmi. Amire nincs vizsgálat, azt figyelmen kívül hagyja.

Kerekítés
Adott a magyar készpénzes fizetés kerekítési problémája. Az 1-2-re végződő összegeket lefelé az alatta lévő tízesre kerekítjük, a 3-4-et a felette lévő 5-ösre, stb. Erre nagyon sokféle elegáns, kevésbé elegáns megoldást lehetne adni. Switch szerkezettel is megoldható sokféleképp. Mutatok két megoldást, 1-1 leheletnyi különbséggel.

Első verzió:

int penz = 0;

for (int i = 0; i < 20; i++)
{
  penz = (int) (Math.random() * 991) + 10;
  System.out.print(penz + " -> ");

  switch (penz % 10)
  {
    case 2: case 7: penz -= 2; break;

    case 1: case 6: penz--;    break;

    case 3: case 8: penz += 2; break;

    case 4: case 9: penz++;    break;
  }
  System.out.println(penz);
}
Második verzió:

int penz = 0;

for (int i = 0; i < 20; i++)
{
  penz = (int) (Math.random() * 991) + 10;
  System.out.print(penz + " -> ");

  switch (penz % 10)
  {
    case 2: case 7: penz--;
    case 1: case 6: penz--; break;

    case 3: case 8: penz++;
    case 4: case 9: penz++; break;
  }
  System.out.println(penz);
}
A második esettel trükkös megoldás, ahol kihasználom azt, hogy a hiányzó break miatt a következő utasításokat is végrehajtja a break nélküli előfordulásokhoz egészen addig, ameddig egy break-be bele nem szalad. A helyzet azonban az, hogy mivel a programozók legtöbbször csapatban dolgoznak, a legkevésbé szeretik mások trükkös megoldásait bogarászni. A lényeg az, hogy a megoldás átlátható és világos legyen, hiszen akkor annak működését, esetleges hibáit is jóval egyszerűbb felismerni. Természetesen vannak ettől egyszerűbb, switch mentes megoldások is, ezeket most csak a szerkezet bemutatása miatt írtam meg.

Switch használata String-gel
Az alábbi feladatban a hónapokat nevük alapján szeretnénk visszaalakítani számokká. Természetesen ennek is van egyszerűbb módja, de a példa kedvéért álljon itt switch szerkezettel:

String[] honapok = { "januar","marcius","december","november",
                     "januar","julius","majus","majus","szeptember",
                     "oktober","aprilis","majus","februar" };
int ho = 0;
      
for( int i = 0; i < honapok.length; i++ )
{
    switch( honapok[i] )
    {
        case "januar"     : ho = 1;  break;
        case "februar"    : ho = 2;  break;
        case "marcius"    : ho = 3;  break;
        case "aprilis"    : ho = 4;  break;
        case "majus"      : ho = 5;  break;
        case "junius"     : ho = 6;  break;
        case "julius"     : ho = 7;  break;
        case "augusztus"  : ho = 8;  break;
        case "szeptember" : ho = 9;  break;
        case "oktober"    : ho = 10; break;
        case "november"   : ho = 11; break;
        case "december"   : ho = 12; break;
        default           : ho = -1; break;
    }
    System.out.print(ho + " " );
}

Véletlen
Ha egész számokat akarunk sorsolni, akkor ezek a típusok jöhetnek szóba. A jó az egészben az, hogy bármilyen egészeket tartalmazó intervallumra egy általános “képlettel” meg lehet adni a sorsolandó számot. Először meg kell határozni az intervallum alsó és felső határát. Ha ezeket tudjuk, akkor jöhet a sorsolást végző programkód. Ennek általános formája a következő:

(int)( Math.random()*(felső-alsó+1) )+alsó;


Példaprogramok
public class FindLargestSmallestNumber {

         public static void main(String[] args) {
                  
                   //array of 10 numbers
                   int numbers[] = new int[]{32,43,53,54,32,65,63,98,43,23};
                  
                   //assign first element of an array to largest and smallest
                   int smallest = numbers[0];
                   int largetst = numbers[0];
                  
                   for(int i=1; i< numbers.length; i++)
                   {
                            if(numbers[i] > largetst)
                                      largetst = numbers[i];
                            else if (numbers[i] < smallest)
                                      smallest = numbers[i];
                           
                   }
                  
                   System.out.println("Largest Number is : " + largetst);
                   System.out.println("Smallest Number is : " + smallest);
         }
}

public class Egesz {

 public static void main(String[] args) {
  int i,n=10;

  System.out.println("Az elso "+n+" egesz szam:");
  for(i=1;i<=n;i++){
   System.out.println(i);
   }
  }

 }

public class Lotto {

 public static void main(String[] args) {
  int i,veletlen,vege=5,min=1,max=90;
    for(i=1;i<=vege;i++){veletlen=(int)(max*Math.random())+min;
   System.out.println(veletlen);
   }
  }

 }


public class Negyzetszam {

 public static void main(String[] args) {
  int i,n=10;

  System.out.println("Az elso 10 negyzetszam:");
  for(i=1;i<=n;i++){
   System.out.println(i+"*"+i+" = "+i*i);
   }
  }

 }


public class Odavissza {

 public static void main(String[] args) {
  int i,n=20;

  System.out.println("Az elso "+n+" egesz szam:");
  i=15; //kezdőértékadás
  while(i<=20) {
   System.out.println(i);
   i++; //ciklusváltozó növelése
   }
  i=30;
  System.out.println("Az elso "+n+" egesz szam visszafele:");
  while(i>=25) {
   System.out.println(i);
   i--;
   }
  }

 }

public class Osszeg {

 public static void main(String[] args) {
  int i,sum,n=31;

  System.out.print("Az elso "+n+" egesz szam osszegenek erteke: ");
  sum=0;
  for(i=42;i<=73;i++){
   sum+=i;
   }
  System.out.println(sum);
  }

 }

public class Paratlan {

 public static void main(String[] args) {
  int i,j,sum,n=5;
  long f; //bővebb értéktartomány

  sum=0;
  f=1;
  j=1;
  for(i=1;i<=n;i++){
   sum+=j;
   f*=j;
   j+=2;
   }
  System.out.println("Az elso "+n+" paratlan szam osszegenek erteke: "+sum);
  System.out.println("Az elso "+n+" paratlan szam szorzatanak erteke: "+f);
  }

 }

public class Parosszam {

 public static void main(String[] args) {
  int i,j,n=10;

  System.out.println("Az elso "+n+" paros szam:");
  j=2; //első páros szám
  for(i=1;i<=n;i++){
   System.out.println(j);
   j+=2; //következő paros szám
   }
  }

 }
public class Osszeg {

 public static void main(String[] args) {
  int i,sum,n=31;

  System.out.print("Az elso "+n+" egesz szam osszegenek erteke: ");
  sum=0;
  for(i=42;i<=73;i++){
   sum+=i;
   }
  System.out.println(sum);
  }

 }

public class Szamok {

 public static void main(String[] args) {
  int i,n=10;

  System.out.println("Az elso "+n+" egesz szam:");
  for(i=1;i<=n;i++){
   System.out.println(i);
   }
  }

 }

public class Tomb {
    public static void main(String[] args) {
        int[] anArray;
        anArray = new int[10];
        for (int i = 0; i < anArray.length; i++) {
            anArray[i] = i;
            System.out.print(anArray[i] + " ");
        }
        System.out.println();
    }
}

Kérjkünk be számokat amíg nem lesz 0 rekurzívan:  


    import java.util.Scanner;

    

    class Program {  

        static void szamok() {

            Scanner input = new Scanner(System.in);  

            System.out.print("Szam: ");

            int szam = input.nextInt();

            input = null;

            if(szam != 0)

                szamok();

        }  

    

        public static void main(String args[]) {

            szamok();

        }

    }

public class Sz{ public static void main(String[]args){int i,n=10;for(i=1;i<=n;i++){System.out.println(i);}}}
public class Hatvany {

 public static void main(String[] args) {
  int i,n=10;
  double h=2.0,x;

  x=1.0; //h^0 (h nulladik hatványa)
  System.out.println(h+" elso 10 hatvanya:");
  for(i=0;i<n;i++){
   System.out.println(h+"^"+i+" = "+x);
   x*=h;
   }
  }

 }
public class Lotto {

 public static final int MAXNUM=5; //maximum ennyi számmal dolgozunk
 private boolean[] sz=new boolean[92]; //milyen számokat generáltunk?
 private int num; //hány számot generáltunk már?

 public Lotto() { //konstruktor
  num=0; //az osztály példányosításakor inicializáljuk n-t
  torol(); //az osztály példányosításakor inicializáljuk a tömböt
  }
 public void torol() {
  int i;
  for(i=1;i<=90;i++) {
   sz[i]=false; 
   }
  sz[0]=true; //strázsa
  sz[91]=true; //strázsa
  }
 public int general() {
  int i;
  if(num>MAXNUM) { //öt érték után újrakezdjük a számok generálását
   num=0;
   torol();
   }
  do {
   i=(int)(90*Math.random())+1; //véletlen lottószám generálása
   } while(sz[i]); //addig folytatjuk, amíg nem kapunk új számot
  sz[i]=true; //"betesszük" a számot a tömbbe
  num++; //eddig n darab számot generáltunk
  return i;
  }
 public int kihuz() {
  int i=1;
  while(!sz[i]) { //addig folytatjuk, amíg sz[i] igaz nem lesz
   i++;
   }
  if(0<i && i<91) { //nem értük el a strázsát
   sz[i]=false; //"kivesszük" a számot a tömbből
   num--; //eggyel kevesebb szám van a tömbben
   }
  return i;
  }

 public static void main(String[] args) {
  int i;
  Lotto lotto=new Lotto();
  
  System.out.println("A javasolt lottoszamok:");
  for(i=1;i<=MAXNUM;i++){
   lotto.general(); //öt különböző számot generálunk
   }
  for(i=1;i<=MAXNUM;i++){
   System.out.println(i+". szam: "+lotto.kihuz()); //kiíratás rendezetten
   }
  }
 }
public class Fakt1 {

 public long fakt(int n){ //metódus formális paraméterrel
  int i; //metódus lokális változói
  long f;

  f=1;
  for(i=2;i<=n;i++){
   f*=i;
   }
  return f; //visszatér n faktoriálisának értékével
  }

 public static void main(String[] args) {
  int i,n=10;
  Fakt1 f=new Fakt1();

  System.out.println("Az elso "+n+" szam faktorialisanak erteke:");
  i=1;
  for(i=1;i<=n;i++){
   System.out.println(i+"! = "+f.fakt(i));
   }
  }

 }
public class Szam { public static void main(String[] args) {int i,n=10; for(i=1;i<=n;i++){System.out.println(i); }  } }
public class Szamok {
 public static void main(String[] args) {
  int i,n=10;
    for(i=1;i<=n;i++){
   System.out.println(i);
   }  } }

public class Lotto {

 public static void main(String[] args) {
  int i,veletlen,n=5,min=1,max=90;

  System.out.println(n+" darab veletlen egesz szam a(z) ["+
                     min+","+max+"] intervallumbol:");
  for(i=1;i<=n;i++){
   veletlen=(int)(max*Math.random())+min; //típuskényszerítés (int)-re
   System.out.println(veletlen);
   }
  }

 }
Az adatbekérés billentyűről

direkt erre a feladattípusra készített osztály, a Scanner osztály

Mivel ez a Scanner egy előre megírt osztály, a program elkészítésének első lépése importálni

Még a program osztályainak megadása előtt: import java.util.Scanner;
Ha ez megvan, ettől a ponttól kezdve deklarálhatunk Scanner típusú változót,

és létrehozhatunk belőle egy Scanner objektumot

Nézzünk példákat



 Konzolról bekért szám kiírása a képernyőre



package io1;
/**
 * @Pelda orai
 */
import java.util.Scanner;

public class io1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Kérek egy egész számot!");
        int a = sc.nextInt();
        System.out.println("A beolvasott szám: " + a);
    }
}



 Vagy legyen a kétszerese





import java.util.Scanner;



public class Adatbekeres

{

  public static void main( String[] args )

  {

    Scanner sc;



    sc = new Scanner(System.in);



    int szam;

    szam = sc.nextInt();



    sc.close();



    System.out.println("A bekert szam ketszerese: "+szam*2);

  }

}






    A kód elején a Scanner osztály importálásával kezdünk, mert enélkül nem tudjuk használni. Ha már használhatjuk, akkor létre kell hoznunk egy Scanner objektumot, ami majd az adatbekérést fogja végrehajtani. Ez történik meg a 7. sorban.
    A létrehozott Scanner objektumunkat egy sc nevű változóban fogjuk tárolni, így bármikor egyszerűen elérhetjük. Természetesen más nevet is megadhatunk neki, de lustaságból én nem adok meg hosszabb nevet, minek annyit gépelni A Scanner osztálynak meghívjuk a konstruktorát, és odaadjuk neki a System.in bemenetet, ami alapértelmezetten a billentyűzet. Ettől kezdve az objektumunk a billentyűzetről fogja beolvasni az általunk megadott adatokat. A Scanner objektumnak meghívjuk a nextInt() metódusát, amely a begépelt és Enter billentyűvel lezárt adatbevitel esetén a begépelt számot azonnal eltárolja egy int típusú változóba. Lezárjuk a Scanner-t, miután már nincs rá szükségünk.



Több féle tipust is bekérhetünk


    String s = sc.nextLine();
    float f = sc.nextFloat();
    double d = sc.nextDouble();
    byte b = sc.nextByte();
    long l = sc.nextLong();



 Töltsünk fel egy 3x3 mátrixot véletlen számokkal és írassuk ki őket mátrix fromában a képernyőre.

static void Main(string[] args)

{

int[,] tm = new int[3,3];

int i, j ;

Random rnd = new Random();

for (i = 0; i < 3; i++)

{

for (j = 0; j < 3; j++)

{

tm[i,j] = rnd.Next(10,20);

Console.Write("{0} ",tm[i,j]);

}

Console.WriteLine();

}

Console.ReadLine();

}







http://www.petrik.hu/files/tamop/SZINFO13/SZINFO13_NYOMDA/SZINFO13_TJ/SZINFO13_TJ.pdf



Lottó



import java.util.*;

class lotto {
    public static void main(String args[]) {
 Random veletlen = new Random();   
        System.out.println("Lottó");
 int[] szamok  = new int[5];
 int szam;
 boolean van = false;
 int darab = 0;

 do {
  //Dobok egy számot:
  szam = veletlen.nextInt(90) + 1;

  //Megnézem van, már ilyen:
  for (int i=0; i<darab; i++)
      if(szamok[i] == szam)
   van = true;
  //Ha még nincs ilyen, akkor elteszem tömbbe
  if (!van) {  
   szamok[darab] = szam;
   darab++; 
  }
 }while(darab<5);  //Csak 5-öt szeretnék

 System.out.print("Lottó számok: ");
 for (int i=0; i<5; i++)
  System.out.print(szamok[i] + " ");
 System.out.println();
    }
}



Kérjkünk be számokat amíg nem lesz 0 rekurzívan:  


    import java.util.Scanner;

    

    class Program {  

        static void szamok() {

            Scanner input = new Scanner(System.in);  

            System.out.print("Szam: ");

            int szam = input.nextInt();

            input = null;

            if(szam != 0)

                szamok();

        }  

    

        public static void main(String args[]) {

            szamok();

        }

    }




 A következő példában megint számokat kérünk be 0 végjelig, de most eltároljuk egy vektorban: 



    import java.util.Scanner;
    import java.util.Vector;
     
    class Program3 { 
     static void szamok(Vector<Integer> szamok) {
      Scanner input = new Scanner(System.in); 
      System.out.print("Szam: ");
      int szam = input.nextInt();
      input = null;
      if(szam != 0) {
       szamok.add(szam);
       szamok(szamok);
      }
     }
     
     public static void main(String args[]) {
      Vector<Integer> szamok = new Vector<Integer>();
      szamok(szamok);
     
      for(Integer szam : szamok)
       System.out.print(szam + " ");
      System.out.println();
     }
    }

     

     Lista egy tömb tartalmáról lista tömbből


    Program01.java


        import java.util.List;

        import java.util.Arrays;

        class Program01 {

            public static void main(String args[]) {

                Integer[] t = {45, 37, 29, 82, 34, 56};

                List<Integer> v = Arrays.asList(t);

        

                for(Integer a : v)

                    System.out.println(a);       

            }

        }
    Maradékos osztás

    Maradékos osztás, a prímtényezős felbontáshoz hasonlóan, a folyamat ábrázolásával. 
Program01.java

    import java.util.Scanner;
    class Program01 {
     public static void main(String[] args) {
      Scanner in = new Scanner(System.in);
      System.out.println("Maradékos osztás a prímtényezős felbontáshoz hasonlóan.");
      System.out.println("Egy decimális szám konvertálása adott számrendszerre.");
     
      System.out.print("Szám: ");
      double szam = in.nextDouble();
      System.out.print("A számrendszer alapja: ");
      int alap = in.nextInt();  
     
      do{
       int hanyados = (int) szam / alap;
       int maradek = (int) szam % alap;
       System.out.printf("%10.0f|%d\n", szam, maradek);
       szam = hanyados;
      }while(szam > 0);
     }
    }









Sztring karaktertömbbé

Program01.java

    class Program01 {
     public static void main(String args[]) {
      String s = "alma";
      char[] t = new char[s.length()];
      t = s.toCharArray();
      for(char ch : t)
       System.out.println(ch);
     
     }
    }







 Tömb tartalmának kiírása képernyőre



public class ForDemo {
    public static void main(String[] args) {
        int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 };

        for (int i = 0; i < arrayOfInts.length; i++) {
            System.out.print(arrayOfInts[i] + " ");
        }
        System.out.println();
    }


Vezérlési szerkezetek


https://szit.hu/doku.php?id=oktatas:programoz%C3%A1s:java:java_megold%C3%A1sok&s[]=scanner

Ciklus tipusokra példa

Elől tesztelő ciklus

A while ciklus utasításblokk végrehajtására használható, amíg a feltétel igaz. A while ciklus szintaxisa:

while (feltétel) {
    utasítások
}

A while ciklus először kiértékeli a feltételt, amely művelet egy boolean értéket ad vissza. Ha a kifejezés értéke igaz, a while ciklus végrehajtja while blokkjában szereplő utasításokat. A while ciklus addig értékeli ki a kifejezést és hajtja végre az utasításblokkot, amíg a kifejezés hamis értékű nem lesz.

A következő WhileDemo nevű példaprogram a while ciklust használja fel, amely megvizsgálja a sztring karaktereit, hozzáfűzi a sztring minden karakterét a sztring puffer végéhez, amíg ’g’ betűvel nem találkozik.

public class WhileDemo {
    public static void main(String[] args) {

        String copyFromMe = "Copy this string until you " +
                            "encounter the letter 'g'.";
        StringBuffer copyToMe = new StringBuffer();

        int i = 0;
        char c = copyFromMe.charAt(i);

        while (c != 'g') {
            copyToMe.append(c);
            c = copyFromMe.charAt(++i);
        }
        System.out.println(copyToMe);
    }
}

Az érték, amelyet az utolsó sor ír ki:

Copy this strin
Hátul tesztelő ciklus

A Java nyelv egy a while ciklushoz hasonló utasítást is biztosít — a do-while ciklust. A do-while szintaxisa:

do {
    utasítás(ok)
} while (feltétel);

Ahelyett, hogy a feltételt a ciklus végrehajtása előtt értékelné ki, a do-while ezt a ciklusmag lefutása után teszi meg. Így a do-while magjában szereplő utasítások minimum egyszer végrehajtódnak.

Itt látható az előző program do-while ciklussal megvalósítva, ami a DoWhileDemo nevet kapta:

public class DoWhileDemo {
    public static void main(String[] args) {

        String copyFromMe = "Copy this string until you " +
                            "encounter the letter 'g'.";
        StringBuffer copyToMe = new StringBuffer();

        int i = 0;
        char c = copyFromMe.charAt(i);

        do {
            copyToMe.append(c);
            c = copyFromMe.charAt(++i);
        } while (c != 'g');
        System.out.println(scopyToMe);
    }
}


For ciklus

A for utasítás jó módszer egy értéktartomány bejárására. A for utasításnak van egy hagyományos formája, és a Java 5.0-tól kezdődően egy továbbfejlesztett formája is, amit tömbökön és gyűjteményeken való egyszerű bejárásnál használhatunk. A for utasítás általános formája a következőképpen néz ki:

for (inicializálás; feltétel; növekmény) {
    utastás(ok)
}

Az inicializálás egy olyan kifejezés, amely kezdőértéket ad a ciklusnak – ez egyszer, a ciklus elején fut le. A feltétel kifejezés azt határozza meg, hogy meddig kell a ciklust ismételni. Amikor a kifejezés hamisként értékelődik ki, a ciklus nem folytatódik. Végezetül a növekmény egy olyan kifejezés, amely minden ismétlődés után végrehajtódik a ciklusban. Mindezen összetevők opcionálisak. Tulajdonképpen ahhoz, hogy egy végtelen ciklust írjunk, elhagyjuk mindhárom kifejezést:

for ( ; ; ) {
    ...
}

A for ciklusokat gyakran arra használjuk, hogy egy tömb elemein vagy egy karakterláncon végezzünk iterációt. Az alábbi példa, ForDemo, egy for utasítást használ arra, hogy végighaladjon egy tömb elemein és kiírja őket.

public class ForDemo {
    public static void main(String[] args) {
        int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 };

        for (int i = 0; i < arrayOfInts.length; i++) {
            System.out.print(arrayOfInts[i] + " ");
        }
        System.out.println();
    }
}

If else

Az if utasítás lehetővé teszi a programunk számára, hogy valamilyen kritérium szerint kiválasztva futtasson más utasításokat. Például tegyük fel azt, hogy a programunk hibakereső (debugging) információkat ír ki egy DEBUG nevű, boolean típusú változó értéke alapján. Ha a DEBUG igaz, a program kiírja az információt, az x változó értékét. Különben a program futása normálisan folytatódik. Egy ilyen feladatot implementáló programrész a következőképpen nézhet ki:

if (DEBUG) {
    System.out.println("DEBUG: x = " + x);
}

Ez az if utasítás legegyszerűbb formája. Az if által vezérelt blokk végrehajtódik, ha a feltétel igaz. Általában az if egyszerű alakja így néz ki:

if (feltétel) {
    kifejezések
}

Mi van akkor, ha az utasítások más változatát akarjuk futtatni, ha a feltétel kifejezés hamis? Erre az else utasítást használhatjuk. Vegyünk egy másik példát. Tegyük fel azt, hogy a programunknak különböző műveleteket kell végrehajtania attól függően, hogy a felhasználó az OK gombot vagy más gombot nyom meg a figyelmeztető ablakban. A programunk képes lehet erre, ha egy if utasítást egy else utasítással együtt használunk.

if (response == OK) {
    //code to perform OK action
} else {
    //code to perform Cancel action
}

Az else blokk akkor kerül végrehajtásra, ha az if feltétele hamis. Az else utasítás egy másik formája az else if egy másik feltételen alapulva futtat egy utasítást. Egy if utasításnak lehet akárhány else if ága, de else csak egy. Az alábbi IfElseDemo program egy teszt pontszámot alapul véve egy osztályzatot határoz meg: 5-ös 90%-ért vagy afölött, 4-es 80%-ért vagy afölött és így tovább:

public class IfElseDemo {
    public static void main(String[] args) {
        int testscore = 76;
        int grade;
        if (testscore >= 90) {
            grade = 5;
        } else if (testscore >= 80) {
            grade = 4;
        } else if (testscore >= 70) {
            grade = 3;
        } else if (testscore >= 60) {
            grade = 2;
        } else {
            grade = 1;
        }
        System.out.println("Grade = " + grade);
    }
}

Switch alkalmazása

Akkor használhatjuk a switch utasítást, ha egy egész szám értéke alapján akarunk végrehajtani utasításokat. A következő SwitchDemo példaprogram egy month nevű egész típusú változót deklarál, melynek értéke vélhetőleg a hónapot reprezentálja egy dátumban. A program a switch utasítás használatával a hónap nevét jeleníti meg a month értéke alapján.

public class SwitchDemo {
    public static void main(String[] args) {
        int month = 8;
        switch (month) {
            case 1:  System.out.println("January"); break;
            case 2:  System.out.println("February"); break;
            case 3:  System.out.println("March"); break;
            case 4:  System.out.println("April"); break;
            case 5:  System.out.println("May"); break;
            case 6:  System.out.println("June"); break;
            case 7:  System.out.println("July"); break;
            case 8:  System.out.println("August"); break;
            case 9:  System.out.println("September"); break;
            case 10: System.out.println("October"); break;
            case 11: System.out.println("November"); break;
            case 12: System.out.println("December"); break;
            default: System.out.println("Not a month!");
                    break;
        }
    }
}

A switch utasítás kiértékeli kifejezést, ez esetben a month értékét, és lefuttatja a megfelelő case utasítást. Ezáltal a program futási eredménye az August lesz. Természetesen ezt az if utasítás felhasználásával is megoldhatjuk:

int month = 8;
if (month == 1) {
    System.out.println("January");
} else if (month == 2) {
    System.out.println("February");
}
...

Annak eldöntése, hogy az if vagy a switch utasítást használjuk, programozói stílus kérdése. Megbízhatósági és más tényezők figyelembevételével eldönthetjük, melyiket használjuk. Míg egy if utasítást használhatunk arra, hogy egy értékkészlet vagy egy feltétel alapján hozzunk döntéseket, addig a switch utasítás egy egész szám értéke alapján hoz döntést. Másrészt minden case értéknek egyedinek kell lennie, és a vizsgált értékek csak konstansok lehetnek.

Egy másik érdekesség a switch utasításban a minden case utáni break utasítás. Minden egyes break utasítás megszakítja az épp bezáródó switch utasítást, és a vezérlés szála a switch blokk utáni első utasításhoz kerül. A break utasítások szükségesek, mivel nélkülük a case utasítások értelmüket vesztenék. Vagyis egy explicit break nélkül a vezérlés folytatólagosan a rákövetkező case utasításra kerül (átcsorog). Az alábbi SwitchDemo2 példa azt illusztrálja, hogyan lehet hasznos, ha a case utasítások egymás után lefutnak.

public class SwitchDemo2 {
    public static void main(String[] args) {
        int month = 2;
        int year = 2000;
        int numDays = 0;
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                numDays = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                numDays = 30;
                break;
            case 2:
                if ( ((year % 4 == 0) && !(year % 100 == 0))
                     || (year % 400 == 0) )
                    numDays = 29;
                else
                    numDays = 28;
                break;
            default:
                numDays = 0;
                   break;
        }
        System.out.println("Number of Days = " + numDays);
    }
}



Kivételkezelő utasítások

A Java programozási nyelv egy kivételkezelésnek nevezett szolgáltatást nyújt, hogy segítse a programoknak a hibák felderítését és kezelését. Amikor egy hiba történik, a program „dob egy kivételt”. Ez azt jelenti, hogy a program normális végrehajtása megszakad, és megkísérel találni egy kivételkezelőt, vagyis egy olyan kódblokkot, ami a különféle típusú hibákat le tudja kezelni. A kivételkezelő blokk megkísérelheti a hiba kijavítását, vagy ha úgy tűnik, hogy a hiba visszaállíthatatlan, akkor szabályosan kilép a programból.

Alapvetően három utasítás játszik szerepet a kivételkezelésekben:

    a try utasítás tartalmaz egy utasítás blokkot, amiben a kivétel dobása elképzelhető
    a catch utasítás tartalmaz egy olyan utasításblokkot, ami le tudja kezelni az azonos típusú kivételeket. Az utasítások akkor hajtódnak végre, ha kivételtípus típusú kivétel váltódik ki a try blokkban
    a finally egy olyan utasítás blokkot tartalmaz, ami végrehajtódik akkor is, ha a try blokkban hiba történt, és akkor is, ha hiba nélkül futott le a kód.

Az utasítások általános alakja:

try {
    utasítás(ok)
} catch (kivételtípus kivételobjektum) {
    utasítás(ok)
} finally {
    utasítás(ok)
}

A kivételkezelés módszerének részletes ismertetésére később kerül sor.
Feltétel nélküli vezérlésátadás

A Java programnyelv háromféle feltétel nélküli vezérlésátadást támogat:

    a break utasítást
    a continue utasítást
    a return (visszatérés) utasítást

A break és a continue utasításokat használhatjuk címkével vagy anélkül. A címke egy azonosító, ami az utasítás előtt helyezkedik el. A címkét egy kettőspont (:) követi. A következő programrészletben láthatunk egy példát a címke alkalmazására:

statementName: someJavaStatement;

A break utasítás

A break utasításnak két alakja van: címke nélküli és címkés. A címke nélküli break utasítást korábban a switch-nél már használtuk. Ahol a címke nélküli break utasítással fejeztük be a sort, ott befejezi a switch utasítást, és átadja a vezérlést a switch után következő utasításnak. A címke nélküli break utasítás használható még a for, while vagy do-while ciklusokból való kilépésre is. A BreakDemo példaprogram tartalmaz egy for ciklust, ami egy bizonyos értéket keres egy tömbön belül:

public class BreakDemo {
    public static void main(String[] args) {
        int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 };
        int searchfor = 12;
        int i = 0;
        boolean foundIt = false;
        for ( ; i < arrayOfInts.length; i++) {
            if (arrayOfInts[i] == searchfor) {
                foundIt = true;
                break;
            }
        }
        if (foundIt) {
            System.out.println("Found " + searchfor + " at index " + i + '.');
        } else {
            System.out.println(searchfor + "not in the array");
        }
    }
}

Emeltszintű érettségi feladat

https://www.youtube.com/watch?v=sdenyQS0GR4&feature=youtu.be

using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace infagazatiemelt2017
{
class IdozitettFelirat
{
string idozites;
string felirat;
public string Felirat
{
get { return felirat; }
}
public IdozitettFelirat(string idozites, string felirat)
{
this.idozites = idozites;
this.felirat = felirat;
}
//rövidebb megoldás
public int SzavakSzama
{
get { return felirat.Split(' ').Length + 1; }
}
//általános megoldás
public int SzavakSzama2
{
get
{
int db = 1;
foreach (char item in felirat)
{
if (item == ' ') db++;
}
return db;
}
}
public string SrtIdozites()
{
string srtido = "";
srtido += ConverterMinSec_HMinSec(idozites.Split(' ')[0]) + " --> ";
srtido += ConverterMinSec_HMinSec(idozites.Split(' ')[2]);
return srtido;
}
private string ConverterMinSec_HMinSec(string ido)
{ //05:12 00:05:12
string srt = "0";
int min = int.Parse(ido.Split(':')[0]);
string sec = ido.Split(':')[1];
srt += min / 60 + ":";
if (min % 60 > 9)
srt += min % 60;
else
srt += "0" + min % 60;
srt += ":" + sec;
return srt;
}
}
class Program
{
static List<IdozitettFelirat> FeliratokLista = new List<IdozitettFelirat>();
static void SrtKiir(string fn)
{
StreamWriter sw = new StreamWriter(fn);
for (int i = 0; i < FeliratokLista.Count; i++)
{
sw.WriteLine(i + 1);
sw.WriteLine(FeliratokLista[i].SrtIdozites());
sw.WriteLine(FeliratokLista[i].Felirat);
sw.WriteLine();
}
sw.Flush();
sw.Close();
}
static void Beolvasas(string fn)
{
StreamReader sr = new StreamReader(fn);
while (!sr.EndOfStream)
{
FeliratokLista.Add(new IdozitettFelirat(sr.ReadLine(), sr.ReadLine()));
}
sr.Close();
}
static string LegtobbSzavas()
{
int legtobb_index = 0;
for (int i = 0; i < FeliratokLista.Count; i++)
{
if(FeliratokLista[i].SzavakSzama > FeliratokLista[legtobb_index].SzavakSzama)
{
legtobb_index = i;
}
}
return FeliratokLista[legtobb_index].Felirat;
}
static void Main(string[] args)
{
Beolvasas("feliratok.txt");
Console.WriteLine("5.feladat: Feliratok száma:" + FeliratokLista.Count);
Console.WriteLine("7.feladat: Legtöbb szavas felirat:\n" + LegtobbSzavas());
SrtKiir("felirat.srt");
Console.ReadKey();
}
}
}
using System;

http://info.berzsenyi.hu/programozas

import java.util.*;

class lotto {
    public static void main(String args[]) {
 Random veletlen = new Random();   
        System.out.println("Lottó");
 int[] szamok  = new int[5];
 int szam;
 boolean van = false;
 int darab = 0;

 do {
  //Dobok egy számot:
  szam = veletlen.nextInt(90) + 1;

  //Megnézem van, már ilyen:
  for (int i=0; i<darab; i++)
      if(szamok[i] == szam)
   van = true;
  //Ha még nincs ilyen, akkor elteszem tömbbe
  if (!van) {  
   szamok[darab] = szam;
   darab++; 
  }
 }while(darab<5);  //Csak 5-öt szeretnék

 System.out.print("Lottó számok: ");
 for (int i=0; i<5; i++)
  System.out.print(szamok[i] + " ");
 System.out.println();
    }
}
http://www.browxy.com/
Órai mintaprogramok

public class Veletlen3 {

 public static void main(String[] args) {
  int i,veletlen,n=5,min=1,max=90;

  System.out.println(n+" darab veletlen egesz szam a(z) ["+
                     min+","+max+"] intervallumbol:");
  for(i=1;i<=n;i++){
   veletlen=(int)(max*Math.random())+min; //típuskényszerítés (int)-re
   System.out.println(veletlen);
   }
  }

 }

-------------------
public class Veletlen {

 public static void main(String[] args) {
  int i,n=10;
  double szam;

  System.out.println(n+" darab veletlen szam a [0,1) intervallumbol:");
  for(i=0;i<n;i++){
   szam=Math.random(); //véletlen szám generálása
   System.out.println(szam);
   }
  }

 }

---------
public class ArrayOfIntegersDemo {
    public static void main(String[] args) {
        Integer[] anArray = new Integer[10];
        for (int i = 0; i < anArray.length; i++) {
            anArray[i] = new Integer(i);
            System.out.println(anArray[i]);
        }
    }
}
-------------
public class Szoroz extends Szamol {

 public Szoroz() {
  super("*");
  }

 public double muvelet(double x,double y) {
  return x*y;
  }

 public static void main(String[] args) {
  Szoroz p=new Szoroz();
  p.szamol(args);
  }
 }
---------
public class Szamok {

 public static void main(String[] args) {
  int i,n=10;

  System.out.println("Az elso "+n+" egesz szam:");
  for(i=1;i<=n;i++){
   System.out.println(i);
   }
  }

 }

----------
public class Osszeg {

 public static void main(String[] args) {
  int i,sum,n=10;

  System.out.print("Az elso "+n+" egesz szam osszegenek erteke: ");
  sum=0;
  for(i=1;i<=n;i++){
   sum+=i;
   }
  System.out.println(sum);
  }

 }

---------

public class Osszead extends Szamol {

 public Osszead() {
  super("+");
  }

 public double muvelet(double x,double y) {
  return x+y;
  }

 public static void main(String[] args) {
  Osszead p=new Osszead();
  p.szamol(args);
  }
 }
-------
public class Negyzet {

 public static void main(String[] args) {
  int i,n=10;

  System.out.println("Az elso 10 negyzetszam:");
  for(i=1;i<=n;i++){
   System.out.println(i+"*"+i+" = "+i*i);
   }
  }

 }
---------

public class Lotto {

 public static void main(String[] args) {
  int i,veletlen,n=5,min=1,max=90;

  System.out.println(n+" darab veletlen egesz szam a(z) ["+
                     min+","+max+"] intervallumbol:");
  for(i=1;i<=n;i++){
   veletlen=(int)(max*Math.random())+min; //típuskényszerítés (int)-re
   System.out.println(veletlen);
   }
  }

 }
----------


public class Szamok {

 public static void main(String[] args) {
  int i,n=10;

  System.out.println("Az elso "+n+" egesz szam:");
  for(i=1;i<=n;i++){
   System.out.println(i);
   }
  }

 }

---------

public class Fakt {

 public static void main(String[] args) {
  int i,n=10;
  long f; //bővebb értéktartomány

  f=1;
  for(i=2;i<=n;i++){
   f*=i;
   }
  System.out.println(n+" faktorialisanak erteke: "+f);
  }

 }


-------------


public class Fakt4 {

 public static void main(String[] args) {
  int i,j,sum,n=5;
  long f; //bővebb értéktartomány

  sum=0;
  f=1;
  j=1;
  for(i=1;i<=n;i++){
   sum+=j;
   f*=j;
   j+=2;
   }
  System.out.println("Az elso "+n+" paratlan szam osszegenek erteke: "+sum);
  System.out.println("Az elso "+n+" paratlan szam szorzatanak erteke: "+f);
  }

 }
--------------
public class Hatvany {

 public static void main(String[] args) {
  int i,n=10;
  double h=2.0,x;

  x=1.0; //h^0 (h nulladik hatványa)
  System.out.println(h+" elso 10 hatvanya:");
  for(i=0;i<n;i++){
   System.out.println(h+"^"+i+" = "+x);
   x*=h;
   }
  }

 }

----------
public class Negyzet {

 public static void main(String[] args) {
  int i,n=10;

  System.out.println("Az elso 10 negyzetszam:");
  for(i=1;i<=n;i++){
   System.out.println(i+"*"+i+" = "+i*i);
   }
  }

 }
public class Szamok {
 public static void main(String[] args) {
  int i,n=10;
  System.out.println("Az elso "+n+" egesz szam:");
  for(i=1;i<=n;i++){
   System.out.println(i);
   }
  }

 }

public class Osszeg2 {

 public static void main(String[] args) {
  int i,j,sum,n=10;

  System.out.print("Az elso "+n+" paratlan szam osszegenek erteke: ");
  sum=0;
  j=36;
  for(i=1;i<=n;i++){
   sum+=j;
  j+=3;
   }
  System.out.println(sum);
  }


 }


Összegzés

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
    
            int osszeg = 0;
            for(int i=0; i<7; i++)
                osszeg = osszeg + tomb[i];
    
            System.out.println(osszeg);
        }
    }

Megszámolás

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7;
            int szamlalo = 0;
            for(int i=0; i<n; i++)
                if(tomb[i] > 5)
                    szamlalo++;
    
            System.out.println(szamlalo);
        }
    }

Eldöntés tétel

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
            int ker = 2; //Amiről el szeretnénk dönteni, hogy van-e ilyen
    
            int i = 0;
            while(i<n && tomb[i] != ker)
                i++;
    
            if(i<n)
                System.out.println("Van ilyen szám.");
            else
                System.out.println("Nincs ilyen szám.");
        }
    }

Kiválasztás tétel

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
            int ker = 2; //Amiről szeretnénk tudni, hogy hányadik helyen van
    
            int i = 0;
            while(tomb[i] != ker)
                i++;
    
            System.out.printf("%d\n", i + 1);
        }
    }

Keresés tétel

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
            int ker = 2; //Amit keresünk
    
            int i = 0;
            while(i<n && tomb[i] != ker)
                i++;
    
            if(i<n) {
                            //Ha a kérdés az, hogy hányadik akkor i + 1 a vége
                            //ha a kérdés az, hogy mi az indexe, akkor csak i
                System.out.printf("Van ilyen a következő helyen: %d\n", i + 1);
    
            }else {
                System.out.println("Nincs ilyen elem");
                    }
        }
    }

Kiválogatás tétel

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] a = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
            int[] b = new int[n];
            int j=0;
            for(int i=0; i<n;i++)
                if(a[i] > 5)
                    b[j++] = a[i];
    
            int m = j; //A "b" tömb elemeinek száma
    
            //Első tömb kiíratva:
            for(int i=0; i<n;i++)
                System.out.print(a[i] + " ");
            System.out.println();
    
            //Második tömb kiíratva:
            for(int i=0; i<m;i++)
                System.out.print(b[i] + " ");
            System.out.println();
    
        }
    }

Szétválogatás tétel

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] a = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
            int[] b = new int[n];
            int[] c = new int[n];
    
            int j=0;
            int k=0;
            for(int i=0; i<n;i++)
                if(a[i] > 5)
                    b[j++] = a[i];
                else
                    c[k++] = a[i];
    
            int m = j; //A "b" tömb elemeinek száma
            int l = k; //A "c" tömb elemeinek száma
    
            //Első tömb kiíratva:
            for(int i=0; i<n;i++)
                System.out.print(a[i] + " ");
            System.out.println();
    
            //Második tömb kiíratva:
            for(int i=0; i<m;i++)
                System.out.print(b[i] + " ");
            System.out.println();
    
            //Harmadik tömb kiíratva:
            for(int i=0; i<l;i++)
                System.out.print(c[i] + " ");
            System.out.println();
    
        }
    }

Metszet tétel

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] a = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // Az első tömb elemeinek száma
            int[] b = {4, 7, 9, 8, 2};
            int m = 5; //A második tömb elemeinek száma
            int[] c = new int[n+m]; //A harmadik tömb
    
            int j;
            int k = 0;
            for(int i=0; i<n;i++)
            {
                j = 0;
                while(j<m && b[j] != a[i])
                    j++;
                if(j<m)
                {
                    c[k] = a[i];
                    k++;
                }
            }
    
            int l = k; //A "c" tömb elemeinek száma
    
            //Első tömb kiíratva:
            for(int i=0; i<n;i++)
                System.out.print(a[i] + " ");
            System.out.println();
    
            //Második tömb kiíratva:
            for(int i=0; i<m;i++)
                System.out.print(b[i] + " ");
            System.out.println();
    
            //Harmadik tömb kiíratva:
            for(int i=0; i<l;i++)
                System.out.print(c[i] + " ");
            System.out.println();
    
        }
    }

Unió tétel

Program.java

    /* Unió tétel */
    class Program7
    {
        public static void main(String[] argv)
        {       
            int[] a = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // Az első tömb elemeinek száma
            int[] b = {4, 7, 9, 8, 2};
            int m = 5; //A második tömb elemeinek száma
            int[] c = new int[n+m]; //A harmadik tömb
    
            for(int i=0; i<n; i++)
                c[i] = a[i];
    
            int k = n-1;
    
            for(int j=0; j<m;j++)
            {
                int i = 0;
                while(i<n && a[i] != b[j])
                    i++;
                if(i>=n)
                {
                    k++;
                    c[k] = b[j];   
                }
            }
    
            int l = k + 1; //A "c" tömb elemeinek száma
    
            //Első tömb kiíratva:
            for(int i=0; i<n;i++)
                System.out.print(a[i] + " ");
            System.out.println();
    
            //Második tömb kiíratva:
            for(int i=0; i<m;i++)
                System.out.print(b[i] + " ");
            System.out.println();
    
            //Harmadik tömb kiíratva:
            for(int i=0; i<l;i++)
                System.out.print(c[i] + " ");
            System.out.println();
    
        }
    }

Maximum kiválasztás tétele

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
    
            int max = 0;
    
            for(int i=0; i<n;i++)
                if(tomb[i] > max)
                    max = tomb[i];
    
            System.out.println("Legnagyobb: " + max);
    
        }
    }

Minimumkiválasztás tétele

Program.java

    class Program
    {
        public static void main(String[] argv)
        {       
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
    
            int min = tomb[0];
    
            for(int i=0; i<n;i++)
                if(tomb[i] < min)
                    min = tomb[i];
    
            System.out.println("Legkisebb: " + min);
    
        }
    }

Rendezések
Buborék rendezés

Program.java

    /* Buborék rendezés */
    class Program
    {
        public static void main(String args[])
        {
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
    
            for(int i= n-1; i>0; i--)
                for(int j=0; j<i; j++)
                    if(tomb[j] > tomb[j+1])
                    {
                        int tmp = tomb[j];
                        tomb[j] = tomb[j+1];
                        tomb[j+1] = tmp;
                    }
    
            for(int i=0; i<n; i++)
                System.out.print(tomb[i] + " ");
            System.out.println();
        }
    }

Vagy:

Program.java

    /* Buborék rendezés */
    class Program
    {
        public static void main(String args[])
        {
            int[] tomb = {3, 8, 2, 4, 5, 1, 6};
            int n = 7; // A tömb elemeinek száma
    
            for(int i= n-2; i>0; i--)
                for(int j=0; j<=i; j++)
                    if(tomb[j] > tomb[j+1])
                    {
                        int tmp = tomb[j];
                        tomb[j] = tomb[j+1];
                        tomb[j+1] = tmp;
                    }
    
            for(int i=0; i<n; i++)
                System.out.print(tomb[i] + " ");
            System.out.println();
        }
    }

Utóbbi különbsége: mettől-meddig megyünk a ciklusban.
Beszúrásos rendezés

Rekurzív megvalósítás:

Program01.java

    package rendezesbeszurassal;
    
    public class RendezesBeszurassal {
    
        static void rendezesBeszurassalR(int[] t, int n) {       
            if(n>0) { // eredeti: n>1
                rendezesBeszurassal(t, n-1);
                int x = t[n-1]; // eredeti: t[n]
                int j = n-2; // eredeti: n-1
                while(j>= 0 && t[j]>x) {
                    t[j+1] = t[j];
                    j = j-1;
                }
                t[j+1] = x;
            }
        }
        static void kiir(int[] t) {
            for (int i = 0; i < t.length; i++) {
                System.out.print(t[i]+" ");
            }
            System.out.println();
        }
    
        public static void main(String[] args) {
            int[] t = {35, 24, 83, 12, 7, 23};
            rendezesBeszurassalR(t, t.length);
            kiir(t);
        }
    
    }

Normál megvalósítás:

    static void rendezesBeszurassal(int[] t) {
        for (int i = 0; i < t.length; i++) {  //eredeti: i=1
            int x = t[i];
            int j = i - 1;
            while(j>=0 && t[j]>x) {
                t[j+1] = t[j];
                j = j - 1;
            }
            t[j+1] = x;
        }
    }

A megjegyzések azokra a tömbökre utalnak, ahol a kezdőérték 1.
Gyorsrendezés

Program.java

    class Program
    {
        static void gyors(int[] tomb, int bal, int jobb)
        {
            if(bal < jobb)
            {
                int also = bal, felso = jobb + 1, kulcs = tomb[bal];
                for( ; ; )
                {
                    while(++also < felso && tomb[also] < kulcs)
                        ;
                    while(tomb[--felso] > kulcs)
                        ;
                    if(also >= felso)
                        break;
                    csere(tomb, also, felso);
                }   
                csere(tomb, felso, bal);
                gyors(tomb, bal, felso -1);
                gyors(tomb, felso+1, jobb);           
            }
        }
    
        static void csere(int[] tomb, int i, int j)
        {
            int seged = tomb[i];
            tomb[i] = tomb[j];
            tomb[j] = seged;
        }
    
        public static void main(String args[])
        {
            int[] tomb = {8, 5, 2, 9, 4, 3, 1, 6};
            int meret = 8;
    
            gyors(tomb, 0, 7);
    
            for(int i=0; i<meret; i++)
                System.out.print(tomb[i] + " ");
            System.out.println();
        }
    }

Program01.java

    import java.util.ArrayList;
    import java.util.Arrays;
    
    
    public class Program01 {
        static ArrayList<Integer> quicksort(ArrayList<Integer> list) {
            if (list.size() <= 1) {
                return list;
            }
            ArrayList<Integer> less = new ArrayList<>();
            ArrayList<Integer> equal = new ArrayList<>();
            ArrayList<Integer> greater = new ArrayList<>();
            int pivot = list.get(list.size()-1);
            for (Integer x : list) {
                if (x < pivot) less.add(x);
                if (x == pivot) equal.add(x);
                if (x > pivot) greater.add(x);
            }       
            ArrayList<Integer> sumList = new ArrayList<Integer>();
            sumList.addAll(quicksort(less));
            sumList.addAll(equal);
            sumList.addAll(quicksort(greater));       
            return sumList;
        }
    
        static void kiirLista(ArrayList<Integer> list) {
            for(Integer x : list) {
                System.out.print(x + " ");
            }
            System.out.println();
        }
    
        public static void main(String[] args) {
            Integer[] t = {8, 2, 7, 9, 5, 4, 3};
            ArrayList<Integer> list = new ArrayList<>(Arrays.asList(t));
            list = quicksort(list);
            kiirLista(list);
        }
    }

Program01.java

    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class Program01 {
    
        static void quicksort(ArrayList<Integer> list, int lo, int hi) {
            if(lo < hi) {
                int p = partition(list, lo, hi);
                quicksort(list, lo, p-1);
                quicksort(list, p+1, hi);
            }
        }
        static int partition(ArrayList<Integer> list, int lo, int hi) {
            int pivot = list.get(hi);
            int i = lo -1;
            for (int j = lo; j < hi; j++) {
                if(list.get(j)<= pivot) {
                    i++;
                    swap(list, i, j);
                }
            }
            swap(list, i+1, hi);
            return i + 1;
        }
        static void swap(ArrayList<Integer> list, int i, int j) {
            int tmp = list.get(i);
            list.set(i, list.get(j));
            list.set(j, tmp);
        }
        static void kiir(ArrayList<Integer> list) {
            for(Integer x : list) {
                System.out.print(x + " ");
            }
            System.out.println();
        }
        public static void main(String[] args) {
            Integer[] t = {8, 2, 7, 3, 4, 9};
            ArrayList<Integer> list = new ArrayList<>(Arrays.asList(t));
            quicksort(list, 0, list.size()-1);
            kiir(list);
        }
    
    }

Shell rendezés

Program.java

    class Program
    {
        public static void main(String args[])
        {
            int[] tomb = {8, 5, 2, 9, 4, 3, 1, 6};
            int[] leptomb = {5, 3, 1};
    
            int meret = 8;
    
            for(int k = 0; k< 3; k++)
            {
                int lepeskoz = leptomb[k];
                for(int j = lepeskoz; j < meret; j++)
                {
                    int i = j - lepeskoz;
                    int kulcs = tomb[j];
                    while(i>=0 && tomb[i] > kulcs)
                    {
                        tomb[i + lepeskoz] = tomb[i];
                        i = i - lepeskoz;
                    }
                    tomb[i + lepeskoz] = kulcs;
                }
            }
    
            for(int i=0; i<meret; i++)
                System.out.print(tomb[i] + " ");
            System.out.println();
        }
    }

Összefuttatás
Összefuttatás, összefésülés

Program01.java

    class Program01{
        public static void main(String[] args) {
            int[] a = { 1, 3, 5, 7, 9};
            int[] b = {2, 4, 6, 8 };
    
            int[] c = new int[a.length+b.length];
    
            int n = a.length;
            int m = b.length;
    
            int i = 0;
            int j = 0;
            int k = -1;
            while(i<n && j<m) {
                k++;
                if(a[i]<b[j]) {
                    c[k] = a[i];
                    i++;
                }else if(a[i] == b[j]) {
                    c[k] = a[i];
                    i++;
                    j++;               
                }else if(a[i] > b[j]) {
                    c[k] = b[j];
                    j++;
                }
            }
            while(i<n) {
                k++;
                c[k] = a[i];
                i++;
            }
            while(j<m) {
                k++;
                c[k] = b[j];
                j++;
            }
    
            kiir(c, k);
    
        }
        public static void kiir(int[] tomb, int meret) {       
            for (int i = 0; i < meret + 1; i++) {           
                System.out.println(tomb[i]);
            }       
        }

Keresés rendezett tömbben
Logaritmikus keresés

Program01.java

    public class Program01 {
        public static void main(String[] args) {
    
            int[] t={3, 4, 6, 8, 18, 50, 52, 61, 68, 70};   
    
            int n = t.length;       
    
            int e = 0;
            int u = n-1;
            int k;
            int ker = 52;
            do {
                k = (e+u) / 2;
                if(ker<t[k]) u = k-1;
                if(ker>t[k]) e = k+1;
            }while(e<=u && t[k]!=ker);
            boolean van = e<=u;
            int index = 0;
    
            if(van) {           
                index = k;
            }
            System.out.printf("%s %d\n", van, index);
    
        }
    }