Java-Ausnahmebehandlung: Behandlung geprüfter Ausnahmen

vish234

Mitglied
Ich arbeite an einer Java-Anwendung, die Datei-E/A umfasst, und habe es mit geprüften Ausnahmen zu tun, insbesondere mit FileNotFoundException beim Versuch, eine Datei zu lesen. Ich möchte diese Ausnahme in meinem Code ordnungsgemäß behandeln.

Hier ist eine vereinfachte Version dessen, was ich versuche:

Java:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileProcessor {

    public static void main(String[] args) {
        String fileName = "sample.txt";

        try {
            BufferedReader reader = new BufferedReader(new FileReader(fileName));
            String line;

            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            reader.close();
        } catch (IOException e) {
            System.err.println("An error occurred while reading the file: " + e.getMessage());
        }
    }
}

In diesem Code versuche ich, den Inhalt einer Datei namens „sample.txt“ zu lesen. Wenn die Datei nicht vorhanden ist oder ein E/A-Fehler vorliegt, kann eine FileNotFoundException oder eine IOException auftreten.

Ich möchte die Ausnahmebehandlung in meinem Code verbessern, um aussagekräftigere Fehlermeldungen bereitzustellen und möglicherweise je nach Ausnahmetyp unterschiedliche Aktionen durchzuführen. Könnten Sie ein prägnantes Java-Codebeispiel bereitstellen, das zeigt, wie diese Ausnahmen effektiv behandelt und gleichzeitig der Code sauber und lesbar bleibt? Vielen Dank für Ihre Hilfe!

Community-verified icon
 
Erst einmal wäre wichtig, dass man erst einmal das Verhalten im Detail festlegt. Das ist etwas, das man nicht pauschal festlegen kann.

Hinweise bezüglich dieser Thematik:

a) Bei einer Exception sollte es sich um "exceptional events" handeln, also um Dinge, die unerwartet sind. Statt daher auf Exceptions zu reagieren sollte man schauen, ob es nicht besser ist, aktiv Dinge zu prüfen. Also z.B. existiert die Datei (z.B. File.exists), ist es eine Datei (z.B. File.isFile), ist sie lesbar (File.canRead), ...

b) Wenn man Exceptions annimmt und Details ausgeben will, dann sollte es nicht nur getMessage() sein. Der Stacktrace gehört da auch mit dazu.

c) Ggf. ist zu unterscheiden: Interaktion mit User (bei Dir Ausgabe auf der Konsole) vs. Logging. Ein Stacktrace interessiert den Anwender nicht, aber wenn Du als Entwickler dem Fehler auf den Grund gehen willst, dann wäre es gut wenn man nach einem Logfile fragen kann ...

d) Lesbarkeit ist hier wie überall: Über die üblichen Refactorings kann man hier vorgehen und dabei die üblichen Design-Punkte beachten:
  • Refactoring Rename: Das ist mit der wichtigste - man will klare saubere Bezeichner, damit Code lesbar ist.
  • Refactoring Extract to Method / Class / ...: Du unterteilst Code in Klassen und Methoden. Dabei versuchst du, auf einer Ebene zu sein.
  • Design: Separation of Concerns: Überlege Dir genau, was die Verantwortlichkeit einer Klasse / Methode / ... ist. Die Methode soll dann einfach eine Datei Zeile für Zeile lesen und diese dann ausgeben. Das ist die Verantwortlichkeit! Also gehört da nichts anderes rein. Die Methode kann dann eine IOException werfen. Diese wird dann in einer Methode gefangen, dessen Aufgabe es ist, die Datei zu lesen und auszugeben mit Behandlung des Fehlers. Die Fehlerbehandlung im Detail ist da dann egal - das wäre auf einem anderen Level.
  • Design - Trennung Logik von UI - ist eigentlich das gleiche Thema wie oben nur etwas spezifiziert. Man versucht, UI von der Logik zu trennen. Dazu gibt es dann Pattern wie MVC, MVVM, ... So trennt man hier die reine Logik, dass eine Datei gelesen werden soll von der Ausgabe. Fachlich wird dann de Anforderung, dass eine Datei Zeilenweise gelesen werden soll um diese Zeilen dann in einen PrintStream zu schreiben.

So eine Methode kann dann sein:
Java:
public void printFile(String filename, PrintStream out) {
    if (!checkFileCanBeRead(filename)) {
        handleFileCannotBeRead(filename);
        throw new CannotReadFileException("Unable to read file: " + filename, ex);
    }
    
    try {
        readAndPrintFile(filename, out);
    } catch (IOException ex) {
        log.error("Unable to read and print file: " + filename, ex);
        throw new CannotReadFileException("Unable to read file: " + filename, ex);
    }
}

Und da dies die reine Logik ist, können wir nur zurück geben, dass ein Fehler aufgetreten ist. Dazu habe ich hier eine Exception verwendet. Es kann auch eine Rückgabe erfolgen, die angibt, ob etwas ok ist. Was man oft findet, ist dass eben eine eigene Exception verwendet wird. Du bist auf einer anderen Ebene und es ist sozusagen eine Exception von einer höheren Ebene. Die Exception der unteren Ebene muss also nicht einmal verwendet werden. (Das ist aber ein KANN und kein MUSS.)

Das wären so ein paar Ideen, die hoffentlich etwas weiter helfen. Generell kann ich ansonsten nur
Clean Code Developer | Eine Initiative für mehr Professionalität in der Softwareentwicklung (clean-code-developer.de)
empfehlen, wenn man sich selbst Clean Code etwas beibringen will. Das sind dann sinnvolle Stufen, die man nach und nach befolgen kann. Und Uncle Bob (Robert C. Martin) ist ansonsten top, wenn es um die theoretischen Grundlagen geht. Seine Bücher sind nur zu empfehlen und es gibt gute Videos mit Ihm (Habe mal welche in einer Playlist gesammelt):
Uncle Bob - Clean Code - YouTube
 

Zurück
Oben