A propos des Exceptions

Share:
Exceptions java
Lorsque Java est apparu il y a quelques décennies, il était très novateur à l'époque. En particulier, son mécanisme de gestion des exceptions était une grande amélioration par rapport à C / C ++ . Par exemple, pour lire dans le fichier, il peut y avoir beaucoup d'exceptions: le fichier peut être absent, il peut être en lecture seule, etc.

Le pseudo-code associé à Java ressemblait à:
File file = new File("/path");

if (!file.exists) {
    System.out.println("File doesn't exist");
} else if (!file.canRead()) {
    System.out.println("File cannot be read");
} else {
    // Finally read the file
    // Depending on the language
    // This could span seveal lines
}
L'idée derrière les blocs Try Catch était de séparer le code métier et le code de gestion des exceptions.
try {
    File file = new File("/path");
    // Finally read the file
    // Depending on the language
    // This could span seveal lines
} catch (FileNotFoundException e) {
    System.out.println("File doesn't exist");
} catch (FileNotReadableException e) {
    System.out.println("File cannot be read");
}
Bien sûr, le code ci-dessus est autonome. Il constitue probablement le corps d'une méthode dédiée à la lecture de fichiers.
public String readFile(String path) {
    if (!file.exists) {
        return null;
    } else if (!file.canRead()) {
        return null;
    } else {
        // Finally read the file
        // Depending on the language
        // This could span seveal lines
        return content;
    }
}
L'un des problèmes avec les blocs catch ci-dessus est qu'ils retournent null. Par conséquent:
Le code appelant doit vérifier à chaque fois les valeurs NULL
Il n'y a aucun moyen de savoir si le fichier n'a pas été trouvé ou s'il n'était pas lisible.
L'utilisation d'une approche plus fonctionnelle corrige le premier problème et permet donc de composer des méthodes:
public Optional<String> readFile(String path) {
    if (!file.exists) {
        return Optional.empty();
    } else if (!file.canRead()) {
        return Optional.empty();
    } else {
        // Finally read the file
        // Depending on the language
        // This could span seveal lines
        return Optional.of(content);
    }
}
Malheureusement, cela ne change rien au second problème. Les adeptes d'une approche purement fonctionnelle rejetteraient probablement l'extrait précédent en faveur de quelque chose comme ça:
public Either<String, Failure> readFile(String path) {
    if (!file.exists) {
        return Either.right(new FileNotFoundFailure(path));
    } else if (!file.canRead()) {
        return Either.right(new FileNotReadableFailure(path));
    } else {
        // Finally read the file
        // Depending on the language
        // This could span seveal lines
        return Either.left(content);
    }
}
Et hop, il y a une belle amélioration par rapport au code précédent. Maintenant c'est plus significatif, car le code indique exactement pourquoi il a échoué (si c'est le cas), grâce à la partie droite de la valeur de retour.
Malheureusement, il reste un problème, et pas un petit. Qu'en est-il du code d'appel? Il aurait besoin de gérer l'échec. Ou plus probablement, laissez la méthode appelante le gérer, et ainsi de suite, jusqu'à la méthode la plus élevée. Pour moi, cela rend impossible de considérer l'approche fonctionnelle sans exception comme une amélioration.

De plus, les langages et les frameworks peuvent fournir des solutions pour gérer les exceptions au plus haut niveau. Par exemple, sur la machine virtuelle Java, on a :
  • Dans la JDK, Thread.setDefaultUncaughtExceptionHandler ()
  • Dans Vaadin, VaadinSession.setErrorHandler ()
  • Dans Spring MVC, @ExceptionHandler
  • etc.

De cette façon, vous pouvez laisser vos exceptions passer à l'endroit où elles peuvent être gérées comme elles le devraient.

Post a Comment

Aucun commentaire