Monday, 23 February 2009

Ai suprascris equals? Suprascrie şi hashCode!

E o lecţie care se învaţă la început, dar e uşor de uitat pentru un programator Java, deşi e util de ştiut. De exemplu, metoda contains() a interfeţei java.util.Collection declară în contractul ei din API că va căuta în colecţie un obiect care are proprietatea că: fie este null dacă obiectul primit ca parametru este null, fie apelarea metodei equals a obiectului din colecţie cu obiectul căutat ca parametru dă true.

Clasa java.util.HashSet, care implementează printre altele interfaţa java.util.Collection, teoretic aderă la acest contract, deşi documentaţia ei (în mod ciudat), e mai vagă decât cea a interfeţei. Practic, pentru eficientizare, metoda contains(), aşa cum este ea implementată în clasa java.util.HashSet, nu ajunge să apeleze metoda equals() pentru verificare, decât dacă la apelul metodei hashCode() (mai rapidă) pe ambele obiecte se returnează aceeaşi valoare.

Documentaţia Java este cea care este deficitară şi derutantă aici. Documentaţia clasei java.util.HashSet ar trebui să specifice exact comportamentul fiecărei metode şi nu doar să enunţe generic în antet o prezumţie („assuming the hash function disperses the elements properly among the buckets” - nu e clar ce înseamnă aici properly).

Deci, dacă cumva ai suprascris equals() pentru o clasă, pentru ca ea să aibă efectul dorit în toate cazurile în care te-ai aştepta, trebuie ca metoda hashCode() a acelui obiect să fie şi ea suprascrisă. Contractul lui hashCode() spune aşa: If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. Cum suprascriem hashCode, depinde de noi, atâta vreme cât respectăm acest contract. Dacă nu sunt egale, nu se specifică nimic, pot să difere sau pot să fie identice, dar e de preferat să se încerce ca nici comparaţia hashCode să nu dea fals pozitiv prea uşor.

Vezi şi itemul 8 de aici.

Wednesday, 18 February 2009

Stacktrace

Ce este aia o stivă de urme? Termenul de stacktrace este încetăţenit. Toţi cei care îl folosesc ştiu bine ce înseamnă. Nu are rost să forţezi o traducere în română a unui termen folosit şi înţeles într-o formă direct importată. Scuze, dar traducerea literală de mai jos (din varianta în română a lui Firebug) sună a fandoseală:


Şi în plus, chiar dacă traduci literal, nu este urma stivei?

Tuesday, 17 February 2009

Jasper şi mesajele de eroare

Una din calităţile necesare ale unui framework sau ale unei biblioteci de funcţii este capacitatea de a furniza mesaje clare în caz de eroare. Aici Jasper, motorul de interpretare JSP care lucrează cu Apache Tomcat dă un rateu urât.

Într-un JSP, aveam o clauză de import a unei clase, să-i zicem x.y.MyClass. La un moment dat, m-am trezit cu următoarea eroare:

Only a type can be imported. x.y.MyClass resolves to a package

Evident că numele de acolo era al unei clase, asta e uşor de verificat. Problema era că în momentul deploy-ului, clasa respectivă nu era inclusă în JARul instalat pe server, iar numele de fapt nu reprezintă un pachet, el reprezintă nimic. Nu era de un milion de ori mai simplu şi mai clar un simplu ClassNotFoundException?