Gyakorlati alapok II.

Néhány tipikus probléma

 

Nullával való osztás

Negatív szám négyzetgyöke

Tömbindex túllépése

Rossz adatkonverzió

Üres referencia

Null referencia

 

Ebben a fejezetben okulásul megnézünk néhány olyan tipikus programozási hibát, amelyet garantáltan a programozó követ el.

 

Nullával való osztás

 

Ez a durva programozási hiba már ismertetésre került az előző fejezetben:

 

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

 

 

 

 

 

 

 

 

public class Main {
    public static void main(String[] args) {
    System.out.println(4 / 0);
    }
}

 

Végeredmény:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:152)

 

Az olvashatóság és a továbbiak érdekében egy kicsit manikűrözzük ki a kódot, bár funkcionálisan ugyanaz lesz:

 

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

 

 

 

 

 

 

 

 

public class Main {
    public static void main(String[] args) {
    int a = 4;
    int b = 0;
    double c = a / b;
    System.out.println(c);
    }
}

 

Végeredmény:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:152)

 

Negatív szám négyzetgyöke

 

A negatív számoknak nincs négyzetgyökük, a művelet rajtuk matematikailag nem értelmezhető:

 

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

 

 

 

 

 

 

 

 

import java.math.*;

public class Main {
    public static void main(String[] args) {
    double szam = -1;
    System.out.println(Math.sqrt(szam));
    }
}

 

Végeredmény:

NaN

 

Valójában nem generáltunk kivételt, mert már maga a művelet alkalmazása is hiba. Ezen okból csupán egy szabványos üzenet kapunk:

 

NaN - Not a Number - nem szám

 

Tömbindex túllépése

 

Ezt a hibát többféleképpen is el tudjuk követni. A hiba lényege, hogy nem egyezik az előzetesen deklarált tömbméret és (bármilyen jellegű) tömbművelet iterálásának (tipikusan a for ciklus) hossza.

Az alábbi futtatható Java-kódban a for ciklusban +1 értékkel futunk túl a tömbméreten, még pontosabban: a tömbelem-indexelésen:

 

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

 

 

 

 

 

 

 

 

public class Main {
public static void main(String[] args) {
    int[] tomb = new int[]{0, 1, 2, 3, 4};
    for(int i = 0; i <= tomb.length; i++){
        System.out.println(tomb[i]);
        }
    }
}

 

Végeredmény:

0
1
2
3
4
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at Main.main(Main.java:5)

 

Ezzel a deklarációval azonban már jó lesz:

 

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

 

 

 

 

 

 

 

 

public class Main {
public static void main(String[] args) {
    int[] tomb = new int[]{0, 1, 2, 3, 4};
    for(int i = 0; i < tomb.length; i++){
        System.out.println(tomb[i]);
        }
    }
}

 

Végeredmény:

0
1
2
3
4

 

Vagy:

 

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

 

 

 

 

 

 

 

 

public class Main {
public static void main(String[] args) {
    int[] tomb = new int[]{0, 1, 2, 3, 4};
    for(int i = 0; i <= tomb.length-1; i++){
        System.out.println(tomb[i]);
        }
    }
}

 

Végeredmény:

0
1
2
3
4

 

Rossz adatkonverzió

 

Tipikus hiba a String adattípus és a numerikus adattípusok (Numerikus egész és Numerikus lebegőpontos) közti átváltáskor, konvertáláskor szokott előfordulni. Itt is többféle hibalehetőségből válogathatunk. Az egyik leggyakoribb, hogy összekeverjük a tizedespontot (.) és a tizedesvesszőt (,). A hétköznapi életben valóban keverve használjuk őket, de a Java-béli Double.parseDouble() függvény és hasonló funkciójú testvérei csakis tizedespontot hajlandók fogadni. Az alábbi futtatható Java-kódban a 3,14 értékű szamString még gond nélkül ki lesz írva a konzolra, de a konvertáló függvény már dob egy NumberFormatException kivételt:

 

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

 

 

 

 

 

 

 

 

public class Main {
public static void main(String[] args) {
    String szamString = "3,14";
    System.out.println(szamString);
    double PI = Double.parseDouble(szamString);
    }
}

 

Végeredmény:

3,14
Exception in thread "main" java.lang.NumberFormatException: For input string: "3,14"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at Main.main(Main.java:5)

 

A tizedespont használata már sokat javít az összképen:

 

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

 

 

 

 

 

 

 

 

public class Main {
public static void main(String[] args) {
    String szamString = "3.14";
    System.out.println(szamString);
    double PI = Double.parseDouble(szamString);
    System.out.println(PI);
    }
}

 

Végeredmény:

3.14

3.14

 

Üres referencia

 

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

 

Elméletileg üres referencia olyankor keletkezik, ha változót nem inicializáltunk, azaz nem adtunk neki kezdőértéket. A manapság elterjedt fejlesztési eszközök azonban már egyre magasabb szintű automatikával képesek ezt a hibát detektálni. Így tesz az Eclipse is: a változó pontatlan létrehozásakor már valós időben visítozik és jól érthető hibaüzeneteket küld (a kurzort a sor melletti x fölé pozícionálva a következő szöveggel szembesülünk: The local variable nev may not have been initialized - a nev változó nem lett inicializálva):

 

www.informatika-programozas.hu

 

A kód erőltetett futtatásakor azonnal ugyanilyen jellegű kivétellel szembesülünk:

 

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

 

 

 

 

 

 

 

 

public class Main {
public static void main(String[] args){
    String nev;
    System.out.println(nev);
    }
}

 

Végeredmény:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The local variable nev may not have been initialized at Main.main(Main.java:4)

 

A may not have been initialized üzenet mindenkor és mindenképpen a megfelelő inicializálás hiányára utal.

 

További érdekesség, hogy a keletkezett hibát a JVM Error-nak minősíti, ez azonban felvet egy érdekes kvízkérdést: egy másik, régebben keletkezett példakódban viszont még RuntimeException kivétel keletkezik.

 

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

 

Vajon ez a fejlesztői felületek (NetBeans és Eclipse) vagy a Java-verziók különbözősége miatt alakult így?

 

Null referencia

 

A null referencia azt jelenti, hogy a hivatkozás mögött nincs értelmezhető adattartalom, vagy az adattartalom 0 (illetve null), amely alapjában véve nem probléma egyszerű adattípusok esetében, de néhány speciális és komplex adatszerkezetnél már komoly fennakadásokat okoz. Egy ilyet láthatunk az alábbi, NullPointerException kivételt generáló Java-kódban, hiszen a létrehozott o objektum lényegében üres, ezért nincs alaposztálya sem (amely információt a getClass() metódussal próbálnánk elérni):

 

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

 

 

 

 

 

 

 

 

public class Main {
public static void main(String[] args){
    Object o = null;
    System.out.println(o.getClass());
    }
}

 

Végeredmény:

Exception in thread "main" java.lang.NullPointerException

at Main.main(Main.java:11)