Archief - [PROG][JAVA] checked exceptions wrappen in RuntimeException

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

forloRn_

Legacy Member
Goeiemorgen,

Eenvoudig vraagje: een checked exception wrappen in een RuntimeException, genre
Code:
try {
    myDao.doSomething();
} catch (DaoException e) {
    throw new RuntimeException(e);
}
, is dat een gangbare praktijk? De exceptions ontstaan in je DAO (laagste niveau), de situatie kan onderweg niet hersteld worden en resulteren enkel in een foutmelding voor de gebruiker (hoogste niveau).

Ik heb geen zin om die exceptions in de throws clause van al mijn methods te schrijven, terwijl ze toch moeten propageren naar boven.

Iemand een idee? :unsure:

Bedankt!

Bavo aka Joske

Legacy Member
Ja, het is de 'Spring' aanpak. Zij gooien enkel checked Exceptions als je ze echt moet afhandelen. Het is me zelfs onzeker of ze dat ooit doen. Alle code in Spring gooit bijgevolg RuntimeExecepties en dwingt u nooit handling af, tenzij je dat zelf wilt (dan catch je de verwachte Runtime gewoon, door hen gedeclareerd in de throws), en handle je ernaar.
Zo hebben ze een hele wrapper rond Hibernate geschreven (template oa), die alle Hibernate specifieke Checked excepties omzette naar Spring generale runtime Data excepties. Twee voordelen: een andere persistentie-engine zou nog steeds dezelfde excepties gooien, en je vangt ze enkel op indien je dat wenst (vaak op het einde van de keten)



Zeer zeker een gangbare praktijk.

edit: het is wel aangeraden specifiek te blijven over uw exceptie, dus RuntimeException extenden en zelf een type definieren, zodat je het later toch nog kan vangen, en de zaak documenteerbaar blijft (blijf ze in throws zetten bvb op de interface)

forloRn_

Legacy Member
Cool. Wat dat laatste betreft (het alsnog catchen van specifieke exceptions), dit vind ik in Thinking in Java:

Code:
try {
    // ...
catch (RuntimeException re) {
    try {
        throw re.getCause();
    } catch (SpecificException1 e) {
        // ...
    } catch (SpecificException2 e) {
        // ...
    } catch (Throwable e) {
        // ...
    }
}

Zo kan je alsnog je specifieke exceptions catchen.

Bavo aka Joske

Legacy Member
Dat kan zeker, maar het documenteert geen gedrag van uw interfaces, je weet enkel welke execepties je kan behandelen indien je de code bekijkt, wat een beetje het interface/absractie pattern doorbreekt.
Daarom dat Spring opteert om specifieke runtime wrappers te maken rond specifieke checked exceptions. Je declareert de throws dan enkel in de interface.

forloRn_

Legacy Member
Goed, maar als je de geworpen exceptions in de interface declareert, zou je ze net zo goed checked kunnen maken.

Dit vind ik in de Java API:
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Throwable.html zei:
A second reason that a throwable may have a cause is that the method that throws it must conform to a general-purpose interface that does not permit the method to throw the cause directly. For example, suppose a persistent collection conforms to the Collection interface, and that its persistence is implemented atop java.io. Suppose the internals of the put method can throw an IOException. The implementation can communicate the details of the IOException to its caller while conforming to the Collection interface by wrapping the IOException in an appropriate unchecked exception. (The specification for the persistent collection should indicate that it is capable of throwing such exceptions.)

Bavo aka Joske

Legacy Member
De laatste lijn zegt juist dat je het moet aangeven, en het zegt niet dat het in RuntimeException moet, maar eerder in een 'unchecked exception', wat per definitie RuntimeException of een van zijn extensies is.

Ik ben van mening dat een interface moet communiceren wat zijn in en output is, en excepties zijn een mogelijke output. De gebruikers van de interface weten dan wat ze kunnen doen in welke omstandigheid, maar worden niet verplicht iets te doen, in tegenstelling tot bij checked excepties.
Je declareert enkel die excepties via throws op de interface, niet op elke methode die ze aanroept, en niet op methodes binnenin de implemetatie van de interface.

Er bestaat geen ergere interface die willkeurig runtimeexcepties gooit waarvan je niet op voorhand weet wat er in zit. Erger nog, als je excepties aan iets hangt moeten remote clients die ook kennen. Daarom zijn specifieke wrappers vaak makkelijker.

Het kan best zijn dat je nie tmet interfaces werkt, dan stelt het probleem zich niet. Maar dat zou toch minstens verdacht zijn

forloRn_

Legacy Member
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Throwable.html zei:
The implementation can communicate the details of the IOException to its caller while conforming to the Collection interface by wrapping the IOException in an appropriate unchecked exception. (The specification for the persistent collection should indicate that it is capable of throwing such exceptions.)

Hier gaat het wel degelijk om de implementatie (de persistent collection) die zegt dat ze unchecked exceptions throwt, en niet de interface (want de Collection interface throwt geen exceptions).

Ik ben het met je eens wat de bedoeling van een interface betreft: het bepalen van in- en output. Geef toe dat je wel erg beperkt bent in het hergebruiken van interfaces voor verschillende implementaties, want je moet je houden aan de throws clause in je interface. Wil je dat niet, dan moet je je toevlucht zoeken tot truukjes als wrappen in een RuntimeException, zoals hierboven. Voor nieuwe interfaces stelt het probleem zich niet, want dan bepaal je zelf de throws clause, eventueel met je eigen algemene wrapper exception.

Ik ben er nog niet uit of exceptions behoren tot een interface, of dat het eigenlijk implementatiedetails zijn, en ik ben er ook nog niet uit of checked exceptions een goed idee zijn. Was Java tot op heden niet de enige programmeertaal met checked exceptions?

Bavo aka Joske

Legacy Member
Er staat daar gewoon dat je niet anders kan dan een runtime exception gebruiken om een specifieke exception te communiceren, omdat je vast zit met de gegeven interface (van Collection). Er staat niet dat het een RuntimeException moet zijn, wel een 'unchecked exception', wat volgens de Java syntax een RuntimeException is, of ene extensie daarvan. Het kan nog steeds beide kanten op, het helpt u gewoon op weg om consistent te blijven met een reeds vastgelegde interface. Jij echter kan er nog zelf een maken.

Het is trouwens niet verboden RuntimeExceptions te throwen in overriden methodes, noch minder excepties te gooien dan de overriden methode. Technisch gezien is er geen probleem.

Ik vind persoonlijk wel dat ze deel zijn van een Java interface. Het is gene implementatie-detail, want de klant ervaart het gedrag rechtsrteeks in zijn aanroep (iets wat een thread kan doden is nogal belangrijk om weten).

Checked excepties zijn idd erg Java specifiek, en omstreden. Het kan zorgen voor betere code (het dwingt u), het kan ook zorgen voor slechtere (veel gebruikers vangen en doen niets omdat ze niet beter weten, het is dan beter het te laten propageren en threaddumpen). De verplichte boilerplate die het genereert is in elk geval kut.

Bavo aka Joske

Legacy Member
Nog even hierop voort: het moet niet veel werk zijn hoor, je kan gewoon een
Code:
ApplicationException extends RuntimeException

maken en dat in de throws zetten bvb. Dat zegt al iets.

forloRn_

Legacy Member
Goed, wat zou jij doen in dit geval?

  • de bovenste laag van de applicatie is een servlet, de onderste een DAO, ertussen zitten pakweg vijf of zes laagjes (klassen)
  • de servlet moet een respons teruggeven aan de client: een succesboodschap óf specifieke foutboodschappen voor een hele hoop exceptions, gethrowd door die vijf of zes klassen
  • de specifieke foutboodschap van het vorige puntje is onafhankelijk van getMessage() van de exception, dus geen
    Code:
    try {
      doIt();
    } catch (Exception e) {
      out.println(e.getMessage());
    }
  • de servlet moet voor onvoorziene exceptions (in de praktijk zijn dat RuntimeExceptions) een algemene foutboodschap teruggeven ("general error" of iets dergelijks)
  • de tussenliggende laagjes moeten exceptions gewoon all the way doorgeven naar de servlet

Wat ik gewoon wil vermijden is dat elk laagje álle exceptions van de daaronder liggende laagjes in zijn throws clause moet zetten, gewoon om die exceptions te kunnen laten propageren naar boven. Het zint me ook niet dat mijn throws clauses afhankelijk worden van de onderliggende laagjes (want dat zijn wel implementatiedetails).

Voorbeeldje:

A.a() throws AException, BException, CException, DException, EException
B.b() throws BException, CException, DException, EException;
C.c() throws CException, DException, EException;
D.d() throws DException, EException;
E.e() throws EException;

Is het dan een goed idee om al deze exceptions subklassen te maken van, om jouw voorbeeldje te nemen, ApplicationException extends RuntimeException?

Bavo aka Joske

Legacy Member
Wrappen in ApplicationExcepten, subclassen is niet nodig, en enkel dat declareren waar nodig, bvb in een three-tier applicatie zou dat in uw service-laag zijn (de plaats waar bussiness logica zit)
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan