Dolgozz keveset, nem ér baleset - tartja a mondás, s igaz ez a Java programozókra is, hiszen ha dolgozunk, közben hibákat is vétünk, de nem mindegy milyen hibákat. David Reilly csokorba szedte a leggyakoribb programozói hibákat, lássuk a Top10 listát.

10. Nem statikus tagot akarunk elérni statikus metódusból

A Java programozásban eleinte furcsa lehet a statikus és a nem statikus (példányosított) változók és metódusok megkülönböztetése. A statikusnak jelölt részek nem igényelnek példányosítást, az összes többi helyen a deklarált változók csak példányosítás után érhetők el, vagyis belőlük tetszőleges számú példány létezhet. Mivel a programozási példák erősen építenek a statikus main metódusra, a kezdőket összezavarhatja, hogy mit lehet elérni a main metódusból és mit nem, az alábbi kód nem fog fordulni, hiszen a valami nevű változó nem statikus változó:

public class StaticDemo
{
  public String valami = "valami cucc";

  public static void main (String args[])
  {
    System.out.println ("Írjunk ki a valami tartalmát: " + valami );
  }
}

9. Öröklődésnél elírjuk a felüldefiniálandó metódus nevét

Az öröklődés az objektum orientált programozás lételeme, mondhatni áldás, de átok is egyben, ha a felüldefiniálandó metódus nevét elírjuk akár egy betűvel is. Ez utóbbi esetben ugyanis a leszármazott osztályban nem a látszólag meghívott metódus fog lefutni, hanem az ősosztály megfelelő nevű metódusa. A hibát éveken keresztül programozók ezrei ejtették mondhatni napi rutinnal, de az ötös verzió óta az @Override annotációval végre kivédhetünk, hiszen ezzel az annotációval jelezzük a fordító felé, hogy valamelyik ős metódusát felül szeretnénk definiálni, s ha nincs egyik osztályban se ilyen, akkor a kód nem fog fordulni.

8. Összehasonlítás = jellel

Sok egyéb nyelvben az összehasonlítás az egyenlőség jellel történik - ahogy azt a matematika is teszi - viszont sok programozási nyelv esetén az egyenlőség jel a legyen egyenlő utasítást takarja. A C nyelvhez sokkal jobban hasonlító nyelvek különösebb lelkifurdalás nélkül elfogadják egy feltételben az értékadást és az eredményből igaz/hamis értéket képezve döntik el, hogy a program végrehajtása melyik ágon folytatódjon. Szerencsére a Java ezt nem teszi lehetővé, és az erősen típusosság is kivédi a hibalehetőségeket, így ezt a hibát csak a zöldfülű kezdők vétik a Java karrierjük első pár napján.

7. Példányok összehasonlítása == jellel

A Java nyelven kívül szinte minden egyéb nyelvben két akármi között egyenlőséget tudunk vonni, és az igaz/hamis eredményt fel tudjuk használni. Java bármely két példány között elfogadott az == jel, de nem a példány értékét hasonlítja össze, hanem a referenciát - vagyis hogy a két példány valóban egy és azonos-e. Az alábbi programrészlet szerint mind a két változónak az értéke "23" lesz, mégis két külön példány a memóriában, ezért példány szerint (==) nem lesznek egyenlők, de érték szerint (.equals) igen.

String a="23";
String b="2";
b=b+"3";
System.out.println(a==b);
System.out.println(a.equals(b));

6. Érték szerint vagy referencia szerint?

A Java nyelv elrejti a memóriát a programozó elől, a szemétgyűjtő szálra hagyva a memória tisztán tartását. Ha változókat használunk, tudnunk kell mit jelent a referencia szerinti és érték szerinti átadás, hiszen ez nagymértékben befolyásolja a programjaink hibátlan működését: a primitív típusok (és azok befoglaló osztályai) érték szerint adódnak át, minden más referencia szerint. Ez azt jelenti, hogy ha átadunk egy vektort egy metódusnak, akkor a metódusok belül hozzá tudunk adni új elemet, vagy törölni tudjuk annak tartalmát:

public static void add(Vector vector)
{
   vector.add("0");
}

public static void create(Vector vector)
{
   vector = new Vector();
}

public static void main(String[] args)
{
   Vector vector=new Vector();
   add(vector);
   System.out.println(vector.toString());
   create(vector);
   System.out.println(vector.toString());
}

A várt eredmény, hogy a második kiírásnál üres vektort kapunk - elmarad, mivel a create metódusban nem a referencián végzünk műveletet, hanem új értéket adunk neki, ezáltal a metódusok belül minden művelet egy új vektor példányra fog végrehajtódni, egyik művelet sem befolyásolja a paraméterben kapott változót. Gyakori hiba még haladóbb programozók között is.

5. Üresen hagyott catch ág

A struktúrált programozás leghasznosabb találmánya a try-catch blokk, amely igen hatékony hibakezelést tesz lehetővé. Sokszor találkozni olyan try-catch programrészekkel, amelyben a catch ágban nem történik semmi:

try
{
  // ...
}
catch (Exception except)
{
}

Bármilyen hiba is keletkezik a try blokkon belül, a catch ág elkapja, majd jól nem csinál semmit, a program fut tovább, a programozó pedig a felhasználóra fogja a problémát, hiszen nincs semmi hiba se a konzolon, se a naplóban...

4. Minden index nullával kezdődik...

Sok nyelvben a halmazok vagy listák első eleme az első (1) indexet viseli, sok másik nyelvben pedig a nulladik (0) indexet; a Java ez utóbbi nyelvek közé tartozik. Szerencsére túlcímzés esetén futás közben kivételt kapunk, hogy a tömb nem tartalmaz annyi elemet, ahányadikat használni szeretnénk. Persze ha üres a catch blokk... akkor nem kapunk kivételt... :)

Ha végre megszokjuk a nullával kezdődő indexelést, akkor a JDBC ezt a tudást porig rombolja, ugyanis itt minden sorszám egyel kezdődik... a dátumok esetén pedig - teljesen logikusan - a hónapok nullával kezdődnek, a január a 0. hónap, a napok viszont egyessel kezdődnek.

3. Több szálon futás

Még több éves tapasztalatok után is képes az ember hibákat hagyni egy több szálon futó programban, amikor szinkronizálás nélkül használ egy-egy változót - amely általában nem szálbiztos. Persze tesztelni egy szálon tesztel, és a kész rendszer a terhelés növekedtével egyre több rejtélyes hibát okoz...

2. Kisbetű-nagybetű probléma

Jó pár friss Java programozóknak okoz gondot a Java nyelv metódus és változó elnevezési konvenciója. Minden változót kisbetűvel írunk - az első szót követően minden szó első betűje nagybetű, ellenben minden konstanst nagybetűvel deklarálunk. Ehhez jön még a getter/setter minta, amikor a változók nevéhez ragasztjuk a get/set szót és ilyen néven szerepeltetjük ezeket a metódusokat. A kezdő programozók pár osztály után, az önfejű programozók sok-sok osztály után döbbennek rá, hogy ezen az elnevezési módszeren egy csomó Java technológia alapul...

1. A null pointer

Minden hibák legalattomosabbika, még a legtapasztaltabb öreg rókák életét is megkeseríti, ha egy változót nem példányosít, majd megpróbálja a példányváltozókat használni. Természetesen nem lehet a nyelvből kivenni a null értéket, hiszen egy csomó metódus ad vissza null értéket - akár üzemszerűen, akár hibát jelezve: sajnos ezzel együtt kell élni. Mint minden nyelvben - a Java nyelvben is vannak érdekes mellékhatások, íme a legrövidebb Java program, amely egyszerűen csak hibásan működik, pedig hiba nélkül lefordítható:

public class Main
{
  public static void main(String[] args)
  {
    throw null;
  }
}

Vélemény? (smile)