Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[ALG] Wat wel/niet binnen try block

Pagina: 1
Acties:

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 13-11 10:23
Steeds vaker vraag ik mij af hoeveel code binnen het try block moet, en wanneer je door moet gaan buiten het try block. Ik heb dus niet zozeer een probleem, meer een vraag over wat is netjes programmeren.

Als voorbeeld wil ik me Database class nemen die resultaten terug geeft uit een query(sql). Via clsDatabase.getResultset(sql) kan ik resultaten van een query opvragen, maar deze kan ook een exception geven als er iets fout gaat.

Een voorbeeld:
Java:
1
2
3
4
5
6
7
8
9
try {
  ResultSet rs = clsDatabase.getResultset(sql);
  // Nu moet ik wel de resultaten binnen het try block doorlopen, omdat er eventueel een exception gegooit is
  while (rs.next()) {
    // doe iets...
  }
} catch (SQLException e) {
  // Error afhandeling...
}


Of:
Java:
1
2
3
4
5
6
7
Map mp = new HashMap(); // Of arraylist of een andere array van objecten
try {
  mp = clsDatabase.getResultset(sql);
} catch (SQLException e) {
  // Error afhandeling...
}
// Hier kunnen de eventuele resultaten ook doorlopen worden


Wat is netter, of heeft meer voordelen?

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Het is misschien een beetje een non-antwoord; maar in het boek Code Complete ISBN10: 0735619670 ISBN13: 9780735619678 staat een heleboel hierover beschreven en kun je aardig als guideline gebruiken (er zijn wat puntjes waar ik wat kanttekeningen zou zetten, maar dat zegt ook niet alles ;) )

Het is een beetje afhankelijk van wat je in welke situatie hoe wil oplossen (als je al iets wil oplossen; soms wil je gewoon (bijv.) je app terminaten, re-tryen, een blok data skippen en doorrekenen of een 'neutral value' returnen)

Dit is overigens niet echt java-specifiek en meer iets voor SEA denk ik.

PRG >> SEA en Tagfix Java >> ALG

[ Voor 33% gewijzigd door RobIII op 28-02-2008 02:46 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 17:20

Janoz

Moderator Devschuur®

!litemod

Wat voor voordeel zou de tweede hebben? Een klein nadeel zie ik wel. Je maakt een nieuw object aan (hashmap) die je tijdens je normale programma doorloop helemaal niet gebruikt en gelijk weer overschrijft. Het enige moment waarop je hem eventueel nog wel gebruikt is wanneer je na de catch gewoon verder gaat, maar dat lijkt me lang niet altijd de wenselijke situatie.

Een try catch blok zet je imho om de hele functionaliteit heen. Het verwerken van de resultset hoort bij het ophalen ervan. Wanneer het ophalen fout gaat dan zou het verwerken imho ook niet meer kunnen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Wat ik meestal doe is:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
Map map = null;

try
{
    map = clsDatabase.getResultSet(sql);
}
catch(SQLException sqlex)
{
}
catch(Exception ex)
{
}


Declaraties buiten try/catch(/finally), instantiatie daar binnen, maar of het beter of slechter is dan een andere werkwijze weet ik niet. Ik vind het persoonlijk een fijne manier, maar dat zal voornamelik met gewenning te maken hebben.

[ Voor 25% gewijzigd door Verwijderd op 28-02-2008 08:33 ]


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

verytallman schreef op donderdag 28 februari 2008 @ 02:17:
Steeds vaker vraag ik mij af hoeveel code binnen het try block moet,
Zo min mogelijk. Dan is direct zichtbaar waar de exceptie vandaan kan komen en zijn de activiteiten die eventueel teruggedraaid moeten worden duidelijk te zien. Liever drie losse try..catch blokken rond drie opvolgende statements die verschillende excepties gooien (waarbij ik alle excepties met bijvoorbeeld IOException als superklasse als dezelfde exceptie reken), dan 1 block met drie catch clauses.
Janoz schreef op donderdag 28 februari 2008 @ 08:03:
Een try catch blok zet je imho om de hele functionaliteit heen. Het verwerken van de resultset hoort bij het ophalen ervan. Wanneer het ophalen fout gaat dan zou het verwerken imho ook niet meer kunnen.
'De hele functionaliteit' is een beetje vaag. Hoort het inlezen van een file met configuratie gegevens bij de opvolgende configuratie van de database? Doe je die twee dus in 1 try...catch block met 2 catch clauses of in twee losse try...catch blocks? Ik ga dan altijd voor het laatste, waarbij er een nieuwe Exception uit een catch block wordt gegooid als de toestand zodanig is dat uitvoering niet verder kan gaan en een bovenliggend niveau van een probleem op de hoogte gebracht moet worden. Maar sowieso gebeuren die dingen dan in losse methoden, dus speelt dat probleem eigenlijk niet...

[ Voor 59% gewijzigd door Confusion op 28-02-2008 08:47 ]

Wie trösten wir uns, die Mörder aller Mörder?


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Bij jouw voorbeeld met het ResultSet, zou ik het zo doen:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
...
ResultSet rs = null;
try {
  rs = clsDatabase.getResultset(sql);
  // doe iets...
} catch (SQLException e) {
  // Error afhandeling...
} finally {
  if (rs != null) {
    try {rs.close()} catch(Exception) {/* loggen ofzo*/}
  }
}
...

De reden is dat je een resultset naderhand moet sluiten en anders heb je in de finally geen referentie meer.

Fat Pizza's pizza, they are big and they are cheezy


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 17:20

Janoz

Moderator Devschuur®

!litemod

Functionaliteit is inderdaad een redelijk vage term. Ik bedoelde hem niet zo breed als jij hem nu schetst, maar meer als dat je het openen en daarna inlezen van het bestand binnen 1 try catch blok zet, en niet een aparte catch om de open en daarna nog een catch blok voor de readln's.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Janoz schreef op donderdag 28 februari 2008 @ 08:03:
Een try catch blok zet je imho om de hele functionaliteit heen.
Euh. Nee?

Je zet een try-catch block om het stuk heen waar je een error kunt verwachten, dus dat een database bijvoorbeeld niet online is, niet om je hele while loop.

https://niels.nu


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 17:20

Janoz

Moderator Devschuur®

!litemod

Bij het uitlezen van een resultset zet ik hem wel degelijk om de query zelf en de verwerking in de while lus heen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-11 23:43

.oisyn

Moderator Devschuur®

Demotivational Speaker

Confusion schreef op donderdag 28 februari 2008 @ 08:39:
[...]

Zo min mogelijk. Dan is direct zichtbaar waar de exceptie vandaan kan komen en zijn de activiteiten die eventueel teruggedraaid moeten worden duidelijk te zien. Liever drie losse try..catch blokken rond drie opvolgende statements die verschillende excepties gooien (waarbij ik alle excepties met bijvoorbeeld IOException als superklasse als dezelfde exceptie reken), dan 1 block met drie catch clauses.
Dat defeats een beetje de purpose van de hele program flow mogelijkheden die exceptions je bieden. Als je zo gaat werken kun je net zo goed return codes gebruiken - is een stuk praktischer dan om elke statement die een error op kan leveren een try/catch blok zetten.

Ik ben het dan ook eens met Janoz. Als je een file wilt openen, definieer je de variabele binnen een try/catch en open je meteen de file, daarna ga je alle lees-acties doen, en dan sluit je 'm weer. Als het openen van de file niet lukt, heeft het ook geen zin om de data uit te lezen, en derhalve is het dus onzinnig om de data-uitlees-code buiten de try/catch te zetten, zodat je in je catch een return moet doen, of een andere constructie zodat je het uitleesgedeelte over kunt slaan. Het hele mooie van de try-block is nou juist dat de rest overgeslagen wordt op het moment dat er ergens in dat try-block een exception gegooid wordt.

Uiteraard gaat dit natuurlijk alleen op als code ook daadwerkelijk niet uitgevoerd moet worden bij een foutmelding. Je zou bijvoorbeeld ook bij een mislukte file-open een alternatieve file kunnen openen. In zo'n geval zet je de data-uitlees code niet binnen de try en zorg je in je catch voor een andere data source.

Om te bepalen wat er in de try moet, moet je jezelf imho de vraag stellen of je dat statement uit wilt voeren als er voor dat statement een exception gegooid is. Is het antwoord nee, dan plaats je 'm in de try. Anders erbuiten.

[ Voor 6% gewijzigd door .oisyn op 28-02-2008 11:41 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

.oisyn schreef op donderdag 28 februari 2008 @ 11:38:
Ik ben het dan ook eens met Janoz. Als je een file wilt openen, definieer je de variabele binnen een try/catch en open je meteen de file, daarna ga je alle lees-acties doen, en dan sluit je 'm weer. Als het openen van de file niet lukt, heeft het ook geen zin om de data uit te lezen, en derhalve is het dus onzinnig om de data-uitlees-code buiten de try/catch te zetten, zodat je in je catch een return moet doen, of een andere constructie zodat je het uitleesgedeelte over kunt slaan. Het hele mooie van de try-block is nou juist dat de rest overgeslagen wordt op het moment dat er ergens in dat try-block een exception gegooid wordt.
Dat is ook meteen het nadeel van try-catch blokken. Als iemand denkt "die ingelezen data in de database stoppen hoeft ook niet te gebeuren als de file inlezen misgaat", dan zal je zien dat de databaseconnectie initialisatie wordt overgeslagen en hij vervolgens stukloopt op het feit dat je verderop met die databaseconnectie iets probeert in te lezen. Try-catch blokken hebben de onaangename neiging complete methodes te gaan omspannen, steeds meer typen excepties te gaan catchen en steeds onduidelijker te maken welke code samenhangt, welke overgeslagen moet worden in een bepaalde geval, etc. Daarom: 'zo min mogelijk'. Zonder dat het absurd wordt natuurlijk.
Om te bepalen wat er in de try moet, moet je jezelf imho de vraag stellen of je dat statement uit wilt voeren als er voor dat statement een exception gegooid is. Is het antwoord nee, dan plaats je 'm in de try. Anders erbuiten.
IMHO moet de code in het blok meer samenhang hebben dan alleen een flow-afhankelijkheid. Ik test liever verderop een keer op null, omdat de file niet is ingelezen en de string nog leeg is, dan dat ik code die iets met de string doet ook in het try-catch blok opneem. Als de try en de catch niet tegelijk op mijn scherm passen, dan is er iets mis.

Wie trösten wir uns, die Mörder aller Mörder?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-11 23:43

.oisyn

Moderator Devschuur®

Demotivational Speaker

Confusion schreef op donderdag 28 februari 2008 @ 12:17:
[...]

Dat is ook meteen het nadeel van try-catch blokken. Als iemand denkt "die ingelezen data in de database stoppen hoeft ook niet te gebeuren als de file inlezen misgaat", dan zal je zien dat de databaseconnectie initialisatie wordt overgeslagen en hij vervolgens stukloopt op het feit dat je verderop met die databaseconnectie iets probeert in te lezen.
Dan zit de fout niet zozeer in de layout van de try/catch blokken, maar meer in het feit dat er geen duidelijk afgebakend initialisatiesequence is. Zo zou je bijv. ook kunnen stellen dat je de file niet hoeft te openen op het moment dat de geen verbinding naar de database kunt maken. Je hele initialisatiedeel kun je dus al verhuizen naar een eigen try blok. Daarnaast loop je alleen tegen dat probleem aan als je je variabelen buiten je try-blok gaat definieren. Ja, dan kun je idd tegen het feit aan lopen dat je later met een null-pointer zit te werken omdat er bij/voor initialisatie van de variabele een exceptie gegooid werd. Als je je variabelen definieert wanneer je ze initialiseert heb je dat hele probleem ook niet. En als dan blijkt dat je de variabele buiten het try-blok toch nog nodig hebt, dwingt je dat meteen tot nadenken over of je de flow zo eigenlijk wel goed hebt uitgedacht.
Try-catch blokken hebben de onaangename neiging complete methodes te gaan omspannen, steeds meer typen excepties te gaan catchen en steeds onduidelijker te maken welke code samenhangt, welke overgeslagen moet worden in een bepaalde geval, etc. Daarom: 'zo min mogelijk'. Zonder dat het absurd wordt natuurlijk.
Ik heb natuurlijk ook niet gezegd dat het 1 monolithisch try blok moet worden. En je zou bijv. ook kunnen nesten. Zonder dat het absurd wordt natuurlijk ;).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Laurens-R
  • Registratie: December 2002
  • Laatst online: 29-12-2024
Aanvulling:

Code Complete 2 zegt ook dat een try catch block ook echt alleen gebruikt dient te worden voor exceptions! Exceptions moeten dus ook echt exceptioneel zijn qua foutomvang om in een try-catch blok behandeld te worden.

Soms zie je echt van die half gare try-catch implementaties om fouten in een algoritme af te vangen ofzo... (DevideByZero e.d.). Dan moet je dat niet in een try-catch blok afvangen, dan moet je het algoritme fixen!

[ Voor 32% gewijzigd door Laurens-R op 01-03-2008 17:37 ]


Verwijderd

EvilB2k schreef op zaterdag 01 maart 2008 @ 17:35:
Soms zie je echt van die half gare try-catch implementaties om fouten in een algoritme af te vangen ofzo... (DevideByZero e.d.). Dan moet je dat niet in een try-catch blok afvangen, dan moet je het algoritme fixen!
Ik heb code gezien die bij compilatie massa's warning gaf : "Exception exc" is declared but never used. Vond dit maar raar, beetje gaan snuffelen en bleek dat er wel een hele reeks try/catch blokken waren gedeclareerd maar de catch blokken waren allemaal leeg.

meer on-topic:
wat wel en wat niet ? de stukken waar je fouten verwacht (verkeerde inputs, missing files, failed connections,...) daar is iedereen er wel mee eens
dan blijft de vraag : hoeveel ?


persoonlijk gebruik ik als een ruwe regel dat als mijn catch-blok groter is dan mijn try-block er iets mis is met mijn logica

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:01
Confusion schreef op donderdag 28 februari 2008 @ 08:39:
[...]

Zo min mogelijk. Dan is direct zichtbaar waar de exceptie vandaan kan komen en zijn de activiteiten die eventueel teruggedraaid moeten worden duidelijk te zien. Liever drie losse try..catch blokken rond drie opvolgende statements die verschillende excepties gooien (waarbij ik alle excepties met bijvoorbeeld IOException als superklasse als dezelfde exceptie reken), dan 1 block met drie catch clauses.
Daar ben ik het niet mee eens.
Wat met atomaire operaties ?
Een try block moet imho rond een atomaire operatie geplaatst worden; ofwel wordt alles uitgevoerd, ingeval van een exceptie moet de rest van die operatie niet meer uitgevoerd worden.
Alles hangt dus imho van de context.

https://fgheysels.github.io/


  • Cloud
  • Registratie: November 2001
  • Laatst online: 03-11 10:25

Cloud

FP ProMod

Ex-moderatie mobster

Verwijderd schreef op donderdag 13 maart 2008 @ 16:49:
Ik heb code gezien die bij compilatie massa's warning gaf : "Exception exc" is declared but never used. Vond dit maar raar, beetje gaan snuffelen en bleek dat er wel een hele reeks try/catch blokken waren gedeclareerd maar de catch blokken waren allemaal leeg.
Dit kom ik ook geregeld tegen in code (outsourcing :X). Werkelijk overal try/catch blokken omheen gooien..

Ik zorg er gewoon voor dat de exceptie in de eerste plaats niet voorkomt. Input validatie en dergelijke. Ik vang alleen excepties af die er horen te zijn (zoals FileNotFound of een parse operatie die mislukt), en excepties die de applicatie in een verkeerde state achterlaten of zorgen voor data corruptie. Wil je alles 'vriendelijk' afvangen voor je user, dan maak je gewoon een globale try/catch. Maar niet per methode als je er toch niets nuttigs mee kunt doen.

Bijvoorbeeld al je DB queries gaan try/catchen is m.i. niet handig. Want wat wil je doen als een INSERT faalt, anders dan een foutmelding weergeven? De devver moet het toch fixen. Uiteindelijk werken al je DB queries namelijk (zodra je ze bug vrij hebt) en zit je met bergen code die nooit meer gebruikt wordt. Er zijn natuurlijk situaties waarin je het wél nodig hebt, maar het wordt nogal eens verkeerd/teveel toegepast. Vind ik. :)

Never attribute to malice that which can be adequately explained by stupidity. - Robert J. Hanlon
60% of the time, it works all the time. - Brian Fantana


Verwijderd

Persoonlijk vind ik dat je een groep bij elkaar horende statements altijd bij elkaar moet houden. Exceptions zijn min of meer onverwachte/ongewenste situaties die je wil afvangen. Maar zolang het excepties/uitzonderingen zijn moet je niet je logica ervoor uit elkaar gaan rafelen. Je gaat er van uit dat exceptions niet gegooid gaan worden, althans, niet zo vaak, dus je richt je op het leveren van functionaliteit en vervolgens implementeer je per groep samenhangende statements de excepties.

en inderdaad, de meeste excepties zullen uiteindelijk ofwel runtime zijn (fout van/voor de programmeur), ofwel een input-fout (maar daar heb je wellicht validaties voor) of het ontbreken van resources (file, database, server not found). en veel ingewikkelder dan dat moet je het m.i. ook niet maken. De programmeur die vind heus wel op welk regelnummer de boel in de soep loopt.

Verwijderd

In Delphi (Win32) gebruik ik nauwelijks try/except (= try/catch), maar wel veel checks of iets gelukt is of niet en een akelig goede exception handler die precies vertelt waar de echte exceptions optraden en in welke context (MadExcept).
Try/finally gebruik ik echter ontzettend veel: benodigde objecten buiten 't blok aanmaken, binnen de try doen wat je met die objecten moet doen, en ze in 't finally deel weer vrijgeven.
Delphi heeft nl. geen GC, en dan is 't verdraaid handig dat zelfs na een echte exception je objecten toch netjes worden opgeruimd...

Vaak zie je try/except gebruikt worden om bv. iets simpels als een 'list index out of bounds' exception af te vangen, terwijl je vantevoren al weet wat de bounds van die list zijn. Dan check je dat eerst toch?

[ Voor 14% gewijzigd door Verwijderd op 21-03-2008 22:58 ]


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

whoami schreef op donderdag 13 maart 2008 @ 16:58:
Daar ben ik het niet mee eens.
Wat met atomaire operaties ?
Een try block moet imho rond een atomaire operatie geplaatst worden; ofwel wordt alles uitgevoerd, ingeval van een exceptie moet de rest van die operatie niet meer uitgevoerd worden.
Dat was wat ik bedoelde met 'zo min mogelijk': een atomaire operatie per block. Maar het is meer een 'basisheuristiek', want zoals in de discussie met .oisyn al impliciet naar voren kwam:
Alles hangt dus imho van de context.

Wie trösten wir uns, die Mörder aller Mörder?


Verwijderd

Ik heb onlangs in een boek (kan mij de naam net meer herrineren) een hoofdstukje daarover gelezen. Die persoon was van mening om wel grotere try blocks te maken, maar om exceptions gemakkelijk te rethrowen. En dat rethrowen is iets wat volgens mij eigenlijk veel te weinig gedaan wordt.

Verwijderd

Rethrowen is m.i. niet echt 'best practice'. Voor je 't weet wordt de flow bepaald door de exceptions, en daar zijn exceptions niet voor, dat zijn uitzonderingen die je van tevoren niet kon inschatten.

Als je specifieke exceptions rethrowt naar een niveau lager, betekent 't dat je al rekening hebt gehouden met die exception. En in het gros van de gevallen had je dan ook al van tevoren kunnen checken of die exception uberhaupt op zou kunnen treden.

  • sjongenelen
  • Registratie: Oktober 2004
  • Laatst online: 12:03
JKVA's methode vind ik een mooie, leesbare methode (dus ook voor de gebruikers) - houdt het overzichtelijk. Qua performace en andere voordelen: geen idee

offtopic:
ik doe altijd

[code]
catch(...)
{
System.out.printl("ERRORR ERRORRRRR") ;
}
[/code]
:Y)

[ Voor 9% gewijzigd door sjongenelen op 31-03-2008 23:07 ]

you had me at EHLO


Verwijderd

Aangezien exceptions 'duur' zijn, probeer ik zoveel mogelijk de situaties die een exceptie kunnen opleveren te vermijden door simpelweg te checken.. (user input ed..)

Verder zaken als het inlezen van een file gewoon in 1 try/catch.. moet het openen van de file niet lukken heeft het ook niet al te veel zin om verder te gaan..
Uiteraard wel ff in de finally je reader ed. closen

Verder gebruik ik ook altijd een algemene try catch om het hele programma om onverwachte fouten netjes te melden aan de gebruiker.

Disclaimer: werk voornamelijk met C# dus weet niet hoe het zit met JAVA
Pagina: 1