Excepties en bestanden in Java

Leer hoe Java problemen meldt terwijl een programma wordt uitgevoerd en hoe je daarmee omgaat. Lees stacktraces, onderscheid gecontroleerde van ongecontroleerde excepties en handel fouten af met try, catch en finally. Werp je eigen excepties op en ontwerp exceptieklassen die precies aangeven wat er misging. Lees en schrijf vervolgens tekstbestanden met aandacht voor paden, tekencoderingen en regeleinden, sluit elk bestand veilig met try-with-resources en bouw een programma dat omgaat met ontbrekende bestanden en ongeldige gegevens.

BeginnerLes 9 van 11 in Cursus Java programmeren: klassen, overerving, collecties en streams

Wat je leert

  1. Herken een exceptie wanneer een programma vastloopt, lees de stacktrace om te vinden waar en waarom dat gebeurde en plaats elke exceptie in de klassenhiërarchie van Java als gecontroleerd of ongecontroleerd.
    • Lees een exceptie en de bijbehorende stacktrace
      Leg uit wat er gebeurt wanneer een instructie een exceptie opwerpt, noem veelvoorkomende uitvoeringsexcepties en hun oorzaken en gebruik een stacktrace om het probleem te lokaliseren.
    • Deel excepties in als gecontroleerd of ongecontroleerd
      Plaats elke exceptie in de hiërarchie onder Throwable, bepaal of die gecontroleerd of ongecontroleerd is en pas de regel toe dat gecontroleerde excepties moeten worden opgevangen of gedeclareerd.
  2. Vang excepties op die een programma kan verwachten, herstel de uitvoering op een zinvolle manier, handel meerdere soorten in de juiste volgorde af en voer opruimcode uit ongeacht wat er gebeurt.
    • Vang een exceptie op en herstel de uitvoering
      Schrijf een try-catch-instructie, volg hoe de uitvoering erdoorheen verloopt en herstel de uitvoering na ongeldige invoer in plaats van het programma te laten vastlopen.
    • Handel meerdere exceptietypen in de juiste volgorde af
      Gebruik meerdere catch-clausules of een meervoudige catch-clausule, orden die van specifiek naar algemeen en bepaal waar een try-blok moet beginnen en eindigen.
    • Voer opruimcode uit met finally
      Voeg een finally-blok toe, volg wanneer het wordt uitgevoerd op elk pad door een try-instructie en voorkom fouten waardoor finally problemen verbergt.
  3. Signaleer problemen vanuit je eigen methoden met throw, declareer gecontroleerde excepties met throws en maak exceptieklassen die aanroepers precies vertellen wat er misging.
    • Werp excepties op en declareer die met throws
      Valideer argumenten en de toestand van objecten door standaardexcepties op te werpen, declareer gecontroleerde excepties in methodekoppen en bepaal waar een exceptie moet worden afgehandeld.
    • Maak je eigen exceptieklassen en behoud de oorzaak
      Schrijf je eigen gecontroleerde of ongecontroleerde exceptieklassen, werp die op voordat je de toestand van een object wijzigt en pak een exceptie van een lager niveau in zonder die te verliezen.
  4. Laat een programma naar het juiste bestand verwijzen, begrijp hoe tekst als bytes en regels wordt opgeslagen en zorg dat elk geopend bestand met try-with-resources wordt gesloten.
    • Werk met paden, tekencoderingen en regeleinden
      Stel paden naar bestanden samen, voorspel waar Java bij een relatief pad zoekt en leg uit hoe tekencoderingen, regeleinden en getalnotaties tekstbestanden beïnvloeden.
    • Sluit systeembronnen automatisch met try-with-resources
      Gebruik try-with-resources om bestanden en andere systeembronnen te openen en sluiten, voorspel de sluitvolgorde en leg uit hoe excepties behouden blijven.
  5. Lees tekstbestanden regel voor regel en zet de regels om in gegevens, schrijf resultaten naar bestanden of voeg die achteraan toe en combineer alles in een programma dat omgaat met ontbrekende bestanden en ongeldige records.
    • Lees een tekstbestand en zet de regels om in gegevens
      Lees een bestand met Scanner, Files.readAllLines of BufferedReader, splits elke regel en zet de delen om, en sla regels over of meld die als ze niet aan de verwachte opmaak voldoen.
    • Schrijf tekstbestanden en voeg tekst achteraan toe
      Schrijf tekst naar een nieuw of bestaand bestand, voeg tekst achteraan toe zonder de bestaande inhoud te wissen en zorg dat alles wat je schrijft het bestand ook daadwerkelijk bereikt.
    • Bouw een robuust programma voor bestandsverwerking
      Combineer lezen, parsen, excepties en schrijven in één programma dat bij fouten op bestandsniveau netjes stopt, ongeldige records overslaat en meldt, en gedeeltelijke uitvoer voorkomt.

Excepties en bestanden in Java: uitleg

5 hoofdstukken

1

Begrijp wat excepties zijn en hoe Java die indeelt

Een programma kan met succes compileren en toch mislukken als het een lege array, ongeldige tekst of een ontbrekend bestand krijgt. Het exceptieobject en de bijbehorende stacktrace geven aanwijzingen over die fout. Lees de stacktrace terug via de actieve methodeaanroepen en gebruik daarna de klassenhiërarchie om te bepalen of Java tijdens het compileren een beslissing over de afhandeling vereist. Zo leer je onderscheid maken tussen programmeerfouten die je moet herstellen en verwachte problemen waarvan je programma kan herstellen.

1.1 Zoek de instructie die mislukt

Een exceptie is een object dat een probleem beschrijft dat een actief programma onderbreekt. Het opwerpen ervan stopt de huidige instructie. Java slaat de resterende normale werkzaamheden over totdat een passende exceptieafhandelaar wordt gevonden; zonder zo’n afhandelaar wordt de exceptie teruggegeven via de methoden die de betreffende methode hebben aangeroepen.

Herken het soort probleem

Een ontbrekende puntkomma is een compilatiefout: het programma kan niet compileren. Een exceptie treedt op wanneer gecompileerde code wordt uitgevoerd met gegevens die een probleem veroorzaken.

ExceptieTypische aanleiding
ArithmeticExceptionGeheeltallige deling door nul
ArrayIndexOutOfBoundsExceptiona[3] als de array lengte 3 heeft
IndexOutOfBoundsExceptionlist.get(list.size())
NullPointerExceptionEen methode aanroepen via null
NumberFormatExceptionInteger.parseInt("12a")
InputMismatchExceptionScanner.nextInt() komt “ten” tegen
ClassCastExceptionEen object expliciet converteren naar een klasse waartoe het niet behoort

Array-indexen beginnen bij 0, dus bij lengte 3 zijn de geldige indexen 0, 1 en 2. Voor deling met zwevendekommagetallen gelden andere regels: 10.0 / 0 levert Infinity op; er wordt geen exceptie voor geheeltallige deling opgeworpen.

Lees een stacktrace vanaf de bovenkant

Hier staat een volledige klasse, zonder lege regels vóór de eerste regel:

public class Average {
    static int average(int[] values) {
        int sum = 0;
        for (int value : values) sum += value;
        return sum / values.length;
    }
    public static void main(String[] args) {
        int[] values = new int[0];
        System.out.println(average(values));
    }
}

De array is leeg, dus de lengte is 0. De deling op regel 5 mislukt. De stacktrace is:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Average.average(Average.java:5)
    at Average.main(Average.java:9)
  1. Lees op de eerste regel de exceptieklasse en de melding.
  2. Lees het bovenste at-frame voor de plaats waar het probleem is vastgesteld.
  3. Lees naar beneden voor de aanroepers: main riep average aan op regel 9.
  4. Als de bovenste frames bij de bibliotheek van Java horen, zoek dan het eerste frame dat je eigen klasse noemt. Bij een mislukte Integer.parseInt kunnen bibliotheekframes vóór de aanroep in je code staan.

De stacktrace volgt de aanroepstack, de keten van actieve methodeaanroepen. Die vertelt je waar je moet zoeken, maar de ongeldige waarde kan eerder zijn ontstaan. Hier stelt de deling het probleem vast; de aanroeper gaf de lege array door. Bepaal of lege invoer moet worden afgewezen of afgehandeld voordat je een gemiddelde berekent.

Bekijk het exceptieobject

e.getMessage() geeft de melding terug en kan null teruggeven. e.toString() bevat de klassenaam en, indien aanwezig, de melding. e.printStackTrace() schrijft de stacktrace naar de standaardfoutstroom. Een onderdeel Caused by: toont een eerdere exceptie die in een wrapper is bewaard.

Door de JVM gegenereerde meldingen van NullPointerException geven normaal gesproken aan welke expressie null was. Een expliciet aangemaakte exceptie kan daarentegen een eigen melding of geen melding hebben. Volg de referentie terug naar de plaats waar die een object had moeten krijgen.

Een niet-afgehandelde exceptie die main verlaat, beëindigt de hoofdthread; daarmee eindigt een programma met één thread. Herstel programmeerfouten zoals verkeerde indexen in de code. Bereid herstel voor bij verwachte externe problemen, zoals een ontbrekend bestand of ongeldige gebruikersinvoer.

Belangrijkste punten

  • Een exceptie onderbreekt de normale uitvoering; overgeslagen instructies worden niet automatisch hervat.
  • Lees de exceptieklasse en de melding en volg daarna de stackframes van de vastgestelde fout naar de aanroepers.
  • Bibliotheekframes kunnen vóór het eerste frame in je eigen code staan.
  • De mislukte instructie kan een ongeldige waarde aan het licht brengen die eerder is ontstaan.
  • Herstel programmeerfouten en handel verwachte invoer- of bestandsproblemen af.

1.2 Gecontroleerde en ongecontroleerde excepties

Exceptieklassen gebruiken de overervingsregels die je al kent. Een opgeworpen object van een subklasse behoort ook tot de superklasse. Dat verklaart zowel de exceptiecategorieën van Java als hoe een passende afhandelaar wordt gevonden.

Volg de hiërarchie

Alleen objecten van Throwable of de subklassen daarvan kunnen worden opgeworpen. Daaronder staan twee hoofdtakken:

Throwable
  Error
    OutOfMemoryError
    StackOverflowError
  Exception
    RuntimeException
      IllegalArgumentException
        NumberFormatException
      NullPointerException
      IndexOutOfBoundsException
        ArrayIndexOutOfBoundsException
    IOException
      FileNotFoundException
      NoSuchFileException

Error beschrijft ernstige fouten van de uitvoeringsomgeving. Een gewone applicatie moet niet proberen te herstellen van een uitgeputte heap of een stack die door eindeloze recursie is uitgeput. Exception beschrijft problemen die een applicatie kan afhandelen, inclusief de tak RuntimeException.

CategorieKlassenEis van de compiler
OngecontroleerdRuntimeException, Error en hun subklassenOpvangen of declareren is optioneel
GecontroleerdAlle andere subklassen van ThrowableOpvangen of declareren als de code ze kan opwerpen

Beide soorten worden tijdens de uitvoering opgeworpen. Het woord “gecontroleerd” beschrijft dat de compiler je afhandeling controleert, niet dat de fout op een eerder moment optreedt. Ongecontroleerd betekent ook niet onschadelijk: een niet-afgehandelde null-referentie kan een programma stoppen.

Pas opvangen of declareren toe

Een bestand lezen kan ook in correcte code mislukken. Een hulpmethode kan de beslissing aan de aanroeper overlaten:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

class Names {
    static List<String> load(Path file) throws IOException {
        return Files.readAllLines(file);
    }
}

Files.readAllLines kan de gecontroleerde IOException opwerpen. De declaratie geeft die mogelijkheid door aan de aanroeper, die de exceptie ook moet opvangen of declareren. Als je throws IOException verwijdert zonder een afhandelaar toe te voegen, compileert de hulpmethode niet. Een methode die Integer.parseInt gebruikt, heeft geen vergelijkbare verplichting van de compiler omdat NumberFormatException ongecontroleerd is.

Gecontroleerde fouten beschrijven vaak omstandigheden waarop een aanroeper zich kan voorbereiden, zoals een bestand dat verdwijnt. Uitvoeringsfouten wijzen vaak op programmeerfouten of ongeldige argumenten. Dat zijn nuttige redenen voor het ontwerp, maar de keten van superklassen bepaalt de categorie. Een eigen klasse die RuntimeException uitbreidt, blijft ongecontroleerd, ook als een aanroeper kan herstellen.

Koppel afhandelaars via overerving

catch (IOException e) kan een FileNotFoundException of NoSuchFileException afhandelen. catch (Exception e) vangt ook uitvoeringsexcepties op; die kan een programmeerfout veranderen in een misleidende invoermelding. catch (Throwable e) bereikt ook de tak Error en is zelden geschikt voor normaal herstel.

Om een onbekende klasse in te delen, volg je de overerving omhoog in de API-documentatie. InputMismatchException breidt NoSuchElementException uit, dat RuntimeException uitbreidt, dus is die ongecontroleerd. InterruptedException breidt Exception uit buiten de uitvoeringstak en is dus gecontroleerd. Een ongecontroleerd type declareren in een throws-clausule is toegestaan, maar verandert de categorie niet.

Belangrijkste punten

  • RuntimeException, Error en al hun subklassen zijn ongecontroleerd.
  • Andere subklassen van Throwable zijn gecontroleerd; code die ze kan opwerpen moet ze opvangen of declareren.
  • Zowel gecontroleerde als ongecontroleerde excepties treden tijdens de uitvoering op.
  • Een catch voor een superklasse komt ook overeen met de subklassen daarvan.
  • Een brede Exception-afhandelaar kan programmeerfouten verbergen.
  • Deel een onbekende exceptie in aan de hand van de keten van superklassen.
2

Handel excepties af met try, catch en finally

De afhandeling van een fout verandert welke instructies daarna worden uitgevoerd. Een nuttige afhandelaar moet bij de exceptie passen en het programma gereedmaken om verder te gaan, terwijl opruimcode ook moet worden uitgevoerd op paden die voortijdig worden verlaten. Volg conversies en lussen stap voor stap, kies specifieke afhandelaars vóór algemene en plaats het beschermde blok rond de werkzaamheden die samen moeten mislukken. Volg daarna hoe finally zich gedraagt wanneer een exceptie wordt doorgegeven of een methode terugkeert.

2.1 Herstel na een mislukte conversie

Een try-blok markeert werkzaamheden die kunnen mislukken. Een passend catch-blok geeft het programma een nuttige volgende actie, zoals om een andere waarde vragen. De exceptie afhandelen probeert de mislukte instructie niet vanzelf opnieuw.

Volg de paden
System.out.println("A");
try {
    System.out.println("B");
    int value = Integer.parseInt("4x");
    System.out.println("C");
} catch (NumberFormatException e) {
    System.out.println("D: " + e.getMessage());
}
System.out.println("E");

De uitvoer is A, B, D: For input string: "4x" en E, elk op een eigen regel. De conversie mislukt, dus slaat Java C over en gaat naar de passende afhandelaar. Wanneer die afhandelaar normaal eindigt, gaat de uitvoering na de volledige instructie verder. Als de conversie slaagt, wordt de afhandelaar overgeslagen. Als het blok een ArithmeticException opwerpt, past deze afhandelaar niet; die exceptie wordt doorgegeven.

Probeer opnieuw met nieuwe invoer

Lees een hele regel voordat je die omzet. De onderstaande lus accepteert een geheel getal en handelt het einde van de toetsenbordinvoer af door te melden dat geen waarde is opgegeven:

import java.util.Scanner;

class WholeNumbers {
    static int readWholeNumber(Scanner in) {
        while (in.hasNextLine()) {
            String line = in.nextLine();
            try {
                return Integer.parseInt(line.trim());
            } catch (NumberFormatException e) {
                System.out.println("Please enter a whole number.");
            }
        }
        throw new IllegalStateException("No number supplied");
    }
}

Bij de invoer “twenty” en “20” geeft de afhandelaar één keer een melding weer, leest de lus een nieuwe regel en retourneert de methode 20. trim() verwijdert omringende witruimte: Integer.parseInt(" 20") mislukt anders. De conversie accepteert een optioneel teken en cijfers die een geheel getal binnen het bereik voorstellen.

Een scanner die met tokens werkt, heeft een andere oplossing nodig. Wanneer nextInt() “ten” tegenkomt, laat de bijbehorende InputMismatchException die token ongelezen. Opvangen en opnieuw nextInt() aanroepen herhaalt de fout eindeloos. Verbruik de ongeldige token met next() of sla de regel over met nextLine() voordat je het opnieuw probeert. hasNextInt() kan een token vóór de conversie controleren.

Houd de herstelde toestand bruikbaar

Een variabele die binnen try is gedeclareerd, bestaat alleen in dat blok. Als latere code het resultaat nodig heeft, declareer die dan erbuiten en laat elk pad dat doorgaat een geldige waarde toewijzen:

int quantity;
try {
    quantity = Integer.parseInt("bad");
} catch (NumberFormatException e) {
    quantity = 0;
}
System.out.println(quantity);

Nul is hier alleen geschikt als het programma die waarde als een geldig alternatief definieert. Als quantity in de afhandelaar geen waarde krijgt, veroorzaakt dat een compilatiefout omdat de variabele niet op alle paden zeker een waarde heeft gekregen.

Vang het specifieke type op dat je kunt afhandelen. Een lege afhandelaar laat het probleem ongemerkt verloren gaan; een brede catch (Exception e) kan een null-referentiefout als een ongeldig getal aanduiden. Bij herstel kun je opnieuw om invoer vragen, één element overslaan, een geldige standaardwaarde kiezen, een fout melden of een betekenisvolle exceptie doorgeven. Controleer bij eenvoudige voorspelbare grenzen eerst: index >= 0 && index < list.size() voorkomt zowel negatieve als te grote lijstindexen.

Belangrijkste punten

  • Een passende afhandelaar wordt uitgevoerd nadat de rest van het mislukte try-blok is overgeslagen.
  • Een lus moet nieuwe invoer lezen voordat die het opnieuw probeert.
  • Scanner.nextInt() laat een token van het verkeerde type ongelezen.
  • Elk pad dat doorgaat, moet variabelen die later worden gebruikt een zinvolle beginwaarde geven.

2.2 Kies afhandelaars en de werkzaamheden die ze beschermen

Een bestand kan ontbreken, onleesbaar zijn of vol onjuist gevormde records staan. Die fouten vragen om verschillende reacties. Met meerdere afhandelaars kan één try ze onderscheiden, terwijl de plaats van het blok bepaalt hoeveel werk stopt als er iets mislukt.

Zet specifieke afhandelaars voorop

Java toetst afhandelaars van boven naar beneden en voert de eerste passende afhandelaar uit. Daarna worden geen andere afhandelaars voor dezelfde exceptie uitgevoerd.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;

class FirstCount {
    static void show(Path file) {
        try {
            int count = Integer.parseInt(Files.readString(file).trim());
            System.out.println(count);
        } catch (NoSuchFileException e) {
            System.out.println("File not found: " + file.toAbsolutePath());
        } catch (IOException e) {
            System.out.println("Could not read: " + file.toAbsolutePath());
        } catch (NumberFormatException e) {
            System.out.println("The file must contain one whole number.");
        }
    }
}

NoSuchFileException breidt IOException uit en moet dus eerst komen. Als je de volgorde omdraait, wordt de specifieke afhandelaar onbereikbaar en compileert de code niet. De conversie-exceptie is niet verwant aan IOException, dus die twee afhandelaars mogen in beide volgordes staan.

Een afhandelaar voor een gecontroleerde exceptie moet ook relevant zijn voor de beschermde werkzaamheden. IOException opvangen rond alleen int count = 5; wordt afgewezen omdat dat blok de exceptie niet kan opwerpen. Deze beperking geldt niet op dezelfde manier voor ongecontroleerde typen of de brede typen Exception en Throwable.

Deel een afhandelaar als de reactie hetzelfde is

Een meervoudige catch-clausule verbindt niet-verwante exceptietypen met |:

try {
    String[] parts = "Ana".split(",");
    int age = Integer.parseInt(parts[1]);
    System.out.println(age);
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
    System.out.println("Invalid record: " + e.getMessage());
}

Hier veroorzaakt het ontbrekende tweede veld de indexexceptie. Een aanwezig veld dat geen getal bevat, zou de conversie-exceptie veroorzaken en beide krijgen dezelfde reactie. De parameter van de meervoudige catch-clausule is impliciet final. Alternatieven kunnen geen subklasse en de bijbehorende superklasse zijn: FileNotFoundException | IOException is ongeldig omdat IOException beide al omvat.

Bepaal wat één fout moet overslaan

Bekijk de teksten “3”, “x” en “5”. Met een try rond de hele lus stopt de verwerking bij “x” en is de som tot dan toe 3. Zet de try binnen de lus om voor elk element afzonderlijk te herstellen:

int sum = 0;
for (String text : new String[] {"3", "x", "5"}) {
    try {
        sum += Integer.parseInt(text);
    } catch (NumberFormatException e) {
        System.out.println("Skipped: " + text);
    }
}
System.out.println(sum);

Dit geeft Skipped: x en daarna 8 weer. De lus gaat verder omdat de lusbody de fout van dat record heeft afgehandeld. Bij geneste afhandelaars wordt vanuit het binnenste beschermde blok naar buiten gezocht; als een binnenste afhandelaar niet past, krijgt een buitenste de kans. Kies de kleinste werkeenheid die in haar geheel moet mislukken: één record voor ongeldige gegevens, de bestandsbewerking voor een leesfout.

Belangrijkste punten

  • Java voert voor elke exceptie hoogstens één passende afhandelaar uit.
  • Vang een subklasse op vóór de superklasse.
  • Een meervoudige catch-clausule deelt een reactie tussen niet-verwante exceptietypen.
  • Een meervoudige catch-clausule kan een superklasse niet combineren met de subklasse daarvan.
  • Plaats herstel op recordniveau binnen de lus om door te gaan met latere records.

2.3 Voer opruimcode uit voordat de uitvoering verdergaat

Sommige werkzaamheden moeten gebeuren ongeacht of een bewerking slaagt of mislukt. Een finally-blok wordt uitgevoerd wanneer de uitvoering de bijbehorende try-instructie verlaat, ook wanneer een exceptie wordt doorgegeven of een methode terugkeert.

Volg een exceptie zonder passende afhandelaar
try {
    System.out.println("1");
    int[] values = new int[2];
    values[2] = 7;
    System.out.println("2");
} catch (NumberFormatException e) {
    System.out.println("3");
} finally {
    System.out.println("4");
}
System.out.println("5");

Alleen 1 en 4 worden weergegeven voordat de ArrayIndexOutOfBoundsException wordt doorgegeven. Index 2 valt buiten de array met twee elementen. De afhandelaar past niet, maar finally wordt toch uitgevoerd. De instructie die 5 weergeeft, staat buiten het opruimblok en wordt daarom door de doorgegeven exceptie overgeslagen.

Als de beschermde werkzaamheden in plaats daarvan een passende NumberFormatException opwerpen na het weergeven van 1, geeft de afhandelaar 3 weer, geeft de opruimcode 4 weer en gaat de uitvoering verder naar 5. Als alles slaagt, wordt geen afhandelaar uitgevoerd, maar wel de opruimcode.

Retourwaarden worden vóór het opruimen voorbereid
class Cleanup {
    static int result() {
        try {
            return 1;
        } finally {
            System.out.println("cleanup");
        }
    }
}

Eerst wordt de retour­expressie geëvalueerd. Java geeft daarna cleanup weer en de aanroeper ontvangt 1. Een break of continue die een beschermd codegebied verlaat, voert ook de bijbehorende opruimcode uit voordat de overdracht van de uitvoering plaatsvindt.

Houd return buiten finally. Een return 2; daarin zou de wachtende retourwaarde vervangen en zelfs een wachtende exceptie kunnen laten vervallen. Een exceptie die door de opruimcode wordt opgeworpen, kan op dezelfde manier de oorspronkelijke fout vervangen. Opruimcode moet geen tweede concurrerend resultaat opleveren. De compileroptie -Xlint:finally waarschuwt wanneer een finally-blok niet normaal kan eindigen.

Sluit een object alleen als het is geopend

Het oudere handmatige patroon heeft een variabele nodig die zichtbaar is voor het opruimblok:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;

class ManualRead {
    static void firstLine(Path file) throws IOException {
        Scanner sc = null;
        try {
            sc = new Scanner(file, StandardCharsets.UTF_8);
            if (sc.hasNextLine()) System.out.println(sc.nextLine());
            if (sc.ioException() != null) throw sc.ioException();
        } finally {
            if (sc != null) sc.close();
        }
    }
}

Als het openen mislukt, is sc nog steeds null, zodat de controle voorkomt dat de opruimcode een nieuwe null-referentie-exceptie opwerpt. Voor objecten die kunnen worden gesloten, neemt try-with-resources dit beheerwerk weg en handelt het concurrerende fouten veiliger af.

finally biedt geen garantie als de machine stopt. System.exit beëindigt de JVM zonder deze opruimcode uit te voeren; ook een crash of stroomuitval verhindert de uitvoering. Een oneindige lus die het blok nooit verlaat, bereikt de bijbehorende finally evenmin.

Belangrijkste punten

  • finally wordt uitgevoerd bij normale voltooiing, opgevangen en niet-opgevangen excepties en overdrachten van de uitvoering zoals return.
  • Een retourexpressie wordt geëvalueerd voordat de opruimcode wordt uitgevoerd.
  • Code na een try-instructie wordt overgeslagen wanneer een exceptie wordt doorgegeven; finally wordt nog wel bereikt.
  • Een return of opgeworpen exceptie in finally kan het oorspronkelijke resultaat verbergen.
  • Try-with-resources is de gebruikelijke keuze om systeembronnen voor bestanden te sluiten.
  • Beëindiging van de JVM of een blok dat nooit eindigt, kan het uitvoeren van opruimcode verhinderen.
3

Werp excepties op en ontwerp je eigen excepties

Een ongeldig verzoek is het gemakkelijkst te onderzoeken voordat het een object verandert. Je methoden kunnen ongeldige argumenten of toestanden afwijzen met standaardexcepties en domeinproblemen zichtbaar maken met eigen klassen. De methodedeclaratie informeert aanroepers over gecontroleerde fouten; overerving beperkt wat een overschrijvende methode kan toevoegen. Als je een fout van een lager niveau omzet in een nuttigere fout, behoud dan de oorzaak zodat de aanroeper zowel context als de oorspronkelijke informatie voor het opsporen van de fout krijgt.

3.1 Signaleer ongeldige argumenten en toestanden

Je methoden kunnen ongeldige verzoeken afwijzen voordat ze een object wijzigen. Kies een exceptie die het probleem aanduidt en de aanroeper laat reageren.

Werp direct een object op
class Percentage {
    private int value;

    public void setPercentage(int value) {
        if (value < 0 || value > 100) {
            throw new IllegalArgumentException(
                "percentage must be 0 to 100, was " + value);
        }
        this.value = value;
    }
}

De aanroep setPercentage(120) werpt een exceptie op met de melding percentage must be 0 to 100, was 120. De toewijzing is niet uitgevoerd, dus het veld behoudt zijn vorige waarde. Dit is vroegtijdig afbreken: meld het ongeldige verzoek op de plaats waar je het kunt uitleggen. Dezelfde controle in een constructor voorkomt dat een ongeldig object wordt teruggegeven.

throw heeft een exceptieobject nodig, zoals in throw new IllegalArgumentException("bad quantity");. Een klassenaam alleen is geen object. Een gewone instructie direct na een onvoorwaardelijke throw in hetzelfde blok is onbereikbaar.

ProbleemStandaardexceptie
Argument heeft een ongeldige waardeIllegalArgumentException
Object heeft de verkeerde toestand voor de aanroepIllegalStateException
Vereiste objectreferentie is nullNullPointerException
Klasse biedt de bewerking niet aanUnsupportedOperationException
Positie valt buiten een collectieIndexOutOfBoundsException

Objects.requireNonNull(name, "name must not be null") uit java.util.Objects is een handige controle op null. Een al verzonden bestelling die een extra artikel afwijst, heeft een toestandsprobleem; een negatief aantal artikelen is een argumentprobleem.

Declareer wat de methode kan verlaten

Een hulpmethode die een bestand leest, kan de bijbehorende gecontroleerde fout declareren:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

class NameLoader {
    static List<String> loadNames(Path file) throws IOException {
        return Files.readAllLines(file);
    }
}

throw is een uitvoerbare instructie. throws hoort bij de methodedeclaratie en vertelt aanroepers welke gecontroleerde fouten ze moeten afhandelen. Het vangt een fout niet op en laat de methode na een fout ook niet doorgaan. Elke aanroeper moet IOException opvangen of op zijn beurt declareren. Een catch kan hetzelfde object ook opnieuw opwerpen met throw e;.

Vang een exceptie op waar een nuttige reactie mogelijk is. Een hulpmethode kan de gebruiker meestal niet vragen een ander bestand te kiezen, maar main kan dat wel. “fout” weergeven en een lege lijst teruggeven zou een ontbrekend bestand verwarren met een daadwerkelijk leeg bestand. Bij een klein experiment mag main throws IOException declareren; een afgerond programma handelt verwachte fouten af met nuttige meldingen. Ongecontroleerde typen mogen ter documentatie worden gedeclareerd, ook al vereist de compiler dat niet.

Respecteer het overgeërfde contract

Als een interface read() throws IOException declareert, mag een overschrijvende methode IOException, een specifiekere gecontroleerde subklasse of geen gecontroleerde exceptie declareren. De methode mag de declaratie niet verbreden tot Exception. Ongecontroleerde typen declareren mag wel. Een overschrijving van Object.toString() kan geen IOException toevoegen, omdat de overgeërfde methode geen gecontroleerde excepties declareert. Aanroepen via het interfacetype moeten de gedeclareerde IOException nog steeds afhandelen, ook wanneer een implementatie geen exceptie declareert.

Belangrijkste punten

  • Gebruik throw met een exceptieobject om een ongeldige bewerking te stoppen.
  • Valideer voordat je velden of collecties wijzigt.
  • throws declareert een mogelijke fout; het handelt die niet af.
  • Vang de fout op waar zinvol herstel mogelijk is; geef die anders door aan de aanroeper.
  • Overschrijvende methoden kunnen geen nieuwe of bredere gecontroleerde excepties toevoegen.

3.2 Beschrijf domeinfouten en behoud de oorzaken

Een standaardexceptie is vaak voldoende. Maak een eigen klasse als aanroepers een specifiek probleem van het programma moeten herkennen, zoals onvoldoende voorraad of een onjuist gevormd gegevensrecord, en er anders op moeten reageren.

Kies de superklasse bewust

Door Exception uit te breiden maak je een gecontroleerde exceptie. Door RuntimeException uit te breiden maak je een ongecontroleerde exceptie. Kies het gecontroleerde ontwerp wanneer aanroepers rekening moeten houden met een domeinfout waarvan herstel mogelijk is; kies het ongecontroleerde ontwerp bij verkeerd gebruik of een programmeerfout.

class OutOfStockException extends Exception {
    public OutOfStockException(String message) {
        super(message);
    }
}

super(message) slaat de melding op via de overgeërfde exceptiefunctionaliteit, zodat getMessage() die teruggeeft. De klassenaam eindigt volgens afspraak op Exception. Extra velden en getters kunnen gestructureerde details beschikbaar maken, zoals het gevraagde en het beschikbare aantal.

Laat de voorraad na een fout ongewijzigd
import java.util.HashMap;

class Inventory {
    private final HashMap<String, Integer> stock = new HashMap<>();

    Inventory() {
        stock.put("pens", 12);
    }

    void remove(String item, int quantity) throws OutOfStockException {
        if (quantity <= 0) {
            throw new IllegalArgumentException("quantity must be positive");
        }
        int available = stock.getOrDefault(item, 0);
        if (quantity > available) {
            throw new OutOfStockException("Requested " + quantity
                + " of " + item + ", only " + available + " in stock");
        }
        stock.put(item, available - quantity);
    }
}

Als je begint met 12 pennen, blijven er na het verwijderen van 5 nog 7 over. Een later verzoek om 10 werpt een exceptie op en er blijven 7 over, omdat de bijwerking na alle controles komt. De aanroeper moet de gecontroleerde voorraadexceptie afhandelen of declareren; de exceptie voor een ongeldig aantal is ongecontroleerd. Een programma dat een afzonderlijke reactie op een onbekend artikel nodig heeft, kan een verwante UnknownItemException gebruiken, met beide domeintypen onder een basisklasse InventoryException.

Pak in zonder het oorspronkelijke probleem te verliezen

Een parser kan een conversiefout van een lager niveau omzetten in een fout op recordniveau:

class InvalidRecordException extends Exception {
    public InvalidRecordException(String message) {
        super(message);
    }
    public InvalidRecordException(String message, Throwable cause) {
        super(message, cause);
    }
}

Binnen de parsemethode kan een afhandelaar dit doen:

catch (NumberFormatException e) {
    throw new InvalidRecordException(
        "Line 3: quantity is not a number: x", e);
}

De wrapper geeft de aanroeper een betekenisvolle categorie en een regelnummer. De methode getCause() geeft de oorspronkelijke NumberFormatException terug en een weergegeven stacktrace behoudt een onderdeel Caused by:. Als je een nieuwe exceptie maakt met alleen de oude melding, gaan het oorspronkelijke object en de bijbehorende stacktrace verloren.

java.io.UncheckedIOException is een kant-en-klare ongecontroleerde wrapper speciaal voor IOException. De constructoren accepteren de oorzaak, met een optionele melding. De wrapper kan een bestandsfout doorgeven via een overschrijvende methode die geen gecontroleerde declaratie mag toevoegen. Inpakken verandert het type dat de aanroeper ziet; het herstelt het bestandsprobleem niet. Gebruik voor gewone beslissingen in een lus voorwaarden en break, zonder excepties te bedenken voor het normale verloop.

Belangrijkste punten

  • Met eigen klassen kunnen aanroepers betekenisvolle domeinfouten herkennen.
  • Breid Exception uit voor een gecontroleerde klasse of RuntimeException voor een ongecontroleerde klasse.
  • Roep super(message) aan om een nuttige foutmelding te behouden.
  • Valideer het hele verzoek voordat je de toestand bijwerkt.
  • Geef de oorspronkelijke exceptie als oorzaak door wanneer je die inpakt.
  • UncheckedIOException geeft een IOException door als ongecontroleerde fout.
4

Bepaal bestandslocaties en sluit systeembronnen veilig

Een tekstbestand moet correct worden gevonden, gedecodeerd en gesloten. Een relatief pad hangt af van de werkmap, terwijl bytes alleen met de juiste codering leesbare tekens worden. Bij tekst met getallen en regeleinden moet je eigen keuzes maken voor uitwisselbaarheid. Zodra een bestand open is, geeft try-with-resources het bij elke manier van verlaten vrij en houdt het de hoofdfout zichtbaar als het sluiten ook mislukt. Door deze keuzes kun je latere code voor lezen en schrijven beter vertrouwen.

4.1 Laat tekstbestanden op verschillende computers werken

Een bestand slaat bytes op, terwijl je programma met tekens en getallen werkt. Voor een geslaagde leesbewerking zijn de juiste locatie, de juiste tekencodering en een duidelijke afspraak voor regels en tekst met getallen nodig.

Zoek de werkelijke locatie

Een relatief pad begint vanuit de werkmap van het programma. Het begint niet vanuit de map met de broncode. Een absoluut pad begint bij de hoofdmap van het bestandssysteem, zoals /home/ana/data/scores.txt, of bij de hoofdmap van een schijf op Windows.

Path file = Path.of("data", "scores.txt");
System.out.println(System.getProperty("user.dir"));
System.out.println(file.toAbsolutePath());
System.out.println(file.getFileName());

Importeer java.nio.file.Path. Als je deze Path aanmaakt, wordt niets geopend en wordt niet gecontroleerd of iets bestaat. toAbsolutePath() laat zien waar Java zal zoeken en getFileName() geeft scores.txt. Een IDE gebruikt vaak de projectmap als werkmap. Schuine strepen in "data/scores.txt" werken op Windows, Linux en macOS. In een Windows-padliteral met backslashes moeten die worden verdubbeld, zoals in "C:\\data\\scores.txt". Ook de oudere java.io.File stelt een locatie voor; zet de vormen om met toPath() of toFile().

Koppel bytes aan tekens

UTF-8 codeert elk Unicode-teken. Latijnse basistekens nemen één byte in; andere twee tot vier. De tekst “café” bevat vier tekens maar vijf UTF-8-bytes omdat “é” er twee inneemt. Als je die bytes als ISO-8859-1 leest, kan “café” ontstaan. Gebruik de codering die bij het schrijven is gebruikt.

De tekstmethoden van Files gebruiken standaard UTF-8. Klassen zoals FileWriter en een scanner die zonder tekenset is geopend, gebruiken de standaardtekenset, die vanaf Java 18 UTF-8 is; bij oudere installaties kan die anders zijn. Met StandardCharsets.UTF_8 uit java.nio.charset maak je de keuze expliciet. Ongeldige bytes die door Files.readAllLines worden gelezen, leiden tot MalformedInputException, een subklasse van IOException.

Lees regels zonder achtergebleven regeleinden
ConventieEscapesequentie in een Java-string
Regeleinde van Linux en macOS\n
Gebruikelijk regeleinde van Windows\r\n

Met een afsluiting na elke regel hebben “a” en “b” vier bytes nodig met LF-regeleinden en zes met CRLF-regeleinden. BufferedReader.readLine(), Files.readAllLines en Scanner.nextLine() verwijderen herkende regeleinden. Als je een volledige string splitst met split("\n"), blijft de Windows-\r staan, zodat het omzetten van "12\r" met parseInt mislukt. Gebruik bij voorkeur methoden die regels lezen of verwijder de omringende witruimte. System.lineSeparator() en opmaakspecificatie %n produceren het regeleinde van het huidige systeem.

Houd bestanden met getallen consistent

Integer.parseInt accepteert tekst met een geheel getal zonder decimaalteken. Double.parseDouble("3.5") accepteert een punt; Double.parseDouble("3,5") mislukt. Deze parseermethoden negeren de taal- en regio-instelling. Numerieke methoden van Scanner en gewone decimale opmaak volgen die instelling wel, zodat Duitse of Nederlandse instellingen “3,5” kunnen verwachten en “3,50” kunnen produceren. Gebruik scanner.useLocale(Locale.ROOT) en String.format(Locale.ROOT, "%.2f", value) voor gegevens met een decimale punt; importeer java.util.Locale.

Ontbrekende locaties leiden vaak tot NoSuchFileException bij Files of Scanner(Path), terwijl oudere constructoren met een bestandsnaam FileNotFoundException kunnen geven. Ontbrekende toestemming kan AccessDeniedException opleveren. Dit zijn gecontroleerde invoer- en uitvoerfouten: een correcte padexpressie alleen kan ze niet voorkomen.

Belangrijkste punten

  • Relatieve paden worden bepaald vanuit de werkmap.
  • Een Path aanmaken opent of controleert het bestand niet.
  • Gebruik dezelfde codering voor lezen en schrijven; kies UTF-8 expliciet waar standaardinstellingen kunnen verschillen.
  • Methoden die regels lezen verwijderen de regeleinden LF, CRLF en CR.
  • Double.parseDouble gebruikt een punt; voor numerieke methoden die van taal- en regio-instellingen afhangen, moet je een instelling kiezen.
  • Bij het openen en lezen van bestanden moet je nog steeds gecontroleerde excepties afhandelen.

4.2 Laat Java elke geopende systeembron sluiten

Een open bestand gebruikt een systeembron van het besturingssysteem. Sluiten geeft die vrij en schrijft de nog aanwezige uitvoer van een bestandsschrijver door. Als je vergeet te sluiten, kun je de limiet voor open bestanden bereiken, gebufferde tekst verliezen of een ander programma verhinderen het bestand te wijzigen.

Declareer systeembronnen in de try-kop
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

class Lines {
    static void show(Path file) throws IOException {
        try (BufferedReader in =
                Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

De kop opent de lezer. De body gebruikt die en Java sluit de lezer wanneer de body normaal eindigt, terugkeert of een exceptie opwerpt. Een afzonderlijke finally is niet nodig. Hier is geen afhandelaar, dus wordt elke gecontroleerde fout nog steeds via throws IOException aan de aanroeper doorgegeven.

Een systeembron moet AutoCloseable implementeren. Die interface declareert close() en staat Exception toe; de subinterface Closeable beperkt de gedeclareerde gecontroleerde fout tot IOException. Bestandslezers, bestandsschrijvers en Scanner voldoen daaraan. Een String niet. Variabelen in de kop zijn impliciet final en beschikbaar in de body, maar niet in de catch- of finally-blokken van die instructie. Java 9 en later staan ook een bestaande final of effectief final variabele toe: try (in) { ... }.

Sluit in omgekeerde volgorde

Scheid systeembronnen met puntkomma’s:

try (BufferedReader in = Files.newBufferedReader(source);
     java.io.BufferedWriter out = Files.newBufferedWriter(target)) {
    String line;
    while ((line = in.readLine()) != null) {
        out.write(line);
        out.newLine();
    }
}

Dit is een blok binnen een methode die IOException declareert, met verschillende paden voor source en target. Java opent eerst in, daarna out, en sluit out vóór in. Als het openen van out mislukt, wordt de al geopende lezer toch gesloten. Als je een schrijver opent op het invoerpad, wordt die invoer afgekapt. Daarom moeten de paden voor deze directe kopie verschillen.

Systeembronnen worden gesloten vóór de catch- en finally-clausules van dezelfde instructie. Die afhandelaars kunnen fouten ontvangen die ontstaan bij het openen, gebruiken of sluiten van de systeembronnen.

Houd de hoofdfout zichtbaar

Stel dat de body een recordexceptie opwerpt en dat het sluiten van de lezer daarna een IOException opwerpt. Try-with-resources geeft de exceptie uit de body door en voegt de sluitfout toe als onderdrukte exceptie. getSuppressed() haalt die op en de stacktrace geeft een onderdeel Suppressed: weer. De oorspronkelijke fout uit de body blijft zichtbaar. Als de body slaagt en alleen het sluiten mislukt, wordt de sluitexceptie normaal doorgegeven.

Bij meerdere fouten tijdens het sluiten probeert Java de overige systeembronnen nog steeds te sluiten. Een gewone finally { resource.close(); } kan daarentegen een wachtende fout uit de body vervangen door een opruimfout.

Gebruik dit patroon voor bestandssysteembronnen die je code zelf beheert. Als je een scanner op System.in sluit, sluit je ook de toetsenbordinvoer van het programma, waardoor later lezen niet meer mogelijk is. Laat het beheer van gedeelde standaardinvoer op programmaniveau in plaats van die in een hulpmethode te sluiten.

Belangrijkste punten

  • Try-with-resources sluit succesvol geopende systeembronnen bij zowel normaal als uitzonderlijk verlaten.
  • Alleen AutoCloseable-objecten komen als systeembron in aanmerking.
  • Systeembronnen openen van links naar rechts en sluiten van rechts naar links.
  • Het sluiten gebeurt vóór de catch- en finally-blokken van dezelfde instructie.
  • Een fout uit de body blijft de hoofdfout; latere sluitfouten worden onderdrukt.
  • Automatisch sluiten vervangt de afhandeling volgens de opvangen-of-declarerenregel niet.
  • Een scanner sluiten sluit ook de bijbehorende invoerbron als die kan worden gesloten.
5

Lees en schrijf tekstbestanden

Bestandsverwerking verbindt externe bytes met de objecten en resultaten die je programma gebruikt. Lees regels met een methode die past bij de omvang van de invoer, valideer velden vóór de conversie en kies bewust of je bij het schrijven vervangt of achteraan toevoegt. Een volledig rapport vereist afzonderlijke reacties op een ongeldig record en een onbruikbaar bestand. Stel het resultaat samen voordat je het opslaat en gebruik daarna tijdelijke uitvoer en een ondersteunde atomaire verplaatsing wanneer een bestaand doelbestand moet worden beschermd.

5.1 Lees regels en zet die om in objecten

Lezen levert tekst op. Parsen geeft die tekst betekenis: een aantal, een leeftijd of een object. Houd die twee bewerkingen gescheiden, zodat een ongeldig record niet lijkt op een mislukte bestandslezing.

Kies hoeveel je in het geheugen bewaart
MethodeResultaat en gebruik
Files.readAllLines(path)Een lijst met alle regels; handig voor kleine bestanden
Files.readString(path)Eén string met behoud van regeleinden
BufferedReader.readLine()Eén regel tegelijk; null geeft het einde aan
Scanner.hasNextLine() / nextLine()Handig lezen per regel

Importeer java.nio.file.Files en Path, plus de typen voor lezers of collecties die je gebruikt. Tekstmethoden van Files gebruiken standaard UTF-8. Een BufferedReader hoort in try-with-resources en meldt leesfouten met IOException. Door één regel tegelijk te lezen voorkom je dat de hele invoer in het geheugen staat, tenzij je verwerking daarna alle records opslaat.

Ook een scanner moet worden gesloten en heeft een extra foutcontrole nodig:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;

class ScanFile {
    static void show(Path file) throws IOException {
        try (Scanner sc = new Scanner(file, StandardCharsets.UTF_8)) {
            while (sc.hasNextLine()) {
                System.out.println(sc.nextLine());
            }
            if (sc.ioException() != null) throw sc.ioException();
        }
    }
}

Bij het openen kan direct een exceptie worden opgeworpen. Tijdens het lezen behandelt Scanner een onderliggende invoer- of uitvoerfout als het einde van de invoer en slaat die op; ioException() maakt de fout beschikbaar. Zonder die laatste controle kan een gedeeltelijke leesbewerking geslaagd lijken.

Tel de daadwerkelijke regels en parse daarna

Verhoog bij de invoerregels “12”, “15”, “abc”, een lege regel en “9” het regelnummer voordat je beslist of je een lege regel overslaat. Zet elke niet-lege regel om met Integer.parseInt(line.trim()) binnen een eigen try. Meld “Line 3: not a number: abc” en ga verder. De som van de geldige getallen is 36 en het aantal is 3, wat een gemiddelde van 12,0 geeft. Bereken (double) sum / count om een resultaat met een deel achter de komma te behouden en controleer eerst of het aantal niet nul is.

Controleer velden voordat je indexen gebruikt

Eenvoudige kommagescheiden gegevens kunnen objecten worden. Hier is de eerste regel een verplichte kopregel; elk volgend record heeft een niet-lege naam en een gehele leeftijd:

String[] parts = line.split(",", -1);
if (parts.length != 2 || parts[0].isBlank() || parts[1].isBlank()) {
    System.out.println("Line " + lineNumber + ": expected name and age");
    continue;
}
try {
    int age = Integer.parseInt(parts[1].trim());
    people.add(new Person(parts[0].trim(), age));
} catch (NumberFormatException e) {
    System.out.println("Line " + lineNumber + ": invalid age");
}

Dit fragment uit de lusbody gaat uit van line, lineNumber, een List<Person> met de naam people en een constructor Person(String, int). Sla de kopregel “name,age” over vóór deze parseerstap; anders mislukt de numerieke conversie van “age”. De records “Ana,34”, “Ben,29” en “Chen,41” hebben samen 104 jaar en gemiddeld ongeveer 34,67 jaar.

Een gewone split(",") laat lege velden aan het einde weg: “Eve,” levert maar één deel op. De limiet -1 behoudt het lege tweede veld, zodat de validatie dit kan melden. Controleer altijd de lengte vóór parts[1]. Alleen splitsen kan niet omgaan met komma’s tussen aanhalingstekens, zoals bij de naam in “"Smith, Ana",34”; voor volledige CSV is een CSV-parser nodig.

Belangrijkste punten

  • Kies methoden die het hele bestand lezen voor invoer van beheersbare omvang of een leeslus voor grote invoer.
  • Controleer Scanner.ioException() na het lezen om een verborgen leesfout op te sporen.
  • Tel de oorspronkelijke bestandsregels ook wanneer lege regels of records worden overgeslagen.
  • Controleer het aantal velden en de vereiste waarden voordat je indexen gebruikt en waarden omzet.
  • Sla een kopregel over voordat je records parset.
  • Gewoon splitsen kan CSV-velden tussen aanhalingstekens niet parsen.

5.2 Schrijf volledige tekst en voeg bewust achteraan toe

Het openen van een uitvoerbestand kan het bestand direct veranderen. Kies vóór het openen van de schrijver tussen vervangen en achteraan toevoegen, en sluit de schrijver aan het einde zodat gebufferde uitvoer niet in het geheugen achterblijft.

Vervangen of achteraan toevoegen

Files.writeString(path, text) schrijft één string. Files.write(path, lines) schrijft een doorloopbare verzameling regels en voegt na elke regel het regelscheidingsteken van het systeem toe, ook na de laatste. Met hun standaardopties maken beide een ontbrekend bestand aan en kappen ze een bestaand bestand af.

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

class RunLog {
    static void recordStart(Path log) throws IOException {
        Files.writeString(log, "started" + System.lineSeparator(),
            StandardCharsets.UTF_8,
            StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }
}

CREATE maakt een nieuw bestand mogelijk; APPEND behoudt oude inhoud en voegt aan het einde toe. Alleen APPEND mislukt als het bestand ontbreekt. Achteraan toevoegen plaatst geen ontbrekend scheidingsteken vóór je tekst: als een bestaand bestand halverwege een regel eindigt, gaan de volgende tekens op die regel verder.

De oudere FileWriter heeft een vlag voor achteraan toevoegen: new FileWriter("log.txt", StandardCharsets.UTF_8, true). Zonder die vlag kapt een nieuwe FileWriter of een PrintWriter met bestandsnaam een bestaand bestand ook af. Open nooit een schrijver die vervangt op invoer die je nog moet lezen.

Kies een schrijver en merk fouten op

BufferedWriter ondersteunt write en newLine() en meldt schrijffouten als gecontroleerde excepties:

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;

class ReportWriter {
    static void write(Path file) throws IOException {
        try (BufferedWriter out =
                Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
            out.write("Readings: 3");
            out.newLine();
            out.write(String.format(Locale.ROOT, "Average: %.2f", 3.0));
            out.newLine();
        }
    }
}

Het bestand heeft twee regels: “Readings: 3” en “Average: 3.00”. Locale.ROOT legt de decimale punt vast. newLine(), println en %n gebruiken allemaal het regeleinde van het platform; een letterlijke \n schrijft op elk systeem LF.

Een PrintWriter biedt de handige methoden print, println en printf, maar die registreren invoer- en uitvoerfouten in plaats van ze op te werpen. checkError() schrijft de buffer door en geeft de foutvlag terug. Als je ook op fouten bij de definitieve sluiting controleert, zorg dan dat je toegang tot de schrijver houdt en controleer na het sluiten. Gebruik BufferedWriter of de Files-methoden voor code die schrijffouten betrouwbaar moet doorgeven.

Maak de kringloop rond

Bestandsschrijvers bufferen uitvoer. flush() stuurt wachtende tekst verder; close() schrijft de buffer door en geeft het bestand vrij. Try-with-resources zorgt dat bij elke manier van verlaten wordt geprobeerd te sluiten, maar kan een schrijfbewerking naar de schijf niet laten slagen.

Om een persoon op te slaan, schrijf je de naam, een komma en de gehele leeftijd, gevolgd door een regeleinde. Maak kommagetallen op met Locale.ROOT, zodat een latere Double.parseDouble ze kan lezen. Een ontbrekende bovenliggende map wordt niet aangemaakt door een bestand te openen: gebruik Files.createDirectories(folder) als het de bedoeling is die aan te maken, of meld de fout. Een schrijfbewerking kan mislukken na het afkappen of na gedeeltelijke uitvoer; gebruik tijdelijke uitvoer en een atomaire verplaatsing wanneer het doelbestand moet worden beschermd.

Belangrijkste punten

  • Standaard schrijven maakt een ontbrekend bestand aan en kapt een bestaand bestand af.
  • Gebruik CREATE met APPEND om oude inhoud te behouden en een nieuw logbestand mogelijk te maken.
  • Sluiten schrijft gebufferde uitvoer door en geeft de systeembron vrij.
  • PrintWriter registreert schrijffouten; checkError() maakt die zichtbaar.
  • BufferedWriter en de methoden van Files geven invoer- en uitvoerfouten door.
  • Gebruik UTF-8 en Locale.ROOT om tekst uitwisselbaar te schrijven en terug te lezen.
  • Een bestand schrijven maakt ontbrekende bovenliggende mappen niet aan.

5.3 Bouw een rapport zonder fouten te verbergen

Een robuust programma voor bestandsverwerking heeft twee herstelniveaus nodig. Een ongeldig record kan worden overgeslagen en gemeld; als het lezen of opslaan van het bestand mislukt, stopt de taak. Bereken een volledig resultaat voordat je het doelbestand aanraakt.

Lezen, valideren, berekenen, opslaan

Het volledige programma hieronder leest de optionele kopregel “date,temperature”, gevolgd door eenvoudige records met twee velden. Datums zijn niet-lege labels; temperaturen zijn eindige getallen in graden Celsius. Het slaat onjuist gevormde records over en meldt die, inclusief lege regels. De geneste gecontroleerde exceptie houdt recordproblemen gescheiden van bestandsproblemen.

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Locale;

public class TemperatureReport {
    static class InvalidRecordException extends Exception {
        InvalidRecordException(String message) { super(message); }
        InvalidRecordException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    static List<String> readLines(Path file) throws IOException {
        return Files.readAllLines(file, StandardCharsets.UTF_8);
    }

    static double parseTemperature(String line, int lineNumber)
            throws InvalidRecordException {
        String[] parts = line.split(",", -1);
        if (parts.length != 2 || parts[0].isBlank()
                || parts[1].isBlank()) {
            throw new InvalidRecordException("Line " + lineNumber
                + ": expected a date label and a temperature");
        }
        try {
            double value = Double.parseDouble(parts[1].trim());
            if (!Double.isFinite(value)) {
                throw new InvalidRecordException("Line " + lineNumber
                    + ": temperature must be finite");
            }
            return value;
        } catch (NumberFormatException e) {
            throw new InvalidRecordException("Line " + lineNumber
                + ": not a number: " + parts[1], e);
        }
    }

    static String summarize(List<String> lines) {
        int count = 0;
        int skipped = 0;
        double sum = 0;
        double min = Double.POSITIVE_INFINITY;
        double max = Double.NEGATIVE_INFINITY;
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if (i == 0 && line.equals("date,temperature")) continue;
            try {
                double value = parseTemperature(line, i + 1);
                sum += value;
                count++;
                min = Math.min(min, value);
                max = Math.max(max, value);
            } catch (InvalidRecordException e) {
                skipped++;
                System.err.println(e.getMessage());
            }
        }
        if (count == 0) {
            return String.format(Locale.ROOT,
                "No valid readings%nSkipped lines: %d%n", skipped);
        }
        return String.format(Locale.ROOT,
            "Valid readings: %d%nAverage (°C): %.2f%n"
                + "Minimum (°C): %.2f%nMaximum (°C): %.2f%n"
                + "Skipped lines: %d%n",
            count, sum / count, min, max, skipped);
    }

    static void writeSummary(Path file, String text) throws IOException {
        Path target = file.toAbsolutePath();
        Path temp = Files.createTempFile(target.getParent(), "report-", ".tmp");
        try {
            Files.writeString(temp, text, StandardCharsets.UTF_8);
            Files.move(temp, target, StandardCopyOption.ATOMIC_MOVE);
        } catch (IOException e) {
            try {
                Files.deleteIfExists(temp);
            } catch (IOException cleanup) {
                e.addSuppressed(cleanup);
            }
            throw e;
        }
    }

    public static void main(String[] args) {
        Path input = Path.of("readings.csv");
        Path output = Path.of("summary.txt");
        try {
            List<String> lines = readLines(input);
            String report = summarize(lines);
            writeSummary(output, report);
            System.out.println("Saved: " + output.toAbsolutePath());
        } catch (NoSuchFileException e) {
            System.err.println("File or folder not found: " + e.getFile());
        } catch (AtomicMoveNotSupportedException e) {
            System.err.println("Could not save atomically: "
                + output.toAbsolutePath());
        } catch (IOException e) {
            System.err.println("Could not process " + input.toAbsolutePath()
                + " or save " + output.toAbsolutePath() + ": " + e.getMessage());
        }
    }
}
Volg één uitvoering

Gebruik deze vijf invoerregels zonder kopregel:

2026-03-01,4.5
2026-03-02,6.0
2026-03-03,abc
2026-03-04,-1.5
missing comma

Regels 1, 2 en 4 leveren drie geldige metingen op. De som is 9,0; het gemiddelde is 3,00 °C, het minimum is -1,50 °C en het maximum is 6,00 °C. Regels 3 en 5 leveren foutmeldingen op en het rapport vermeldt twee overgeslagen regels. De parseerafhandelaar staat binnen de lus, zodat na elk ongeldig record de latere records bereikbaar blijven. Door totalen pas na geslaagd parsen bij te werken, blijven afgewezen waarden buiten de totalen.

Double.parseDouble accepteert speciale strings zoals “NaN” en “Infinity”. Double.isFinite wijst die hier af omdat ze niet als gewone gemeten temperaturen kunnen dienen. Een leeg bestand, een bestand met alleen een kopregel of uitsluitend ongeldige records bereikt de tak voor een aantal van nul voordat wordt gedeeld of het oorspronkelijke minimum en maximum worden gebruikt.

Bescherm het doelbestand

Het lezen en berekenen zijn voltooid voordat het opslaan begint. Files.writeString opent en sluit zelf een bestand, maar kan mislukken nadat een deel is geschreven. Het programma schrijft daarom naar een tijdelijk bestand in de doelmap, sluit dat en vraagt om ATOMIC_MOVE. De verplaatsing maakt het voltooide resultaat, als de bewerking wordt ondersteund, in één bestandssysteembewerking zichtbaar.

Of een bestaand doelbestand atomair kan worden vervangen, hangt af van de implementatie. Het programma meldt een niet-ondersteunde verplaatsing of vervanging en probeert nooit opnieuw met een niet-atomaire verplaatsing. Een opruimfout wordt aan de oorspronkelijke exceptie toegevoegd in plaats van die te vervangen. Atomaire zichtbaarheid garandeert niet dat het resultaat een stroomuitval overleeft.

Vooraf Files.exists(input) controleren kan de latere leesbewerking niet garanderen: een bestand kan na de controle verdwijnen of ontoegankelijk worden. Handel de daadwerkelijke bewerking af. Probeer voordat je op een verwerkingsprogramma vertrouwt ontbrekende invoer, ontbrekende uitvoermappen, lege bestanden en bestanden met alleen een kopregel, CRLF-regeleinden, tekst met accenttekens en onjuist gevormde records. Gebruikersmeldingen moeten het pad noemen waarbij de fout optrad; voor het opsporen van fouten in een wrapper zijn ook de oorspronkelijke oorzaak en stacktrace nodig.

Belangrijkste punten

  • Handel recordfouten binnen de lus af en fouten op bestandsniveau erbuiten.
  • Valideer een volledig record voordat je aantallen of totalen bijwerkt.
  • Controleer of het aantal geldige records nul is voordat je een gemiddelde berekent.
  • Voltooi het lezen en berekenen voordat je de uitvoer opent.
  • Schrijf en sluit een tijdelijk bestand en vraag daarna om een atomaire verplaatsing om het doelbestand te beschermen.
  • Meld niet-ondersteunde atomaire vervanging in plaats van ongemerkt terug te vallen op een andere werkwijze.
  • Houd oorspronkelijke oorzaken en opruimfouten beschikbaar voor het opsporen van fouten.

Excepties en bestanden in Java: voorbeelden

5 Walkthroughs

1

Volg een fout terug naar de oorzaak

11 stappen
Lees een stacktrace, verbind die met de actieve aanroepen en gebruik overerving om de fout in te delen.
  1. 1
    IntroductieEen programma kan compileren en toch mislukken

    Een invoerwaarde kan geldige Java-code tijdens de uitvoering laten mislukken. Het exceptieobject vertelt je welk soort probleem optrad en de stacktrace toont welke methodeaanroepen actief waren.

    Volg eerst een mislukte conversie naar een geheel getal. Gebruik daarna dezelfde overervingsregels die objecten van een subklasse bruikbaar maken als objecten van een superklasse om te bepalen wat je van de compiler moet afhandelen.

  2. 2
    VoorbeeldBekijk hoe de conversie stopt

    Een methode loadCount voert deze instructies uit:

    System.out.print("start ");
    int count = Integer.parseInt("eight");
    System.out.print("finish");
    

    De methode geeft start weer en werpt daarna NumberFormatException op. De toewijzing wordt niet voltooid en finish wordt overgeslagen. Een passende afhandelaar kan het overnemen, maar de mislukte instructie wordt na herstel niet hervat.

  3. 3
    UitlegVolg de actieve aanroepen

    Stel dat main de methode loadCount aanriep, die vervolgens Integer.parseInt aanriep. Die aanroepen maken deel uit van de aanroepstack. De exceptie gaat naar buiten wanneer een methode geen passende afhandelaar heeft.

    parseInt mislukt als eerste, loadCount kan de normale werkzaamheden niet voltooien en de aanroeper krijgt de kans de fout af te handelen. Als de exceptie main onverwerkt verlaat, meldt Java de exceptie en eindigt de hoofdthread.

  4. 4
    VoorbeeldZoek je eerste frame

    Een stacktrace kan na de bibliotheekframes van Java deze applicatieframes bevatten:

    at Counts.loadCount(Counts.java:14)
    at Counts.main(Counts.java:5)
    

    Bekijk eerst regel 14: dat is de aanroep in je code die het dichtst bij de plaats ligt waar het probleem is vastgesteld. Regel 5 vertelt je waar loadCount is aangeroepen. De eerste regel van de exceptie geeft de klasse en melding; verwar het lagere frame van de aanroeper niet met de instructie die de ongeldige tekst als eerste gebruikte.

  5. 5
    UitdagingZoek de overgeslagen uitvoer

    Een hulpmethode geeft A weer, roept Integer.parseInt("q2") aan en zou daarna B weergeven. De aanroeper vangt NumberFormatException op en geeft C weer. Welke letters worden weergegeven en waarom?

    ---reveal---

    A en daarna C. De conversie werpt vóór B een exceptie op; door doorgifte komt de fout bij de passende afhandelaar van de aanroeper. De resterende instructies van de hulpmethode worden afgebroken, dus na herstel keert de uitvoering niet terug om B weer te geven.

  6. 6
    TipKijk verder dan de instructie waar het probleem is vastgesteld

    De instructie waar een fout wordt vastgesteld, kan een ongeldige waarde gebruiken die eerder is ontstaan. Bij een null-referentiefout moet je nagaan waar die referentie een object had moeten krijgen.

    Gebruik getMessage() voor de foutmelding en printStackTrace() voor de aanroepketen. Een melding kan null zijn; een onderdeel Caused by: toont een andere exceptie die in een wrapper is bewaard.

  7. 7
    UitlegGebruik de keten van superklassen

    Throwable is de basisklasse voor objecten die kunnen worden opgeworpen. De hoofdtakken zijn Error en Exception; RuntimeException staat onder Exception.

    RuntimeException, Error en elke subklasse van een van beide zijn ongecontroleerd. Andere subklassen van Throwable zijn gecontroleerd. Fouten uit beide categorieën treden tijdens de uitvoering op; “gecontroleerd” beschrijft de controle van de afhandeling door de compiler, niet een ander moment waarop de exceptie wordt opgeworpen.

  8. 8
    VoorbeeldVergelijk een parser en een bestandslezer

    NumberFormatException breidt IllegalArgumentException uit, dat op zijn beurt RuntimeException uitbreidt, dus heeft een aanroep van Integer.parseInt geen verplichte afhandelaar.

    IOException breidt Exception uit buiten die tak. Een aanroep van Files.readString moet de mogelijke IOException opvangen of declareren met throws. Een bestandsbewerking kan om externe redenen mislukken, ook wanneer de aanroepende code correct is.

  9. 9
    UitdagingDeel een onbekende fout in

    BadRecordException breidt Exception direct uit. Een hulpmethode declareert dat die dit type kan opwerpen. Wat moet de aanroeper doen en wanneer wordt die verplichting gecontroleerd?

    ---reveal---

    De exceptie opvangen of een toepasselijk gecontroleerd type declareren in de methodedeclaratie van de aanroeper. De compiler dwingt die verplichting af omdat de klasse buiten de ongecontroleerde takken valt. Of een afzonderlijke uitvoering slaagt, neemt de eis op declaratieniveau niet weg.

  10. 10
    UitdagingVerklaar een verrassend brede afhandelaar

    Een blok dat een bestand leest vangt Exception op en geeft “Bestandsprobleem” weer. In plaats daarvan mislukt het met een NullPointerException door een programmeerfout. Ontvangt de afhandelaar die exceptie en is de melding betrouwbaar?

    ---reveal---

    Ja: NullPointerException breidt RuntimeException uit, dat Exception uitbreidt. De melding is misleidend omdat deze fout een programmeerfout is en geen aanwijzing voor een bestandsprobleem. Lees de stacktrace en beperk de verwachte afhandelaar tot de fouten die die kan verklaren.

  11. 11
    SamenvattingKies de volgende stap bij het opsporen van fouten

    Begin een foutonderzoek met de klasse, de melding en het eerste applicatieframe. Volg de aanroepers en de oorsprong van ongeldige waarden als de instructie waar het probleem is vastgesteld de oorzaak niet op zichzelf verklaart.

    Controleer daarna de overerving voordat je de afhandeling kiest: gecontroleerde fouten vereisen een beslissing die zichtbaar is voor de compiler; ongecontroleerde programmeerfouten moeten nog steeds worden hersteld. Voorkom dat brede afhandelaars het ene soort probleem als een ander soort voorstellen.

2

Volg herstel- en opruimpaden

12 stappen
Volg een mislukte invoerconversie, kies het bereik en de volgorde van afhandelaars en volg finally bij voortijdig verlaten.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieBepaal wat er daarna moet gebeuren
  2. 2
    VoorbeeldHerstel na de volledige instructie
  3. 3
    TipLees nieuwe tekst bij een nieuwe poging
  4. 4
    UitdagingHerstel de vastgelopen scanner
  5. 5
    UitlegGeef een specifieke fout een eigen reactie
  6. 6
    VoorbeeldLaat de lus doorgaan
  7. 7
    UitdagingVerplaats de grens van het beschermde codegebied
  8. 8
    KernpuntDeel reacties zonder overlappende typen
  9. 9
    UitlegOpruimcode wordt vóór het verlaten uitgevoerd
  10. 10
    UitdagingVolg een fout zonder passende afhandelaar
  11. 11
    UitdagingVoorkom dat opruimcode een fout bij een nieuwe poging verbergt
  12. 12
    SamenvattingVolg de volgende bereikbare instructie
3

Wijs een verzoek af zonder de toestand te beschadigen

11 stappen
Valideer een voorraadbewerking, maak een domeinfout zichtbaar en pak een parseerfout in met behoud van de oorzaak.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieBehoud een bruikbaar object
  2. 2
    VoorbeeldValideer vóór het aftrekken
  3. 3
    UitlegOnderscheid throw van de declaratie
  4. 4
    UitdagingKies de juiste standaardexceptie
  5. 5
    VerbandEen overschrijvende methode houdt zich aan de belofte aan aanroepers
  6. 6
    VoorbeeldGeef onvoldoende voorraad een eigen type
  7. 7
    VoorbeeldHoud het mislukte verzoek afzonderlijk
  8. 8
    UitdagingBepaal welke toestand overblijft
  9. 9
    UitlegBehoud de oorspronkelijke conversiefout
  10. 10
    UitdagingGeef een bestandsfout door via een beperkte methode
  11. 11
    SamenvattingOntwerp een exceptie die de aanroeper kan gebruiken
4

Open de juiste tekst en sluit die veilig

12 stappen
Bepaal een pad, stem tekstconventies op elkaar af en volg daarna het openen en sluiten van systeembronnen en concurrerende fouten.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieZowel locatie als levensduur is van belang
  2. 2
    VoorbeeldBepaal het pad vanuit de werkmap
  3. 3
    UitlegDecodeer met de tekenset die bij het schrijven is gebruikt
  4. 4
    TipVerwijder een volledig regeleinde
  5. 5
    UitdagingZorg dat een kommagetal kan worden teruggelezen
  6. 6
    UitlegDeclareer een te sluiten systeembron
  7. 7
    VerbandGebruik het sluitcontract
  8. 8
    VoorbeeldKeer de openingsvolgorde om
  9. 9
    UitdagingVolg een mislukte tweede opening
  10. 10
    KernpuntHoud een fout uit de body als hoofdmelding
  11. 11
    UitdagingOnderscheid een gegevensfout van een opruimfout
  12. 12
    SamenvattingBekijk een bestandsbewerking op volgorde
5

Zet metingen om in een betrouwbaar rapport

16 stappen
Lees en valideer eenvoudige records, bereken de geaccepteerde resultaten en sla voltooide uitvoer op met een duidelijke aanpak voor fouten.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieEen rapport vereist meer dan correct rekenwerk
  2. 2
    UitlegKies hoe regels binnenkomen
  3. 3
    VoorbeeldDefinieer het record vóór het parsen
  4. 4
    VoorbeeldValideer voordat je het tweede veld gebruikt
  5. 5
    UitdagingZoek het afgewezen record
  6. 6
    UitlegKies tussen vervangen en achteraan toevoegen
  7. 7
    VoorbeeldSchrijf een uitwisselbare rapportregel
  8. 8
    TipMerk een mislukte schrijfbewerking op
  9. 9
    UitdagingBehoud oude en nieuwe logregels
  10. 10
    VerbandHerstel op twee verschillende niveaus
  11. 11
    VoorbeeldWerk totalen pas na validatie bij
  12. 12
    UitdagingHandel een waarde af die wel kan worden geparset maar niet bruikbaar is
  13. 13
    UitlegVoltooi de uitvoer voordat je het doelbestand vervangt
  14. 14
    TipHoud de opslagfout zichtbaar
  15. 15
    UitdagingKies wat veilig kan worden gerapporteerd
  16. 16
    SamenvattingBeoordeel het verwerkingsprogramma per foutpad

Excepties en bestanden in Java: oefenvragen

40 Oefenvragen in 4 sets

Set 1: Volg fouten en kies passend herstel10 Oefenvragen

Vraag 1 van 10

Een array heeft lengte 5. Wat gebeurt er wanneer het programma values[5] evalueert?
  1. Het leest het vijfde element van de array.
  2. Het werpt ArrayIndexOutOfBoundsException op.
  3. Het geeft de standaardwaarde 0 voor gehele getallen terug.
  4. Het werpt NumberFormatException op.
Toon antwoordVerberg antwoord
Antwoord: B
Een array met lengte 5 heeft geldige indexen van 0 tot en met 4, dus index 5 valt erbuiten. Java werpt bij die toegang ArrayIndexOutOfBoundsException op. Vijf elementen tellen maakt index 5 niet geldig: het vijfde element staat op index 4.

Vraag 2 van 10

DataProblem breidt Exception direct uit. Welke verplichting heeft een methode die een hulpmethode aanroept met de declaratie throws DataProblem?
  1. RuntimeException opvangen of declareren.
  2. De exceptie alleen declareren als de hulpmethode daadwerkelijk mislukt.
  3. De exceptie alleen tijdens de uitvoering afhandelen.
  4. DataProblem opvangen of declareren.
Toon antwoordVerberg antwoord
Antwoord: D
DataProblem is gecontroleerd omdat die klasse Exception uitbreidt buiten de tak van RuntimeException. De aanroepende code moet de exceptie opvangen of een toepasselijk gecontroleerd type declareren. De compiler controleert de gedeclareerde mogelijkheid, ook als een bepaalde aanroep zou slagen.

Vraag 3 van 10

Welke letters worden op volgorde weergegeven?

System.out.print("P");
try {
    int n = Integer.parseInt("7q");
    System.out.print("Q");
} catch (NumberFormatException e) {
    System.out.print("R");
}
System.out.print("S");
  1. PRS
  2. PQRS
  3. PR
  4. PS
Toon antwoordVerberg antwoord
Antwoord: A
Het omzetten van “7q” werpt NumberFormatException op vóór de instructie die Q weergeeft. De passende afhandelaar geeft R weer, waarna de uitvoering verdergaat na de instructie en S weergeeft. De overgeslagen instructie wordt na herstel niet uitgevoerd, dus PQRS kan de uitvoer niet zijn.

Vraag 4 van 10

Een blok kan NoSuchFileException of een andere IOException opwerpen. Welke catch-volgorde geeft elk een eigen reactie?
  1. IOException, daarna NoSuchFileException.
  2. Exception, daarna NoSuchFileException.
  3. NoSuchFileException, daarna IOException.
  4. IOException | NoSuchFileException in één clausule.
Toon antwoordVerberg antwoord
Antwoord: C
NoSuchFileException breidt IOException uit, dus moet de specifieke afhandelaar eerst staan. Als IOException eerst staat, vangt die al elke exceptie voor een ontbrekend bestand op en wordt de latere afhandelaar onbereikbaar. Een meervoudige catch-clausule kan deze verwante typen evenmin combineren.

Vraag 5 van 10

Wat geeft een aanroep van pick() weer en wat retourneert die?

static int pick() {
    try {
        return 8;
    } finally {
        System.out.print("done");
    }
}
  1. De methode retourneert 8 zonder iets weer te geven.
  2. De methode geeft done weer en retourneert 8.
  3. De methode geeft done weer en retourneert geen waarde.
  4. De methode geeft 8 weer en retourneert daarna done.
Toon antwoordVerberg antwoord
Antwoord: B
De retourexpressie wordt geëvalueerd, maar de methode voert finally uit voordat de waarde aan de aanroeper wordt geleverd. De methode geeft daarom done weer en retourneert 8. Een return binnen try slaat het opruimen niet over; alleen een concurrerende overdracht vanuit de opruimcode zou dat resultaat vervangen.

Vraag 6 van 10

Een methode wijst een negatieve capaciteit af voordat die aan een veld wordt toegewezen. Welke standaardexceptie beschrijft het ongeldige argument het best?
  1. IllegalArgumentException
  2. IllegalStateException
  3. NumberFormatException
  4. UnsupportedOperationException
Toon antwoordVerberg antwoord
Antwoord: A
Een negatieve capaciteit schendt de argumentregel van de methode, dus IllegalArgumentException beschrijft de fout. IllegalStateException zou een aanroep beschrijven die door de huidige toestand van het object verboden is. Er wordt geen parseerbewerking genoemd, dus een numeriek argument alleen maakt dit geen getalopmaakfout.

Vraag 7 van 10

Een programma start met werkmap /work/app. Het maakt Path.of("data", "levels.txt") aan. Welke absolute locatie duidt dat relatieve pad aan?
  1. /work/data/levels.txt
  2. /data/levels.txt
  3. /work/app/src/data/levels.txt
  4. /work/app/data/levels.txt
Toon antwoordVerberg antwoord
Antwoord: D
Een relatief pad begint in de werkmap, dus de twee padelementen vullen /work/app aan tot /work/app/data/levels.txt. Java voegt geen broncodemap in. Het bestand naast de broncode plaatsen zou alleen werken als dat toevallig de locatie is die het bepaalde pad aanduidt.

Vraag 8 van 10

Systeembron a wordt geopend, maar het openen van systeembron b werpt een exceptie op. Beide zijn in die volgorde in dezelfde try-with-resources-kop gedeclareerd. Ook het sluiten van a werpt een exceptie op. Welke fout bereikt de aanroeper?
  1. De sluitfout, met de openingsfout als onderdrukte exceptie.
  2. De openingsfout, waarbij de sluitfout vervalt.
  3. De openingsfout, met de sluitfout als onderdrukte exceptie.
  4. Beide fouten afzonderlijk, in de volgorde waarin ze optreden.
Toon antwoordVerberg antwoord
Antwoord: C
Wanneer het openen van b mislukt, sluit Java de al geopende a nog steeds. De openingsfout blijft de hoofdfout en de latere sluitfout wordt als onderdrukte exceptie toegevoegd. Wie de sluitfout als hoofdfout kiest, verwart try-with-resources met handmatige opruimcode die een eerdere fout kan overschrijven.

Vraag 9 van 10

Een BufferedReader heeft het einde van het bestand bereikt. Wat geeft de volgende readLine() terug?
  1. null
  2. Een lege string.
  3. Een string met "EOF".
  4. Een string met "\n".
Toon antwoordVerberg antwoord
Antwoord: A
BufferedReader.readLine() geeft null terug als er geen tekens meer zijn om nog een regel te vormen. Een lege string stelt een daadwerkelijke lege regel voor, dus als je die als eindmarkering gebruikt, stop je te vroeg. Regeleinden worden uit teruggegeven regels verwijderd en zijn geen markering voor het einde van het bestand.

Vraag 10 van 10

Een UTF-8-logbestand kan al bestaan of ontbreken. Met welke opties kan Files.writeString bestaande tekst behouden en nieuwe tekst aan het einde toevoegen?
  1. CREATE en TRUNCATE_EXISTING
  2. CREATE en APPEND
  3. APPEND zonder CREATE
  4. CREATE_NEW en WRITE
Toon antwoordVerberg antwoord
Antwoord: B
APPEND schrijft na bestaande inhoud en CREATE maakt het mogelijk een ontbrekend bestand aan te maken. Alleen APPEND gebruiken mislukt als het logbestand niet bestaat. TRUNCATE_EXISTING zou bestaande inhoud wissen, terwijl CREATE_NEW een pad afwijst dat al bestaat.
Set 2: Pas contracten toe op records en bestandsuitvoer10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Een stacktrace begint met deze frames. Welke regel in de klasse van de cursist moet eerst worden bekeken?

java.lang.NumberFormatException: For input string: "six"
    at java.base/java.lang.NumberFormatException.forInputString(...)
    at java.base/java.lang.Integer.parseInt(...)
    at Importer.readCount(Importer.java:18)
    at Importer.main(Importer.java:6)
  1. Regel 6 in Importer.main.
  2. Het bibliotheekframe in forInputString.
  3. Regel 18 in Importer.readCount.
  4. De regel na regel 18 in Importer.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

AmountProblem breidt IllegalArgumentException uit. Hoe wordt die klasse ingedeeld?
  1. Ongecontroleerd, via RuntimeException.
  2. Gecontroleerd, omdat het een eigen klasse is.
  3. Gecontroleerd, omdat de bovenliggende klasse een exceptie is.
  4. Ongecontroleerd, via de tak van Error.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Een herhaallus vangt InputMismatchException van Scanner.nextInt() op, geeft een melding weer en roept onmiddellijk opnieuw nextInt() aan. De volgende token is “many”. Waarom blijft de lus mislukken?
  1. De afhandelaar spoelt de hele invoerstroom terug.
  2. De scanner zet de token om in nul.
  3. De exceptie sluit de scanner definitief.
  4. De mislukte leesbewerking laat dezelfde token ongelezen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Een interface declareert void load() throws IOException. Een implementatie moet een fout voor een ontbrekend bestand declareren. Welke gecontroleerde declaratie is toegestaan bij het overschrijven?
  1. throws Exception
  2. throws NoSuchFileException
  3. throws Throwable
  4. throws InterruptedException
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Een voorraad bevat 17 stiften. De methode remove wijst verzoeken die groter zijn dan de huidige voorraad af voordat de map wordt gewijzigd. Aanroepen verwijderen eerst 6 en vragen daarna om 14; de tweede fout wordt ingepakt met de oorzaak en door de aanroeper opgevangen. Welke voorraad en foutinformatie blijven over?
  1. 11 stiften, maar alleen de nieuwe melding van de wrapper.
  2. -3 stiften en de oorspronkelijke fout als oorzaak.
  3. 11 stiften en de oorspronkelijke fout als oorzaak.
  4. 17 stiften en de oorspronkelijke fout als oorzaak.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Wat gebeurt er wanneer Double.parseDouble("6,25") wordt uitgevoerd op een computer met Duitse taal- en regio-instellingen?
  1. De methode geeft de decimale waarde 6,25 terug.
  2. De methode geeft de gehele waarde 625 terug.
  3. De methode werpt MalformedInputException op.
  4. De methode werpt NumberFormatException op.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Welke interface moet een object implementeren om als systeembron in try-with-resources te worden gedeclareerd?
  1. AutoCloseable
  2. Serializable
  3. Iterable
  4. Comparable
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

De regel is “Nora,”. Welk verschil tussen line.split(",") en line.split(",", -1) is van belang?
  1. Beide geven twee velden terug, elk met een leeg tweede veld.
  2. De eerste behoudt de komma; de tweede verwijdert de komma.
  3. De eerste geeft één veld terug; de tweede behoudt een leeg tweede veld.
  4. De eerste werpt een exceptie op; de tweede geeft één veld terug.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een programma schrijft via PrintWriter, maar een volle schijf verhindert dat de tekst wordt opgeslagen. Wat moet het gebruiken om de geregistreerde fout van de schrijver te ontdekken?
  1. Vang IOException op vanuit println zelf.
  2. Roep checkError() aan en bekijk het resultaat.
  3. Bekijk getFileName() van het bestandspad.
  4. Neem aan dat sluiten succesvol opslaan garandeert.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Een rapport moet een bestaand resultaat beschermen tegen gedeeltelijke vervanging. Het lezen en berekenen zijn voltooid. Welke opslagaanpak is geschikt?
  1. Schrijf direct naar het doelbestand; begin opnieuw als de eerste schrijfbewerking mislukt.
  2. Schrijf een tijdelijk bestand; gebruik een niet-atomaire verplaatsing als de atomaire mislukt.
  3. Controleer of het doelbestand bestaat; voeg het nieuwe rapport achter het oude resultaat toe.
  4. Schrijf en sluit een tijdelijk bestand in dezelfde map; vraag om een atomaire verplaatsing en meld niet-ondersteunde vervanging.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 3: Volg samenwerkende fouten en opruimcode10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Welke exceptiefamilie ontvangt ook NumberFormatException wanneer die door een afhandelaar voor een superklasse wordt opgevangen?
  1. RuntimeException
  2. IOException
  3. Error
  4. FileNotFoundException
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Welke waarde wordt weergegeven?

int count;
try {
    count = Integer.parseInt("bad");
} catch (NumberFormatException e) {
    count = 4;
}
System.out.println(count + 2);
  1. 4
  2. 2
  3. 6
  4. Niets; count is niet geïnitialiseerd.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Welke waarde bereikt de laatste weergave-instructie?

int total = 0;
try {
    for (String text : new String[] {"8", "bad", "3"}) {
        try {
            total += Integer.parseInt(text);
        } catch (NumberFormatException e) {
            throw new IllegalStateException("record", e);
        }
    }
} catch (IllegalStateException e) {
    total += 2;
}
System.out.println(total);
  1. 13
  2. 10
  3. 11
  4. 2
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Wat doet result()?

static int result() {
    try {
        throw new IllegalArgumentException("bad");
    } finally {
        return 9;
    }
}
  1. De methode werpt de exceptie op en retourneert nooit 9.
  2. De methode retourneert 9 en werpt daarna de exceptie op naar de aanroeper.
  3. De methode compileert niet omdat finally niet kan terugkeren.
  4. De methode retourneert 9 en laat de wachtende exceptie vervallen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Een parser vangt NumberFormatException e op. De zelfgedefinieerde InvalidRecordException heeft constructoren voor alleen een melding en voor een melding met een oorzaak. Hoe moet de parser “Line 8” toevoegen met behoud van de oorspronkelijke stacktrace?
  1. throw new InvalidRecordException(e.getMessage());
  2. throw new InvalidRecordException("Line 8", e);
  3. throw new InvalidRecordException("Line 8");
  4. throw new RuntimeException("Line 8");
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Een Windows-tekstbestand bevat regels met gehele getallen die eindigen op CRLF. Code gebruikt Files.readString(path).split("\n") en daarna Integer.parseInt op elk niet-leeg deel. Waarom kan de conversie van een deel met de cijfers “27” mislukken?
  1. parseInt vereist altijd een decimale punt.
  2. UTF-8 kan Windows-regeleinden niet weergeven.
  3. Door het splitsen kan een afsluitende \r achterblijven.
  4. Het splitsen zet de cijfers automatisch om in bytes.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Systeembronnen a en b worden in die volgorde succesvol geopend. De body werpt E op; het sluiten van b werpt F op; het sluiten van a werpt G op. Wat bereikt de catch die bij die try-with-resources-instructie hoort?
  1. E, met eerst F en dan G als onderdrukte fouten.
  2. G, met eerst E en dan F als onderdrukte fouten.
  3. F, met eerst G en dan E als onderdrukte fouten.
  4. Alleen E, omdat het sluiten stopt na F.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een klein bestand begint met “name,age”, gevolgd door “Omar,36”. Waarom moet de eerste regel afzonderlijk worden behandeld voordat het leeftijdsveld wordt omgezet?
  1. De regel gebruikt een andere tekencodering dan de gegevens.
  2. De komma verhindert dat split twee velden vindt.
  3. Een lezer geeft de regel automatisch terug als een lege regel.
  4. De regel benoemt de kolommen in plaats van een gehele leeftijd te geven.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een verwerkingsprogramma leest “zone,temperature” als kopregel, gevolgd door “north,2.0”, “east,bad” en “west,8.0”. De vereiste aanpak is ongeldige records overslaan en een rapport van geldige records opslaan. Een catch staat momenteel rond de hele parseerlus. Welke wijziging zorgt voor de vereiste aanpak?
  1. Houd de catch buiten de lus; hervat de lus automatisch na de afhandelaar.
  2. Schrijf elk totaal naar het doelbestand voordat je het volgende record probeert te parsen.
  3. Vang recordfouten binnen elke iteratie op; sla pas op nadat lezen en berekenen klaar zijn.
  4. Geef een leeg resultaat terug vanuit de lezer wanneer het parsen mislukt.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Invoer wordt gecontroleerd met Files.exists en daarna gelezen met een scanner. De lus eindigt na slechts enkele records omdat de onderliggende lezer faalde, en het programma begint direct met opslaan. Wat moet veranderen om te voorkomen dat deze gedeeltelijke invoer als geslaagd wordt beschouwd?
  1. Controleer ioException() na het scannen en stop het opslaan als een leesfout is geregistreerd.
  2. Herhaal Files.exists na het scannen en sla op wanneer dit true teruggeeft.
  3. Vang bij elke leesbewerking alleen NumberFormatException op en sla daarna op.
  4. Sluit de scanner en neem aan dat de eerdere leesbewerkingen het bestand volledig hebben gelezen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 4: Onderzoek en verbeter een volledig verwerkingsprogramma10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Wat wordt weergegeven voordat de exceptie main verlaat en welk applicatieframe staat als eerste in de stacktrace?

public class Counter {
    static int read() {
        return Integer.parseInt("9z");
    }
    static void show() {
        System.out.print("L");
        System.out.print(read());
        System.out.print("M");
    }
    public static void main(String[] args) {
        show();
        System.out.print("N");
    }
}
  1. LM; Counter.show(Counter.java:7).
  2. Alleen L; Counter.main(Counter.java:11).
  3. LMN; Counter.read(Counter.java:3).
  4. Alleen L; Counter.read(Counter.java:3).
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Een catch-blok meldt ongeldige numerieke invoer, maar gaat verder met een eerder toegewezen standaardwaarde. Wat moet voor die standaardwaarde gelden om het herstel nuttig te maken?
  1. Die moet altijd de gehele waarde nul zijn.
  2. Die moet een geldige waarde zijn voor de resterende berekening.
  3. Die moet gelijk zijn aan de tekst waarvan de conversie mislukte.
  4. Die moet binnen de mislukte instructie zijn toegewezen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Een parser gebruikt catch (NumberFormatException | IllegalArgumentException e). Waarom compileert deze meervoudige catch-clausule niet?
  1. Geen van beide alternatieven is een gecontroleerde exceptie.
  2. De alternatieven vereisen twee verschillende variabelenamen.
  3. Het ene alternatief is een subklasse van het andere.
  4. Een meervoudige catch-clausule staat alleen bestandsfouten toe.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Wat geeft choose() weer en wat retourneert de methode?

static int choose() {
    int value = 5;
    try {
        return value;
    } finally {
        value = 12;
        System.out.print(value);
    }
}
  1. De methode geeft 12 weer en retourneert 5.
  2. De methode geeft 12 weer en retourneert 12.
  3. De methode geeft 5 weer en retourneert 5.
  4. De methode geeft niets weer en retourneert 12.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Interface ReaderTask declareert String read() throws IOException. Klasse FixedTask implementeert die met public String read() en zonder gecontroleerde declaratie. Variabele task heeft type ReaderTask en verwijst naar een FixedTask. Wat moet code doen die task.read() aanroept?
  1. Afhandeling weglaten omdat de implementatie geen gecontroleerde fout declareert.
  2. RuntimeException opvangen in plaats van het gedeclareerde gecontroleerde type.
  3. throws IOException aan de implementatie toevoegen vóór de aanroep.
  4. IOException opvangen of declareren volgens de interfacedeclaratie.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Een overschrijvende methode mag geen gecontroleerde excepties toevoegen, maar roept bestandscode aan die IOException kan opwerpen. Welke standaardwrapper behoudt die oorzaak en geeft een ongecontroleerde fout door?
  1. new IOException(e.getMessage())
  2. new UncheckedIOException(e)
  3. new Exception(e)
  4. new RuntimeException("error")
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Een body met een systeembron retourneert 6. De methode close() werpt daarna IOException op en de bijbehorende catch retourneert 2; het finally-blok geeft “closed” weer zonder een exceptie op te werpen. Wat doet de methode?
  1. De methode geeft closed weer en retourneert 2.
  2. De methode geeft closed weer en retourneert 6.
  3. De methode werpt IOException op en retourneert geen waarde.
  4. De methode retourneert 6 zonder naar de catch te gaan.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een bestand heeft de kopregel “label,count”, gevolgd door “oak,7”, “ash,”, “elm,11” en “fir,x”. Het verwerkingsprogramma slaat de kopregel over, behoudt lege velden bij het splitsen, valideert beide velden en vangt recordfouten binnen de lus op. Welk geldig aantal, welke som en welke afgewezen daadwerkelijke regelnummers levert dit op?
  1. 3 records, som 18; alleen regel 5 afgewezen.
  2. 1 record, som 7; regels 3, 4 en 5 afgewezen.
  3. 2 records, som 18; regels 3 en 5 afgewezen.
  4. 2 records, som 18; regels 2 en 4 afgewezen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een UTF-8-gegevensbestand moet één regel “sample,7.50” bevatten, waarvan het tweede veld op computers met elke taal- en regio-instelling met Double.parseDouble kan worden gelezen. Welke schrijfaanpak voldoet aan die opmaak?
  1. Schrijf "sample," + String.format("%.2f", 7.5) en een regeleinde.
  2. Schrijf "sample," + String.format(Locale.ROOT, "%.2f", 7.5) en een regeleinde.
  3. Schrijf "sample," + String.format(Locale.GERMANY, "%.2f", 7.5) en een regeleinde.
  4. Schrijf "sample," + Integer.toString((int) 7.5) en een regeleinde.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Een verwerkingsprogramma leest een geldige kopregel en drie ongeldige records. Het moet geaccepteerde gegevens en overgeslagen records rapporteren en een bestaand rapport beschermen tegen gedeeltelijke vervanging. Welk resultaat en welke opslagvolgorde passen daarbij?
  1. Meld geen geldige metingen en drie overgeslagen records; verplaats tijdelijke uitvoer naar het doelbestand voordat je de schrijver sluit.
  2. Meld geen geldige metingen en vier overgeslagen records; sluit tijdelijke uitvoer en vraag om atomaire vervanging.
  3. Meld geen geldige metingen en drie overgeslagen records; vervang het doelbestand direct en schrijf daarna de buffer door en sluit de schrijver.
  4. Meld geen geldige metingen en drie overgeslagen records; sluit tijdelijke uitvoer en vraag om atomaire vervanging.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Kom je niet uit je eigen opgave? Huiswerkhulp

Kernbegrippen

64 Kernbegrippen, elk met een definitie

A

Aanroepstack
De aanroepstack is de keten van methodeaanroepen die momenteel actief zijn in een thread, waarbij elke aanroep wacht op de gevraagde werkzaamheden.
Wanneer main de methode load aanroept, die parse aanroept, houdt de aanroepstack alle drie actieve methodeaanroepen bij.
Absoluut pad
Een absoluut pad geeft een locatie op vanaf de hoofdmap van het bestandssysteem, met zo nodig een schijfhoofdmap, onafhankelijk van de werkmap.
Een aanroep van toAbsolutePath() toont het absolute pad waarmee je kunt onderzoeken of een bestand in de verkeerde map staat.
Achteraan toevoegen
Achteraan toevoegen plaatst nieuwe uitvoer aan het einde van een bestaand bestand met behoud van de tekens die daar al zijn opgeslagen.
Een logregel achteraan toevoegen behoudt eerdere regels, maar voegt geen ontbrekend scheidingsteken vóór de nieuwe tekst in.
Afkappen
Afkappen verwijdert de inhoud van een bestaand bestand wanneer het wordt geopend voor vervanging, voordat nieuwe uitvoer noodzakelijkerwijs succesvol is geschreven.
De standaardwerking van Files.writeString veroorzaakt afkappen, zodat een latere schrijffout een onvolledig resultaat kan achterlaten.
ArithmeticException
Een ArithmeticException is een ongecontroleerde exceptie die een uitzonderlijke rekenkundige omstandigheid aangeeft, zoals geheeltallige deling door nul.
Een geheel gemiddelde berekenen met een lege array kan bij de deling ArithmeticException opwerpen.
Atomaire verplaatsing
Een atomaire verplaatsing verandert de locatie van een bestand in één bestandssysteembewerking wanneer dat wordt ondersteund; vervanging van een bestaand doelbestand hangt af van de implementatie.
Een atomaire verplaatsing maakt een voltooid rapport in één keer zichtbaar en niet-ondersteunde vervanging wordt als opslagfout gemeld.
AutoCloseable
AutoCloseable is de interface die close declareert en waarmee een object in aanmerking komt voor automatisch sluiten door een try-with-resources-instructie.
Een hulpklasse die AutoCloseable implementeert, kan de naam weergeven wanneer de automatische opruimcode close() aanroept.

B

Beschermd codegebied
Een beschermd codegebied omvat de werkzaamheden die door een try-instructie worden omsloten; de grens bepaalt wat wordt afgebroken wanneer een fout de afhandelaar bereikt.
Het beschermde codegebied omvat één record wanneer een try-instructie voor conversie binnen de lusbody staat.
Buffer
Een buffer is een geheugengebied dat tekst tijdelijk vasthoudt voordat die naar een bestand wordt doorgestuurd, waardoor minder kleine uitvoerbewerkingen nodig zijn.
De buffer van een schrijver kan de laatste rapportregel nog bevatten totdat die wordt doorgeschreven of de schrijver sluit.
Buffer doorschrijven
Buffer doorschrijven stuurt uitvoer die in de buffer van een schrijver wacht verder naar de bestemming; de open systeembron wordt daardoor niet zelf vrijgegeven.
Door de buffer door te schrijven verlaat wachtende tekst de buffer van de schrijver, maar het programma moet de bestandssysteembron nog steeds sluiten.
BufferedReader
Een BufferedReader leest tekeninvoer efficiënt met een buffer en kan één regel tegelijk teruggeven zonder het regeleinde.
Een BufferedReader-lus verwerkt grote invoer totdat readLine() aan het einde null teruggeeft.
BufferedWriter
Een BufferedWriter schrijft tekenuitvoer via een buffer, ondersteunt regeleinden en meldt invoer- en uitvoerfouten met IOException.
Een BufferedWriter schrijft een rapportregel en gebruikt daarna newLine() om het regeleinde van het platform toe te voegen.

C

catch-clausule
Een catch-clausule noemt een type dat kan worden opgeworpen en een afhandelaar die wordt uitgevoerd als een exceptie uit de beschermde werkzaamheden bij dat type past.
Een catch-clausule voor NumberFormatException kan om een ander getal vragen nadat de gebruiker “many” invoert.
Closeable
Closeable is een subinterface van AutoCloseable voor invoer- en uitvoersysteembronnen waarvan de methode close IOException declareert in plaats van het bredere Exception.
Een BufferedReader implementeert Closeable en komt dus in aanmerking voor een try-with-resources-declaratie.
CSV
CSV is tekst met kommagescheiden waarden, meestal met één record per regel; velden tussen aanhalingstekens kunnen komma’s bevatten en vereisen correcte CSV-verwerking.
Eenvoudige CSV met “Mina,28” kan worden gesplitst, terwijl een komma tussen aanhalingstekens in een naam een CSV-parser vereist.

D

Doorgifte van excepties
Doorgifte van excepties is het naar buiten doorgeven van een niet-afgehandelde exceptie via omsluitende code en aanroepende methoden totdat een afhandelaar wordt gevonden.
Door doorgifte van excepties gaat een mislukte leesbewerking vanuit een leeshulpmethode naar een aanroeper die om een ander bestand kan vragen.

E

Error
Een Error is een subtype van Throwable voor ernstige fouten tijdens de uitvoering of in de omgeving die normale herstelcode van een applicatie niet moet proberen op te vangen.
OutOfMemoryError behoort tot Error; gewone ongeldige invoer opvangen lost een uitgeputte heap niet op.
Exceptie
Een exceptie is een object dat een gebeurtenis beschrijft die een actief programma onderbreekt en de uitvoering overdraagt in de richting van een passende afhandelaar.
Een exceptie bij het parsen van “red” stopt de toewijzing voordat het programma het numerieke resultaat kan gebruiken.
Exceptiehiërarchie
Een exceptiehiërarchie is een overervingsstructuur waarmee aanroepers een specifieke fout of een gemeenschappelijke superklasse van verwante fouten kunnen opvangen.
Een exceptiehiërarchie kan fouten voor een onbekend artikel en onvoldoende voorraad onder één voorraadbasistype plaatsen.
Exceptiemaskering
Exceptiemaskering treedt op wanneer een latere overdracht van de uitvoering een eerdere fout vervangt en de oorspronkelijke exceptie voor de aanroeper verbergt.
Een return in finally kan exceptiemaskering veroorzaken door een fout uit het try-blok te laten vervallen.
Excepties ketenen
Excepties ketenen behoudt een oorspronkelijke exceptie als oorzaak van een nieuwe exceptie die een nuttiger type of meer context voor het opsporen van de fout toevoegt.
Excepties ketenen voegt het regelnummer van het mislukte record toe zonder de oorspronkelijke conversiestacktrace te verliezen.

F

finally-blok
Een finally-blok is opruimcode die wordt uitgevoerd wanneer de uitvoering de bijbehorende try-instructie verlaat, ook na normaal werk, een afhandelaar, een terugkeer of een opgeworpen exceptie.
Het finally-blok geeft een opruimmelding weer voordat een door return voorbereide waarde de aanroeper bereikt.
Fout op bestandsniveau
Een fout op bestandsniveau verhindert dat een bestandsbewerking betrouwbaar wordt voltooid, zoals bij ontbrekende invoer of een schijffout tijdens het opslaan van een rapport.
Een fout op bestandsniveau tijdens het lezen moet het opslaan stoppen, zodat onvolledige invoer niet als een volledig resultaat wordt gerapporteerd.
Fout op recordniveau
Een fout op recordniveau maakt één invoerrecord onbruikbaar, terwijl latere records kunnen worden verwerkt volgens een aanpak van overslaan en melden.
Een fout op recordniveau meldt “Line 6: invalid temperature” en laat de volgende iteratie bereikbaar.

G

Gecontroleerde exceptie
Een gecontroleerde exceptie is een subtype van Throwable buiten de takken van RuntimeException en Error waarvoor de opvangen-of-declarerenregel geldt.
Een IOException is een gecontroleerde exceptie, dus moet een leeshulpmethode die opvangen of declareren.

H

Herstel
Herstel is de reactie van het programma waardoor het na een fout zinvol kan doorgaan, bijvoorbeeld door opnieuw te proberen of een ongeldig record over te slaan.
Herstel in een invoerlus leest een nieuwe regel voordat een volgende conversie wordt geprobeerd, zodat het programma verder kan.

I

IllegalArgumentException
Een IllegalArgumentException is een ongecontroleerde exceptie die wordt gebruikt wanneer een aanroeper een waarde geeft die de argumentvereisten van een methode schendt.
Een methode kan IllegalArgumentException opwerpen wanneer het vereiste positieve aantal als -2 wordt opgegeven.
IllegalStateException
Een IllegalStateException is een ongecontroleerde exceptie die wordt gebruikt wanneer de huidige toestand van een object de gevraagde bewerking niet toestaat.
Een al verzonden bestelling kan IllegalStateException opwerpen wanneer code probeert er nog een artikel aan toe te voegen.
InputMismatchException
Een InputMismatchException is een ongecontroleerde scannerexceptie die optreedt wanneer een token niet past bij het type of bereik dat een conversiemethode vereist.
nextInt() werpt InputMismatchException op bij “several” en laat die token beschikbaar om te verwijderen.

K

Kopregel
Een kopregel benoemt de kolommen in een gegevensbestand en wordt afzonderlijk behandeld, zodat de labels niet als gewone recordwaarden worden geparset.
De kopregel “name,age” moet worden overgeslagen of gecontroleerd voordat de parser een leeftijd probeert om te zetten.

M

Meervoudige catch-clausule
Een meervoudige catch-clausule verbindt niet-verwante exceptietypen met een verticale streep, zodat ze dezelfde afhandelaarbody delen.
Een meervoudige catch-clausule kan een onjuist gevormd record melden bij zowel een ongeldig veld met een geheel getal als een ontbrekend array-element.

N

NullPointerException
Een NullPointerException is een ongecontroleerde exceptie die wordt opgeworpen wanneer een bewerking een object vereist maar een null-referentie ontvangt of gebruikt.
Een aanroep van name.trim() wanneer name null is, werpt NullPointerException op voordat tekst zonder omringende witruimte wordt teruggegeven.
NumberFormatException
Een NumberFormatException is een ongecontroleerde exceptie die wordt opgeworpen wanneer een numerieke tekstconversie de gevraagde getalwaarde niet kan opleveren.
Integer.parseInt("blue") werpt NumberFormatException op omdat de tekst geen geheel getal kan voorstellen.

O

Onbereikbare exceptieafhandelaar
Een onbereikbare exceptieafhandelaar is een catch-clausule die geen exceptie kan ontvangen omdat een eerdere afhandelaar alle passende typen al omvat.
Als IOException eerst staat en NoSuchFileException daarna wordt opgevangen, ontstaat een onbereikbare exceptieafhandelaar.
Onderdrukte exceptie
Een onderdrukte exceptie is een aanvullende fout die aan een hoofdexceptie is toegevoegd, zoals een sluitfout nadat een systeembronbody al een exceptie heeft opgeworpen.
De onderdrukte exceptie bewaart de sluitfout van een lezer terwijl de oorspronkelijke parseerfout wordt doorgegeven.
Ongecontroleerde exceptie
Een ongecontroleerde exceptie behoort tot RuntimeException of Error, of een subklasse van een van beide, en hoeft niet verplicht te worden opgevangen of gedeclareerd.
Een verkeerde array-index veroorzaakt een ongecontroleerde exceptie, ook als het programma met succes is gecompileerd.
Oorzaak
Een oorzaak is het oorspronkelijke object dat kan worden opgeworpen, dat binnen een wrapperexceptie wordt bewaard en via getCause beschikbaar is voor het opsporen van de fout.
De oorzaak van een InvalidRecordException kan de NumberFormatException zijn die het numerieke veld opwierp.
Opruimen
Opruimen is werk dat systeembronnen vrijgeeft of een instelling herstelt wanneer een bewerking eindigt, ook op paden die wegens een fout worden verlaten.
Opruimen sluit een geopend bestand, ook wanneer het omzetten van een van de records een exceptie opwerpt.
Opvangen-of-declarerenregel
De opvangen-of-declarerenregel vereist dat code die een gecontroleerde exceptie kan opwerpen, die afhandelt of een toepasselijk type in de methodedeclaratie vermeldt.
De opvangen-of-declarerenregel geldt voor een methode die Files.readString aanroept, ook wanneer het bestand dat de methode leest bestaat.

P

Parsen
Parsen interpreteert tekst volgens een verwachte structuur en zet velden om in waarden of objecten die het programma kan gebruiken.
Bij het parsen van een record met naam en leeftijd worden de twee velden gecontroleerd voordat de leeftijd wordt omgezet en een persoon wordt aangemaakt.
Path
Een Path is een object dat een locatie in een bestandssysteem voorstelt; het aanmaken ervan opent, maakt of controleert het genoemde bestand niet.
Path.of("data", "counts.txt") maakt een Path aan zonder te testen of de gegevensmap bestaat.
PrintWriter
Een PrintWriter schrijft opgemaakte tekenuitvoer met printmethoden die invoer- en uitvoerfouten intern registreren, zodat checkError die kan melden.
Een PrintWriter kan een gemiddelde opmaken met printf, maar succesvol terugkeren uit die aanroep bewijst niet dat het opslaan is geslaagd.

R

Regeleinde
Een regeleinde is de tekenreeks die een tekstregel afsluit, doorgaans LF op Linux en macOS of CRLF op Windows.
Een regeleinde dat door BufferedReader.readLine() wordt gelezen, wordt verwijderd voordat de methode de regeltekst teruggeeft.
Relatief pad
Een relatief pad duidt een locatie aan vanuit de werkmap in plaats van te beginnen bij de hoofdmap van het bestandssysteem of een schijf.
Het relatieve pad data/counts.txt kan een ander bestand aanduiden wanneer het programma in een andere map start.
RuntimeException
RuntimeException is de subklasse van Exception waarvan de afgeleide klassen ongecontroleerde fouten vertegenwoordigen, waaronder ongeldige argumenten en het gebruik van een null-referentie.
NumberFormatException bereikt RuntimeException via de superklasse IllegalArgumentException.

S

Scanner
Een Scanner leest tekst als tokens of regels en biedt conversiemethoden, terwijl onderliggende leesfouten bij invoer en uitvoer worden geregistreerd voor latere controle.
Een Scanner voor bestanden heeft na de lus een controle met ioException() nodig, zodat een mislukte leesbewerking niet succesvol lijkt.
Stacktrace
Een stacktrace rapporteert een exceptie en de actieve methodeaanroepen, beginnend bij de plaats waar de exceptie is vastgesteld en verder via de aanroepers.
Wanneer een door main aangeroepen hulpmethode bij een conversie mislukt, wijst de stacktrace eerst naar de conversie en daarna naar de hulpmethode en main.
Systeembron
Een systeembron is een object dat een externe voorziening beheert, zoals een open bestand, en na gebruik moet worden vrijgegeven.
Een bestandslezer is een systeembron die moet sluiten, ook wanneer het verwerken van de volgende regel mislukt.

T

Taal- en regio-instelling
Een taal- en regio-instelling geeft conventies voor taal en regionale opmaak die het parsen van getallen door een scanner en opgemaakte decimale uitvoer kunnen beïnvloeden.
Door de basisinstelling te kiezen, krijgen opgemaakte decimale gegevens de vorm “3.50”, ongeacht de instellingen van een computer.
Tekencodering
Een tekencodering koppelt teksttekens aan opgeslagen bytes en bepaalt hoe een lezer die bytes weer als tekst interpreteert.
Een niet-passende tekencodering kan UTF-8-tekst “café” weergeven als verminkte tekst zoals “café”.
throw
Het sleutelwoord throw begint een instructie die een exceptieobject vanuit de huidige bewerking opwerpt en de normale uitvoering daarvan onderbreekt.
Een throw vóór de veldtoewijzing wijst een ongeldige capaciteit af met behoud van de oude veldwaarde.
Throwable
Throwable is de Java-superklasse van objecten die kunnen worden opgeworpen, met Error en Exception als de twee directe hoofdsubklassen.
Een zelfgedefinieerde gecontroleerde exceptie behoort via Exception tot Throwable, zodat Java die kan opwerpen en opvangen.
throws-clausule
Een throws-clausule is een onderdeel van een methodedeclaratie dat exceptietypen vermeldt die de methode kunnen verlaten en de plicht tot afhandeling van gecontroleerde excepties aan aanroepers doorgeeft.
De throws-clausule throws IOException laat een bestandshulpmethode een fout melden aan een aanroeper die kan herstellen.
Tijdelijk bestand
Een tijdelijk bestand bewaart tussentijdse uitvoer afzonderlijk van het uiteindelijke doelbestand, zodat die kan worden voltooid voordat vervanging wordt geprobeerd.
Een tijdelijk bestand voor een rapport wordt in de doelmap aangemaakt voordat de voltooide tekst naar de bestemming wordt verplaatst.
try-blok
Een try-blok omsluit werkzaamheden waarvan excepties door bijbehorende catch-clausules kunnen worden afgehandeld; bij een fout worden de resterende instructies overgeslagen.
Een try-blok dat tekst naar een geheel getal omzet en daarna weergeeft, stopt vóór de weergave-instructie als de conversie mislukt.
try-with-resources
Try-with-resources is een Java-instructie die succesvol geopende AutoCloseable-systeembronnen automatisch sluit wanneer de beschermde werkzaamheden worden verlaten.
Try-with-resources sluit een schrijver vóór de lezer wanneer de declaraties in de kop eerst de lezer openen.

U

UncheckedIOException
Een UncheckedIOException is een standaard subklasse van RuntimeException die een IOException inpakt en de oorspronkelijke bestandsfout als oorzaak behoudt.
Een overschrijvende methode die geen IOException kan declareren, kan een bestandsfout doorgeven met UncheckedIOException.
UTF-8
UTF-8 is een Unicode-tekencodering die één byte gebruikt voor Latijnse basistekens en maximaal vier bytes voor andere Unicode-tekens.
In UTF-8 neemt “café” vijf bytes in, hoewel het maar vier zichtbare tekens bevat.

V

Veld
Een veld is één waarde binnen een gestructureerd record, zoals de naam of leeftijd die door een komma wordt gescheiden in een eenvoudige gegevensregel.
Het tweede veld in “Mina,” is leeg bij splitsen met een negatieve limiet die lege velden aan het einde behoudt.
Volgorde van catch-clausules
De volgorde van catch-clausules is de volgorde van boven naar beneden waarin afhandelaars worden getoetst, waarbij een afhandelaar voor een subklasse vóór die voor een superklasse moet staan.
De volgorde van catch-clausules plaatst NoSuchFileException vóór IOException wanneer elk een afzonderlijke melding nodig heeft.
Vroegtijdig afbreken
Vroegtijdig afbreken betekent ongeldige invoer of een ongeldige toestand afwijzen zodra die wordt vastgesteld, voordat latere werkzaamheden het probleem kunnen verspreiden of verhullen.
Vroegtijdig afbreken in een setter controleert een ongeldig percentage voordat een waarde aan het veld wordt toegewezen.

W

Wachtende terugkeer
Een wachtende terugkeer is een terugkeer waarvan de expressie is geëvalueerd, maar waarvan de overdracht aan de aanroeper wacht totdat de vereiste opruimcode is voltooid.
Een lokaal geheel getal wijzigen tijdens finally evalueert de expressie van een wachtende terugkeer niet opnieuw.
Werkmap
De werkmap is de huidige map van het programma van waaruit relatieve paden worden bepaald en die kan verschillen van de broncodemap.
Met /work/app als werkmap verwijst data/counts.txt naar een locatie binnen /work/app/data.

Z

Zelfgedefinieerde exceptie
Een zelfgedefinieerde exceptie is een door de applicatie gedefinieerde klasse die kan worden opgeworpen en aanroepers een betekenisvolle domeinfout laat herkennen en afhandelen.
Een voorraad gebruikt een zelfgedefinieerde exceptie om onvoldoende voorraad te onderscheiden van een ongeldig argument.

Over deze les

Door StudeliFout melden

Maak je eigen Studiemateriaal

Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.

Aan de slag