Skip to main content

Foutafhandeling

In dit voorbeeld laten we zien hoe je klassen, functies en foutafhandeling in Dart kunt gebruiken. We maken een eenvoudige klasse Kind om de gegevens van een kind te beheren, voegen validatie toe om ervoor te zorgen dat de gegevens correct zijn, en gebruiken een functie om kinderen aan een lijst toe te voegen. Daarnaast demonstreren we hoe je fouten kunt afhandelen met een try-catch constructie.

Voorbeeldcode

Uitleg van de Code

Klasse Kind

  • Definitie: De Kind klasse wordt gebruikt om gegevens van een kind op te slaan, zoals naam en leeftijd.
  • Attributen: naam en leeftijd zijn attributen van de Kind klasse.
  • Constructor: De constructor valideert dat de naam niet leeg is en dat de leeftijd groter is dan nul. Zo niet, dan wordt er een ArgumentError gegooid.
  • Methode toString: Retourneert een stringrepresentatie van het kind.

Functie voegKindToeLijst

  • Functie: Voegt een nieuw kind toe aan een lijst van kinderen en print een bevestigingsbericht.

main Functie

  • Lijst van Kinderen: Een lege lijst om kinderen op te slaan.
  • Try-Catch Constructie: Probeert kinderen toe te voegen aan de lijst en vangt fouten op als er invalid data wordt toegevoegd.
  • Printen van Kinderen: Print de informatie van elk kind in de lijst.

Belangrijke Concepten

  1. Klassen en Objecten (Classes and Objects): Gebruik van klassen om objecten te definiëren en beheren.
  2. Validatie (Validation): Ingebouwde validatie in de constructor om fouten te voorkomen.
  3. Foutafhandeling (Error Handling): Gebruik van try-catch om fouten af te handelen en het programma robuuster te maken.
  4. Iteratie (Iteration): Gebruik van een for-lus om door een lijst van objecten te itereren en informatie weer te geven.

Foutafhandeling in Dart

Foutafhandeling is cruciaal in elke programmeertaal om ervoor te zorgen dat het programma robuust en fouttolerant is. In Dart gebruik je try-catch om fouten op te vangen en af te handelen.

Uitleg van try-catch

  • Try-blok: Hierin plaats je de code die mogelijk een fout kan veroorzaken. Als er een fout optreedt, stopt de uitvoer van het try-blok en wordt de fout doorgegeven aan het catch-blok.
  • Catch-blok: Hierin plaats je de code die wordt uitgevoerd als er een fout optreedt in het try-blok. Je kunt het caught exception object gebruiken om details over de fout te verkrijgen en geschikte acties te ondernemen.

Voorbeeld van try-catch

In het voorbeeld proberen we kinderen toe te voegen aan de lijst. Als een kind een lege naam heeft of een negatieve leeftijd, zal de constructor een ArgumentError gooien. Deze fout wordt opgevangen door het catch-blok, dat vervolgens de foutmelding print.

void main() {
  List<Kind> kinderen = []; 

  try { 
    voegKindToeLijst(kinderen, Kind("Jan", 12));
    voegKindToeLijst(kinderen, Kind("Piet", 10));
    voegKindToeLijst(kinderen, Kind("", 8)); // Fout: Lege naam
  } catch (e) { 
    print("Fout: ${e.toString()}"); 
  }

  print("Kinderen in de lijst:"); 
  for (Kind kind in kinderen) { 
    print(kind); 
  }
}

Uitzonderingen (Exceptions)

Je Dart-code kan exceptions opwerpen (throw) en opvangen (catch). Exceptions zijn fouten die aangeven dat er iets onverwachts is gebeurd. Als de exception niet wordt opgevangen, wordt het isolate dat de exception heeft opgewekt geschorst, en meestal worden het isolate en het programma beëindigd.

In tegenstelling tot Java zijn alle exceptions in Dart unchecked exceptions. Methoden verklaren niet welke exceptions ze kunnen opwerpen, en je bent niet verplicht om exceptions op te vangen.

Exceptions Gooien (Throwing Exceptions)

Hier is een voorbeeld van het gooien van een exception:

throw FormatException('Expected at least 1 section');

Je kunt ook willekeurige objecten gooien:

throw 'Out of llamas!';

Let op:

Productiecode gooit meestal types die Error of Exception implementeren.

Omdat het gooien van een exception een expressie is, kun je exceptions gooien in => verklaringen, evenals overal waar expressies zijn toegestaan:

void distanceTo(Point other) => throw UnimplementedError();

Exceptions Opvangen (Catching Exceptions)

Het opvangen van een exception stopt de propagation (voortplanting) van de exception (tenzij je de exception opnieuw gooit). Het opvangen van een exception geeft je de kans om deze te behandelen:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  buyMoreLlamas();
}

Om code af te handelen die meer dan één type exception kan gooien, kun je meerdere catch clauses specificeren. De eerste catch clause die overeenkomt met het type van het gegooide object, handelt de exception af. Als de catch clause geen type specificeert, kan die clause elk type gegooid object afhandelen:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // Een specifieke exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Alles wat een exception is
  print('Unknown exception: $e');
} catch (e) {
  // Geen gespecificeerd type, handelt alles af
  print('Something really unknown: $e');
}

Zoals de bovenstaande code laat zien, kun je zowel on als catch of beide gebruiken. Gebruik on wanneer je het exception type moet specificeren. Gebruik catch wanneer je exception handler het exception object nodig heeft.

Parameters in catch()

Je kunt één of twee parameters specificeren voor catch(). De eerste is de exception die is gegooid, en de tweede is de stack trace (een StackTrace object).

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

Exception Deels Afhandelen en Doorgeven

Om een exception gedeeltelijk af te handelen en deze toch te laten propagaten, gebruik je het rethrow sleutelwoord.

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // Runtime error
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // Laat de exception doorgaan naar de aanroepers.
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}

Finally

Om ervoor te zorgen dat bepaalde code wordt uitgevoerd, ongeacht of er een exception is gegooid, gebruik je een finally clause. Als geen enkele catch clause overeenkomt met de exception, wordt de exception gepopagated nadat de finally clause is uitgevoerd:

try {
  breedMoreLlamas();
} finally {
  // Altijd opruimen, zelfs als er een exception is gegooid.
  cleanLlamaStalls();
}

De finally clause wordt uitgevoerd na elke overeenkomende catch clause:

try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Eerst de exception afhandelen.
} finally {
  cleanLlamaStalls(); // Dan opruimen.
}

Tijdens de ontwikkeling kun je een assert verklaring gebruiken om de normale uitvoering te onderbreken als een boolean conditie false is.

// Zorg ervoor dat de variabele een niet-nul waarde heeft.
assert(text != null);

// Zorg ervoor dat de waarde minder is dan 100.
assert(number < 100);

// Zorg ervoor dat dit een https-URL is.
assert(urlString.startsWith('https'));

Om een bericht aan een assert toe te voegen, voeg je een string toe als tweede argument aan assert:

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');

Het eerste argument van assert kan elke expressie zijn die evalueert naar een boolean waarde. Als de waarde van de expressie true is, slaagt de assert en gaat de uitvoering door. Als het false is, faalt de assert en wordt er een exception gegooid (een AssertionError).

Wanneer werken assertions?

  • Flutter stelt assertions in tijdens debug-modus.
  • Tools voor alleen ontwikkeling, zoals webdev serve, stellen meestal assertions standaard in.
  • Sommige tools, zoals dart run en dart compile js, ondersteunen assertions via een command-line flag: --enable-asserts.
  • In productiecode worden assertions genegeerd en worden de argumenten van assert niet geëvalueerd.

Voorbeelden en Uitleg

void main() {
  var kind = Kind("Jan", 12);

  // Validatie via assert
  assert(kind.leeftijd > 0, 'Leeftijd moet groter zijn dan 0.');

  try {
    voegKindToeLijst([], Kind("", 10));
  } catch (e) {
    print('Fout opgetreden: $e');
  }

  // Zorg ervoor dat dit een niet-nul waarde heeft
  String? naam;
  assert(naam != null, 'Naam mag niet null zijn.');
}

Met deze uitleg heb je geleerd hoe je exceptions kunt gooien en opvangen, hoe je de finally clause gebruikt, en hoe je assertions kunt gebruiken om je code te valideren tijdens de ontwikkeling. Door deze concepten toe te passen, kun je robuustere en betrouwbaardere toepassingen bouwen.