Jelenlegi hely

6.5. Vezérlésátadó utasítások

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");
        }
    }
}

A break utasítás befejezi a for ciklust, ha megvan az érték. A vezérlés átadódik a for lezárása után lévő utasításnak, ami a print utasítást tartalmazó if a program végén.

A program kimenete:

Found 12 at index 4.

Megjegyzés: A for ciklusból break-kel való kilépést sokszor használjuk egy adott érték keresése érdekében. Érdemes megfigyelni, hogy ekkor a ciklus után meg kell állapítani (if utasítás), hogy miért is fejeződött be a ciklus: a találat miatt, vagy mert a végére értünk.

A break utasítás címke nélküli alakját használhatjuk a legbelső switch, for, while vagy do-while befejezésére. A címkézett alak befejez egy olyan külső utasítást, ami a break címkéje által van azonosítva. Másként fogalmazva: egyszerre több utasításból is képes kiugrani. A következő (BreakWithLabelDemo) program hasonló az előzőhöz, de itt kétdimenziós tömbben keressük az értéket. Kettő egymásba ágyazott for ciklus vizsgálja át a tömböt. Amikor az érték megvan, egy címkézett break befejezi a search-ként címkézett utasítást, ami a külső for ciklus:

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

A program kimenete:

Found 12 at 1, 0.

Ez a szintaxis egy kicsit zavaró lehet. A break utasítás befejezi a címkézett utasítást, és nem a címkének adja át a vezérlést. A vezérlés annak az utasításnak adódik át, ami közvetlen a (befejezett) címkézett utasítás után van.

A continue utasítás

A continue utasítás arra használható, hogy átugorjuk a ciklusmag hátralevő részét egy for, while vagy do-while ciklusnak. A címke nélküli alakja átugrik a legbelső ciklusmag végére és kiértékeli a logikai kifejezés értékét, ami a ciklust vezérli. A következő ContinueDemo program végigfut egy StringBuffer-en, megvizsgálva az összes betűt. Ha a vizsgált karakter nem ’p’, a continue utasítás átugorja a ciklus hátralevő részét és vizsgálja a következő karaktert. Ha ez egy ’p’, a program megnöveli a számláló értékét és átalakítja a ’p’-t nagybetűssé.

public class ContinueDemo {
    public static void main(String[] args) {
        StringBuffer searchMe = new StringBuffer(
            "peter piper picked a peck of pickled peppers");
        int max = searchMe.length();
        int numPs = 0;
        for (int i = 0; i < max; i++) {
            //interested only in p's
            if (searchMe.charAt(i) != 'p')
                continue;
            //process p's
            numPs++;
            searchMe.setCharAt(i, 'P');
        }
        System.out.println("Found " + numPs + " p's in the string.");
        System.out.println(searchMe);
    }
}

Ennek a programnak a kimenete:

Found 9 p's in the string.
Peter PiPer Picked a Peck of Pickled PePPers

A continue utasítás címkés alakja átugorja a címkézett ciklus ciklusmagjának hátralevő részét. A következő ContinueWithLabelDemo példaprogram egymásba ágyazott ciklusokat használ egy szövegrész keresésére egy másik szövegben. Két egymásba ágyazott ciklus szükséges: egy, hogy ismételje a szövegrészt, és egy, hogy addig ismételje, amíg át nem vizsgálta a szöveget. Ez a program a continue címkézett alakját használja, hogy átugorjon egy ismétlést a külső ciklusban:

public class ContinueWithLabelDemo {
    public static void main(String[] args) {
        String searchMe = "Look for a substring in me";
        String substring = "sub";
        boolean foundIt = false;
        int max = searchMe.length() - substring.length();
    test:
        for (int i = 0; i <= max; i++) {
            int n = substring.length();
            int j = i;
            int k = 0;
            while (n-- != 0) {
                if (searchMe.charAt(j++)
                        != substring.charAt(k++)) {
                    continue test;
                }
            }
            foundIt = true;
                    break test;
        }
        System.out.println(foundIt ? "Found it" : "Didn't find it");
    }
}

Ennek a programnak a kimenete:

Found it

Megjegyezés: Ahogy a korábbi példából is láthatjuk, a címke nélküli continue mindig kiváltható a ciklus átszervezésével, ilyen esetben ritkán is alkalmazzuk.

A return (visszatérés) utasítás

Ez az utasítás az utolsó a feltétlen vezérlésátadó utasítások közül. A return-t az aktuális metódusból vagy konstruktorból való kilépésre használjuk. A vezérlés visszaadódik annak az utasításnak, ami az eredeti hívást követi. A return utasításnak két formája van: ami visszaad értéket, és ami nem. Hogy visszatérjen egy érték, egyszerűen tegyük az értéket (vagy egy kifejezést, ami kiszámítja azt) a return kulcsszó után:

return ++count;

A visszaadott érték adattípusa meg kell, hogy egyezzen a függvényben deklarált visszatérési érték típusával. Ha a függvényt void-nak deklaráltuk, használjuk a return azon alakját, ami nem ad vissza értéket:

return;