Maison Java javaDidacticiel Erreurs de gestion des mauvaises pratiques

Erreurs de gestion des mauvaises pratiques

Sep 03, 2024 pm 06:33 PM

Error Handling Bad Practices

Cet article fait suite à mon précédent article sur la gestion des erreurs en 3 étapes.

Dans cet article, je souhaite montrer quelques mauvaises pratiques en matière de gestion des erreurs et peut-être quelques solutions rapides, si vous trébuchez
à travers eux dans votre base de code.

Avertissement, cet article de blog n'est qu'une opinion personnelle et vous devrez ajuster les recommandations à votre cas d'utilisation spécifique.

1. Avaler des exceptions

Je tombe régulièrement sur des bases de code où les exceptions sont silencieusement ignorées. Peut-être que le développeur était pressé ou voulait gérer les cas d'erreur plus tard ? Quoi qu'il en soit, c'est une mauvaise pratique car si l'erreur se produit :

  • l'utilisateur ne recevra aucun retour et pourra penser que l'opération a réussi.
  • il n'y a pas de trace de pile ou de message d'erreur à enquêter.
  • Parfois, il n'y a même pas d'entrée de journal appropriée, ce qui rend presque impossible la détection de l'erreur.

Mauvais exemple :

  /**
   * Reads some data from another service or repo and returns it.
   * The repo might throw an exception, but we don't care.
   */
  public Mono<String> getHello() {
    try {
      return helloRepository.getHello()
          .map("Hello %s"::formatted);
    } catch (Exception e) {
      // do nothing
      return Mono.just("Hello World");
    }
  }

Dans cet exemple, nous pourrions nous demander pourquoi certains utilisateurs se plaignent de ne pas recevoir le bon message de bonjour, mais nous ne voyons aucune erreur, nous pourrions penser que les utilisateurs sont simplement confus.

Option 1 - Conserver le try-catch et gérer l'erreur

Gérez l'erreur là où elle se produit, par ex. déjà dans le référentiel si possible.
Si vous devez le gérer ici, enregistrez au moins l'erreur et renvoyez un message d'erreur approprié.

Refactoring minimal

  • enregistrer l'erreur (éventuellement également le stacktrace)
  • renvoie un message d'erreur approprié
  public Mono<String> getHello() {
    try {
      return helloRepository.getHello()
          .map("Hello %s"::formatted);
    } catch (Exception e) {
      log.error("Error reading hello data from repository - {}", e.getMessage(), e);
      return Mono.error(new RuntimeException("Internal error reading hello data %s".formatted(e.getMessage()), e));
    }
  }

REMARQUE :

Cela pourrait casser le code en amont puisque vous renvoyez maintenant une erreur au lieu d'une valeur par défaut.

Option 2 – Refactorisation appropriée du flux réactif

Il serait préférable de gérer l'erreur dans l'API du flux réactif

  public Mono<String> getHelloHandling() {
    return helloRepository.getHello()
      .map("Hello %s"::formatted)
      // wrap the exception in a RuntimeException with a meaningful message
      .onErrorMap(e -> new RuntimeException("Internal error reading hello data from HelloRepository` %s".
          formatted(e.getMessage()), e));
  }

1b. Avaler des exceptions - avec un flux réactif

Le modèle de l'exemple 1 apparaît également dans les flux réactifs :

  public Mono<String> getHello() {
    return helloRepository.getHello()
        .map("Hello %s"::formatted)
        // do nothing on error, just return a default value
        .onErrorReturn("Hello world");
  }

Ça a l'air très joli et propre, non ? Mais nous ne pourrons pas détecter que l'erreur est levée dans le référentiel !
S'il existe une valeur par défaut, au moins un journal des erreurs doit être rédigé.

Atténuation

Comme dans l'exemple précédent, nous encapsulons l'exception dans une autre exception, cette fois dans une exception personnalisée qui facilite même la détection de l'endroit spécifique où cette exception est levée

  public Mono<String> getHello2() {
    return helloRepository.getHello()
        .map("Hello %s"::formatted)
        .onErrorMap(
            e -> new CustomException("Error reading hello-data from repository - %s".formatted(e.getMessage()), e));
  }

2. Enregistrer à plusieurs reprises le stacktrace pour la même exception

L'opposé de la suppression silencieuse des exceptions consiste à enregistrer la même exception plusieurs fois. C'est une mauvaise pratique car elle confond les journaux avec des centaines ou des milliers de lignes de stacktraces sans apporter de signification supplémentaire.

Dans mon pire exemple, j'ai trouvé la même trace de pile cinq fois dans les journaux sans aucun message significatif.

Mauvais exemple :

Le contrôleur :

@RestController
@AllArgsConstructor
@Slf4j
public class HelloController {

  private final HelloService helloService;

  @GetMapping("/hello")
  public Mono<ResponseEntity<String>> hello() {
    return helloService.getHello()
        .map(ResponseEntity::ok)
        .defaultIfEmpty(ResponseEntity.notFound().build())
        .onErrorResume(e -> {
          log.error("Error:", e);
          return Mono.error(e);
        });
  }
}

Et dans le Service :

@Service
@AllArgsConstructor
@Slf4j
public class HelloService {

  private final HelloRepository helloRepository;

  /**
   * Reads some data from another service or repo and returns it.
   */
  public Mono<String> getHello() {
    return helloRepository.getHello()
        .map("Hello %s"::formatted)
        .onErrorResume(e -> {
          log.error("Error:", e);
          return Mono.error(e);
        });
  }
}

... et probablement dans d'autres endroits...

Atténuation

Ceci est expliqué dans mon article précédent Gestion des erreurs en 3 étapes, je ne montrerai donc pas le code ici, mais plutôt une recommandation :

  • Avoir un gestionnaire d'erreurs global qui enregistre l'erreur et renvoie un message d'erreur approprié à l'utilisateur.
  • Dans le code, évitez le stacktrace mais
    • enveloppez l'exception dans une exception personnalisée ou une exception d'exécution avec un message significatif
    • enregistrer le message d'erreur (pas la trace complète de la pile)
    • enregistrer la trace de pile uniquement dans le gestionnaire d'erreurs global

3. Détectez les exceptions génériques

La détection d'exceptions génériques telles que Exception ou Throwable peut entraîner un comportement involontaire et rendre le débogage assez difficile. Il est préférable d'attraper des exceptions spécifiques.

Mauvais exemple

  public Mono<String> getHello() {
    try {
      return helloRepository.getHello();
    } catch (Exception e) {
      log.error("Error while fetching hello data", e);
      return Mono.empty();
    }
  }

Atténuation

Détectez des exceptions spécifiques pour gérer différents scénarios d'erreur de manière appropriée.

  public Mono<String> getHello() {
    try {
      return helloRepository.getHello();
    } catch (SQLException e) {
      return Mono.error(new HelloDataException("Database error while getting hello-data - %s".formatted(e.getMessage()), e));
    } catch (IOException e) {
      // maybe perform a retry?
      return Mono.error(new HelloDataException("IO error while getting hello-data - %s".formatted(e.getMessage()), e));
    }
  }

et l'équivalent en utilisant l'API de flux réactif

  public Mono<String> getHello() {
    return helloRepository.getHello()
        .onErrorMap(SQLException.class, e -> new HelloDataException("Database error while getting hello-data - %s".formatted(e.getMessage()), e))
        .onErrorMap(IOException.class, e -> new HelloDataException("IO error while getting hello-data - %s".formatted(e.getMessage()), e));
  }

4. (Sur)utilisation des exceptions vérifiées

À mon avis, les exceptions vérifiées sont une erreur en Java, elles ne sont pas très utiles et conduisent souvent à de mauvaises pratiques et à un code encombré.

Mauvais exemple

public void someMethod() throws IOException, SQLException {
  // some code that might throw an exception
}

Avec les exceptions vérifiées, vous devez les gérer dans le code appelant, ce qui rend plus difficile l'utilisation d'autres modèles, par ex. programmation fonctionnelle ou flux réactifs ou au printemps le gestionnaire d'erreurs global.

Exception :
Les exceptions cochées sont utiles, par ex. dans le code de la bibliothèque, où vous souhaitez forcer l'utilisateur à gérer l'exception.

Atténuation

Utilisez des exceptions non contrôlées pour les scénarios dans lesquels on ne peut raisonnablement pas s'attendre à ce que l'appelant récupère.

public void someMethod() {
  try {
    // some code that might throw an exception
  } catch (IOException | SQLException e) {
    throw new RuntimeException("An error occurred - %s".formatted(e.getMessage()), e);
  }
}

Using Exceptions for Control Flow

Using exceptions for control flow makes the code hard to understand and can lead to performance issues.

Bad Example

try {
  int value = Integer.parseInt("abc");
} catch (NumberFormatException e) {
  // handle the case where the string is not a number
}

Mitigation

Use a regular flow control mechanism like an if-statement.

String value = "abc";
if (value.matches("\\d+")) {
  int number = Integer.parseInt(value);
} else {
  // handle the case where the string is not a number
}

Conclusion

In this article I showed some bad practices in error handling and how to mitigate them.
I hope you found this article helpful and maybe you can use some of the recommendations in your codebase and in your next refactoring.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Tutoriel PHP
1538
276
Java Virtual Threads Performance Benchmarking Java Virtual Threads Performance Benchmarking Jul 21, 2025 am 03:17 AM

Les fils virtuels présentent des avantages de performances significatifs dans les scénarios très concurrencés et IO, mais l'attention doit être accordée aux méthodes de test et aux scénarios applicables. 1. Les tests corrects devraient simuler des affaires réelles, en particulier les scénarios de blocage IO, et utiliser des outils tels que JMH ou Gatling pour comparer les threads de plate-forme; 2. L'écart de débit est évident, et il peut être plusieurs fois à dix fois supérieur à 100 000 demandes simultanées, car elle est plus légère et efficace dans la planification; 3. Pendant le test, il est nécessaire d'éviter de poursuivre aveuglément des nombres de concurrence élevés, de s'adapter aux modèles IO non bloquants et de prêter attention aux indicateurs de surveillance tels que la latence et le GC; 4. Dans les applications réelles, elle convient au backend Web, au traitement des tâches asynchrones et à un grand nombre de scénarios IO simultanés, tandis que les tâches à forte intensité de processeur sont toujours adaptées aux threads de plate-forme ou à Forkjoinpool.

Java Microservices Service Mesh Intégration Java Microservices Service Mesh Intégration Jul 21, 2025 am 03:16 AM

ServiceMesh est un choix inévitable pour l'évolution de l'architecture de microservice Java, et son cœur réside dans le découplage de la logique réseau et du code commercial. 1. ServiceMesh gère l'équilibrage de la charge, le fusible, la surveillance et d'autres fonctions par le biais d'agents side-car pour se concentrer sur les entreprises; 2. Istio Envoy convient aux projets moyens et grands, et Linkerd est plus léger et adapté aux essais à petite échelle; 3. Les microservices Java devraient fermer la feigne, le ruban et d'autres composants et les remettre à Istiod pour la découverte et la communication; 4. Assurer l'injection automatique de side-car pendant le déploiement, prêter attention à la configuration des règles de trafic, à la compatibilité du protocole et à la construction du système de suivi des journaux, et adoptez la planification incrémentielle de la migration et de la surveillance pré-contrôler.

Comment gérer les transactions en Java avec JDBC? Comment gérer les transactions en Java avec JDBC? Aug 02, 2025 pm 12:29 PM

Pour gérer correctement les transactions JDBC, vous devez d'abord désactiver le mode de validation automatique, puis effectuer plusieurs opérations, et enfin vous engager ou randonner en fonction des résultats; 1. Appelez Conn.SetAutoCommit (false) pour démarrer la transaction; 2. Exécuter plusieurs opérations SQL, telles que l'insertion et la mise à jour; 3. Appelez Conn.Commit () Si toutes les opérations sont réussies, et appelez Conn.Rollback () Si une exception se produit pour garantir la cohérence des données; Dans le même temps, les ressources TRY-With doivent être utilisées pour gérer les ressources, gérer correctement les exceptions et clôturer les connexions pour éviter la fuite de connexion; De plus, il est recommandé d'utiliser des pools de connexion et de définir des points de sauvegarde pour réaliser un retour en arrière partiel, et de maintenir les transactions aussi courtes que possible pour améliorer les performances.

Mastering Injection de dépendance en Java avec le printemps et Guice Mastering Injection de dépendance en Java avec le printemps et Guice Aug 01, 2025 am 05:53 AM

DépendanceInjection (DI) IsadesignPatternwhereBjectSeveveveltency dexternal, promotionnloosecouplingAndreasiestingthroughroughConstructor, seter, orfieldInjection.2.springframeworkusesannotations like @ composant, @ service et @ autowiredwithjava-baskusecondotations like @ composant, @ service et @ autowiredwithjava-basesConfitations lik

Comparaison des frameworks Java: Spring Boot vs Quarkus vs MicronAut Comparaison des frameworks Java: Spring Boot vs Quarkus vs MicronAut Aug 04, 2025 pm 12:48 PM

Pré-formancetartuptimemoryusage, quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusofperforming lightbetterine scénarios.

Construire des API RESTful à Java avec Jakarta EE Construire des API RESTful à Java avec Jakarta EE Jul 30, 2025 am 03:05 AM

Setupamaven / gradleprojectwithjax-rsDependces likejersey; 2.CreateArestResourceUsingannotationsSuchas @ pathand @ get; 3.ConfigureTheApplicationViaApplicationsUbclassorweb.xml; 4.AddjacksonforjsonBindingByCludingJersey-Media-Json-Jackson; 5.DeploEp

Comment travailler avec le calendrier à Java? Comment travailler avec le calendrier à Java? Aug 02, 2025 am 02:38 AM

Utilisez des classes dans le package Java.Time pour remplacer les anciennes classes de date et de calendrier; 2. Obtenez la date et l'heure actuelles via LocalDate, LocalDateTime et Localtime; 3. Créez une date et une heure spécifiques en utilisant la méthode OF (); 4. Utilisez la méthode plus / moins pour augmenter et diminuer le temps; 5. Utilisez ZonedDateTime et ZoneID pour traiter le fuseau horaire; 6. Format et chaînes de date d'analyse via DateTimeFormatter; 7. Utilisez instantanément pour être compatible avec les anciens types de dates si nécessaire; Le traitement des dattes dans le Java moderne devrait donner la priorité à l'utilisation de Java.timeapi, qui fournit clairement, immuable et linéaire

Techniques d'optimisation et de profilage des performances Java Techniques d'optimisation et de profilage des performances Java Jul 31, 2025 am 03:58 AM

Utilisez des outils d'analyse des performances pour localiser les goulots d'étranglement, utiliser VisualVM ou JProfiler dans la phase de développement et de test, et donner la priorité à l'async-profil dans l'environnement de production; 2. Réduire la création d'objets, réutiliser les objets, utiliser StringBuilder pour remplacer l'épissage de la chaîne et sélectionner les stratégies GC appropriées; 3. Optimiser l'utilisation de la collection, sélectionner et prérégler la capacité initiale selon la scène; 4. Optimiser la concurrence, utiliser des collections simultanées, réduire la granularité de verrouillage et régler raisonnablement le pool de threads; 5. Assurez les paramètres JVM, définissez la taille du tas raisonnable et le collecteur de déchets à faible latence et activez les journaux GC; 6. Évitez la réflexion au niveau du code, remplacez les classes de wrapper par des types de base, retardez l'initialisation et utilisez final et statique; 7. Test et surveillance des performances continues, combinées avec JMH

See all articles