Gyakorlati alapok II.

Külön függvény

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

A függvény olyan metódus, amelynek van adott típusú kimeneti értéke (return), ellentétben az eljárással, amelynek nincs (void), de az utóbbi kijelentést  pontosítjuk a következő, Eljárás + return című fejezetben.

 

A függvény voltaképpen egy, a külvilág felé zárt feldolgozó egység, amely általunk beadott bemeneti adatokból belső programja szerint gyárt 1 db kimeneti adatot (összetett típus esetén lehet ez sok darab is, amelyek egyetlen komplex adatszerkezetbe, például tömbbe vannak zárva).

 

Az alábbi NEM futtatható Java-kódban egy százalékszámító metódus 3 bemeneti paramétert vár (double szazSzazalek, int szazalek, String irany), amelyből 1 db kimeneti adatot állít elő (return eredmeny). Ez az előre gyártott kód bármelyik projektbe megfelelően beillesztve azonnal képes százalékszámításra (ezt majd alább tapasztalni fogjuk):

 

public double szazalekSzamitas(double szazSzazalek, int szazalek, String irany){
    double eredmeny = 0;
    double egySzazalek = szazSzazalek / 100;
    switch(irany){
        case "+": eredmeny = szazSzazalek + (egySzazalek * szazalek); break;
        case "-": eredmeny = szazSzazalek - (egySzazalek * szazalek); break;
        default: System.out.println("Rossz műveleti jel!");
        }
     return eredmeny;
}

 

Először ismétlésképpen nézzünk meg egy eljárást:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {


    public static void hibaUzenet(){
        System.out.println("Ez egy hibaüzenet!");
    }

    public static void main(String[] args) {
        hibaUzenet();
    }
}

 

Végeredmény:

Ez egy hibaüzenet!

 

Jól láthatjuk, hogy nincs visszatérési értéke (return), azaz típusa void, egyetlen célja valamilyen feladat elvégzése, itt egy hibaüzenet kiírása.

 

Most pedig nézzünk meg egy egyszerű függvényt. Az alábbi futtatható Java-kód egy számot (2 - ez a bemeneti adat) kétszerez meg külön függvényben (szamKetszerezes(int bemenetiAdat)):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {
    public static int szamKetszerezes(int bemenetiAdat){
        return bemenetiAdat * 2;
    }

    public static void main(String[] args) {
        System.out.println(szamKetszerezes(2));
    }
}

 

Végeredmény:

4

 

Nagyon fontos tanulságaink vannak, ezek részben egyeznek az eljárásnál tapasztaltakkal:

Egy kicsit időzzünk még a függvények típusegyezésének problémájánál! Fontossága miatt ismételjük meg az egyik megállapítást:

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

A függvény fejlécében mindig előre kell jelezni, hogy milyen típusú kimeneti adatot fog szolgáltatni (itt int).

 

public static int szamKetszerezes(int bemenetiAdat)

 

Ez azt mutatja meg, hogy milyen típusú lesz a függvény kimeneti értéke (return). Ha ez nem történik meg, vagy a típusok valamilyen módon nem egyeznek, akkor hibaüzenetet kapunk, vagy a függvény hibás eredményt szolgáltat!

 

A probléma szemléltetésére gyártsunk egy, a típusegyezésben garantáltan hibás függvényt: most kétszerezés helyett harmadolja a bemeneti adatot (itt: 2). Tehát a következő matematikai művelet kerül végrehajtásra:

 

2 / 3 = 0.666...

 

Az osztás eredménye nyilvánvalóan nem lesz egész szám:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {
    public static int szamHarmadolas(int bemenetiAdat){
        return bemenetiAdat / 3;
    }

    public static void main(String[] args) {
        System.out.println(szamHarmadolas(2));
    }
}

 

Végeredmény:

0 (rossz!)

 

A fordító ugyan nem visítozik, ám a végeredmény mégis rossz, mert int típus nem tud nem egész, azaz lebegőpontos számot tárolni (például 0.66, ezért mutat 0-t). A végeredmény valójában csonkolódik. A megoldás a bemeneti és kimeneti adatok típusainak összehangolása. Nézzük meg, hogy hol van típusdeklaráció, 2 helyen a külső függvény fejlécében:

 

public static int szamHarmadolas(int bemenetiAdat)

 

A korrekt eredményhez a bemeneti adat típusát (bemenetiAdat) és a kimeneti adat típusát (a függvény deklarált típusa, vele a return értékét) azonosra kell állítanunk. Mivel osztás végeredménye legtöbbször nem egész szám, válasszuk a double típust, amely köztudottan a lebegőpontos számok tárolására szolgál (Numerikus lebegőpontos című fejezet):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {
    public static double szamHarmadolas(double bemenetiAdat){
        return bemenetiAdat / 3;
    }

    public static void main(String[] args) {
        System.out.println(szamHarmadolas(2));
    }
}

 

Végeredmény:

0.6666666666666666

 

Természetesen a típusegyezéseken felül a konkrét bemeneti adatnak is típuskorrektnek kell lennie, hiszen nem sokat érünk például az alábbi értékadással (a):

 

public class Main {
    public static double szamHarmadolas(double bemenetiAdat){
        return bemenetiAdat / 3;
    }

    public static void main(String[] args) {
        System.out.println(szamHarmadolas(a));
    }
}

 

Ilyen esetekben szavatoltan hibaüzeneteket kapunk:

 

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
a cannot be resolved at Main.main(Main.java:7)

 

A megszerzett tudás birtokában most már az eredetileg önmagában nem működő százalékszámításos függvényünk is működőképes lesz:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {
    public static double szazalekSzamitas(double szazSzazalek, int szazalek, String irany){
        double eredmeny = 0;
        double egySzazalek = szazSzazalek / 100;
        switch(irany){
            case "+": eredmeny = szazSzazalek + (egySzazalek * szazalek); break;
            case "-": eredmeny = szazSzazalek - (egySzazalek * szazalek); break;
            default: System.out.println("Rossz műveleti jel!");
        }
    return eredmeny;
    }

    public static void main(String[] args) {
        System.out.println(szazalekSzamitas(100, 25, "+"));
    }
}

 

Végeredmény:

125.0

 

Láthatjuk, hogy hol adtuk meg a bemeneti adatokat: a System.out.println() függvényben, hiszen a százalékszámító függvény hívása ezen függvény paraméterlistájában történik (System.out.println(szazalekSzamitas(100, 25, "+");). A 100, 25, "+" bemeneti paraméterek azt jelentik, hogy a függvény számolja ki 100-nak 25%-át, majd adja hozzá és ez az összeg lesz a függvény egyetlen kimeneti adata (125.0). Mindezt azért sikerült ilyen közvetlenül elérnünk, mert a System.out.println() úgy van programozva, hogy képes bemeneti paraméterként fogadni teljes függvényeket, illetve vegyük észre, hogy képes azonnal megjeleníteni a kimeneti adatot is.

 

Ám a bemeneti adatok megadását "közvetetten" is meg tudjuk tenni: ekkor nem bízunk semmit a System.out.println() függvényre és egyéb programautomatikára, hanem "külsőleg", kézzel oldjuk meg a deklarációkat:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

public class Main {
    public static double szazalekSzamitas(double szazSzazalek, int szazalek, String irany){
        double eredmeny = 0;
        double egySzazalek = szazSzazalek / 100;
        switch(irany){
            case "+": eredmeny = szazSzazalek + (egySzazalek * szazalek); break;
            case "-": eredmeny = szazSzazalek - (egySzazalek * szazalek); break;
            default: System.out.println("Rossz műveleti jel!");
        }
    return eredmeny;
    }

    public static void main(String[] args) {
        double szazSzazalek = 50;
        int szazalek = 10;
        String irany = "-";
        double eredmeny = szazalekSzamitas(szazSzazalek, szazalek, irany);
        System.out.println(eredmeny);
    }
}

 

Végeredmény:

45.0

 

A kód legfontosabb tanulsága, ahogy a százalékszámító függvény kimeneti adatának tartalmát átveszi egy ugyanolyan típusú változó (double eredmeny):

 

double eredmeny = szazalekSzamitas(szazSzazalek, szazalek, irany);
       

Mivel a 2 függvény viszonylag független egymástól, alapjában véve használhatunk azonos elnevezéseket is, bár nagyobb projekt esetén ebből hamar zavar keletkezhet. Gondoljunk csak arra, hogyha a százalékszámítás konkrét, mondjuk egy pénzügyi művelet implementációja, ráadásul a bemeneti adatokat felhasználók gépelik be mondjuk néhány 100 kilométerrel távolabb, akkor az általános programozási protokollok szerint a 2 függvény fizikai távolságban és programozás-technikailag is igen távol eshet egymástól.

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

Egy programozási módszertanban azonban -ahol mindennél sokkal fontosabb a kódok egymásra ható működésének megértése-, az azonos elnevezés módszertanilag hasznos, ezért járható út. A továbbiakban -ameddig lehetséges-, ezt az elvet követjük.

 

A százalékszámító és a System.out.println() függvény közt észrevehetünk egy további fontos különbséget: az előbbi kizárólag 3 adott típusú bemeneti adatot képes fogadni, minden más bemeneti adat hibaüzenetet fog generálni. Ugyanakkor a System.out.println() függvény paraméterlistája rendkívül sokféle kód és kódszerkezet befogadására és futtatására képes; ez voltaképpen csak a függvény leprogramozásának kérdése. Erről meggyőződhetünk, ha átolvassuk az Írjunk ki a konzolra mindenfélét a System.out.println() függvénnyel! című fejezetet.