[Javalist] Segítség! Java7 compiler BUG???

Peter Verhas peter at verhas.com
2012. Júl. 25., Sze, 12:22:56 CEST


Mesélni nem szeretek, illetve igen, de az a gyereknevelés vagy a csajozás témaköre, ez meg egy szakmai fórum, ahol a kőkemény tények számítanak. Persze szellemileg nagyon fel tud frissíteni egy olyan téma, hogy jobb-e exception-t dobni, vagy inkább null-t visszaadni egy metódusból amennyiben abból a szempontból vizsgáljuk meg, hogy melyik eredményez a hívó oldalon olvashatóbb kódot. Ez mindaddig szubjektív, amíg nem végzünk mérést sok átlagos programozón, definiált metrikával, ami méri, hogy mennyire olvasható a kód. Gyakorlatilag ez kivitelezhetetlen, ezért ilyenkor a common sense dönt; illetve az idő, ami éveket jelent. Idővel kiderül, hogy mi a jó, mi a rossz, és sok minden marad azon a mezsgyén, amire a legmegfelelőbb szó a "megfelelő".

Tipikusan például ilyen a singleton. Baromi jól el lehet vitázni, hogy a singleton pattern, vagy antipattern (talán erről is írok majd egy blogbejegyzést, meg ezekből a hosszabb levelekből is), de leginkább azt lehet mondani, hogy nem rossz. Megfelelő. Arra amire.

A tények azonban makacs dolgok, és ha mégoly szép kódot is eredményez egy programozási módszertan, ha használhatatlan  a kód, ami az alapján készül, akkor az nem egy jó pattern (ezt írtam az előző levelemben is, kedves néném...) Anno ezen halt el az Algol60 meg az Algol68 is: nem volt olyan gép, ami le tudta volna fordítani gyorsan és jól: maradt a FORTRAN a kor kódolóinak.

Az a mondás, hogy ne dobjunk Exception-t, mert az lassú überel mindent. Hiába lesz szép és olvasható a kód ha egy null-t visszaadó metódus 1000-szer gyorsabb, mint egy olyan, amelyik egy 'new Exception()' -t dob. (kb. ez az arány, beleértve a try/catch kezelést is, olyan metódusoknál, amelyek egyébként nem csinálnak semmit).

Konkrétan csak egy 'return null'-t visszaadó metódust tíz milliószor meghívva 12ms alatt végez a gépem, míg ugyanennyiszer egy olyat, ami egy Exception-t dob 23ms-ig is eltart. Hogyan?

VIGYÁZAT CSALOK!

Ha minden egyes alkalommal új Exception-t hozok létre, akkor ez az érték már 11000ms, majdnem ezerszer lassabb. De ha ugyanazt az Exception-t dobálom?

Ez azt mutatja, hogy teljesítmény szempontjából nem az a kérdés, hogy null-t adjak-e vissza, vagy kivétel dobásával jelezzem a speciális visszatérési értéket, hanem azt, hogy nem feltétlenül kell minden egyes esetben új Exception objektumot létrehozni.

Persze azt is tudni kell, hogy ilyen esetben az exception objektum stack trace része használhatatlan, hiszen nem azt fogja tartalmazni ahol akkor járt a program, amikor el lett dobva, hanem azt amikor és ahol létre lett hozva. A kérdés az, hogy kell-e nekünk a stack trace?

Ha olyan exception-t dobunk, amelyik kivételes esetet jelez, tipikusan emberi beavatkozást fog igényelni, meg kell hogy jelenjen a log-ban a stack trace, hogy lehessen tudni, hogy honnan lett dobva, akkor létre kell hozni egy új exception objektumot, tipikusan a szokásos

throw new Exception()

pattern szerint. Amikor ezt tesszük a programnak már úgyis betették a kaput, a teljesítménynek nem számít, hogy a szerver X+12ms vagy X+12mp alatt áll le (itt X az az idő ami még ezen kívül kell a leálláshoz).

Ha viszont olyan kivételt dobunk, ami nem különleges helyzet, csak jelezni akarjuk például, hogy nincs több adat, vagy nincs keresett adat, akkor (ha egyébként ez megfelel az ízlésünknek, és minden egyéb feltételnek) csak a teljesítmény szempontokat figyelembe véve dobhatunk egy private static final változóban tárolt exception-t. A metódus futási idejének csak kis része lesz (mondjuk 1%-a) a visszatérés maga, így ha ez kétszer annyi időt vesz igénybe a hívó oldalon, akkor fél százalékkal nőtt a metódus bruttó futási ideje (bruttó alatt a hívási oldali költségeket is figyelembe vesszük, try/catch/finally és társai).

Ez tehát nem támasztja alá, hogy ne dobjunk exception-t nem kivételes helyzetben. Kicsit lassabb, de elviselhető. Ezzel némileg ellentmondok az Effective Java könyvnek, de nem lehet vele vitázni, mert csak annyit ír, hogy "egy száz elemű tömbnél az én gépemen kétszer annyi ideig tart". Ez nem precíz. Hidd el neki. Vagy ne hidd el, hanem mérd meg! Én erre az utóbbira szavazok: a konkrét méréseket, meg kódot majd felrakom a blogra, és továbbra is folyhat arról a vita, hogy melyik a szebb pattern: null-t visszaadni, vagy exception-t dobni (és persze van egy harmadik pattern is, ami azt mondja, hogy legyen hasNext() kinézetű metódus).

--
Verhás Péter
peter at verhas.com
+36(30)9306805
skype: verhas




On 2012.07.25., at 10:50, István Székely wrote:

> Sziasztok!
> 
> Péter, erről légy szíves mesélj, mert úgy érzem, lemaradtam valamiről.
> 
> A kivételkezelés Javaban is lassú (volt?). Ennek oka pontosan a stack trace összeállítása. A hívási lánc bejárása és a stack trace összeállítása igen drága művelet. Pont ebből az okból javasolja Joshua Bloch is, hogy kivételkezelést ne használjunk vezérlési szerkezetek helyett. Emiatt nem jó az sem, hogy az említett JPA metódus is kivételt dob null visszaadása helyett (persze emellett is lehet érvelni, és hajlamos is vagyok elfogadni, de az most más téma).
> 
> Ahonnan van: Effective Java, 2nd ed
> Item 57: Use exceptions only for exceptional conditions
> 
> Üdv,
> Stivi
> 
> 
> On 2012-07-24 23:26, Peter Verhas wrote:
>> Technológiai okok miatt C++ és C# (általánosan .NET) környezetben nem szeretünk exception-t dobni (én magam programozni sem szeretek ezekben a környezetekben, nem is tudok (nagyon), hát még kivételt dobni). Ezekben a környezetekben a kivétel dobása drága, egészen más a kivételek szerkezete, és ezért nem is ad megfelelő információt. Tipikusan nincs benne a stack trace, ezért ha egy szinttel feljebb, mint ahonnan dobták nem kapjuk el, akkor már nem is lehet tudni, hogy honnan dobták. Akkor meg már olcsóbb futási időben a megfelelő hibakód visszaadása, és ennek nagy hagyománya van unix C és Windows C programozási környezetben, régen bevált. [Megjegyzés: ennek a bekezdésnek az egyik fele nem első kézből való információ, csak beszélgettem .NET-es kollégákkal. A másik fele viszont ezer évvel ezelőtti C programozási emlékek megmaradt halvány foszlányai.]
>> 
>> A Java egészen más. Java-ban az exception hordozza a stack trace-t (vagy nem, de inkább igen, mint nem), és ebben nagyon sok szimbolikus információ benne van. Nem kell ott elkapni, ahol dobják, vagy egy szinttel feljebb, mert minden szükséges információ benne van, és ezért elég ha ott kapjuk el, ahol kezelni tudjuk. Ezért lett egyébként kitalálva a hiba dobás, és véleményem szerint a .NET környezet az exception dobás, mint pattern funkcionalitásának egy részét feláldozta a teljesítmény oltárán, amit viszont mostanra (Java6, 7) kezd túlhaladni az idő.
>> 
> 
> _______________________________________________
> Javalist mailing list
> Javalist at lists.javaforum.hu
> http://lists.javaforum.hu/mailman/listinfo/javalist

--------- következő rész ---------
Egy csatolt HTML állomány át lett konvertálva...
URL: <http://lists.javaforum.hu/pipermail/javalist/attachments/20120725/cf6a51db/attachment.html>


További információk a(z) Javalist levelezőlistáról