DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Uncategorized»La beauté de Java Facultatif et l’un ou l’autre
    Uncategorized

    La beauté de Java Facultatif et l’un ou l’autre

    février 16, 2023
    La beauté de Java Facultatif et l'un ou l'autre
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    Beaucoup d’entre nous, développeurs Java, en particulier les débutants, négligent souvent ses capacités de programmation fonctionnelles. Dans cet article, nous verrons comment enchaîner Optional et Either pour écrire du code concis et beau.

    Pour illustrer, supposons que nous ayons une banque où un utilisateur peut avoir zéro ou plusieurs comptes. Les entités se présentent comme ci-dessous :

    record User(
       int id,
       String name
    ) {}
    
    record Account(
        int id,
        User user // a user can have zero or more account
    ) {}

    Pour récupérer les entités, les référentiels se présentent comme ci-dessous :

    interface UserRepository {
        Optional<User> findById(int userId);
    }
    
    interface AccountRepository {
        Optional<Account> findAnAccountOfUser(User user); // given a user, find its any account if it has one
    }

    Maintenant, préparez-vous pour quelques missions !

    Première affectation

    Codons une méthode Optional<Account> findAnAccountByUserId(Integer userId) qui serait:

    1. Donné un userIdrenvoie n’importe quel compte de l’utilisateur, s’il y en a un
    2. Si soit il n’y a pas d’utilisateur avec l’identifiant donnéou il y a pas de compte de l’utilisateurretourne un vide Optional

    Une solution novice pourrait être la suivante :

        public Optional<Account> findAccountByUserId(int userId) {
    
            Optional<User> possibleUser = userRepository.findById(userId);
            if (possibleUser.isEmpty())
                return Optional.empty();
            var user = possibleUser.orElseThrow();
            return accountRepository.findAnAccountOfUser(user);
        }
    

    Mais, alors le map méthode de Optional frappe notre esprit! Au lieu de vérifier possibleUser.isEmpty()on pourrait juste map l’utilisateur, s’il est présent, à un compte :

        public Optional<Account> findAccountByUserId(int userId) {
            return userRepository
                    .findById(userId)
                    .map(accountRepository::findAnAccountOfUser);
        }
    

    Nous nous retrouvons avec une erreur de compilation car accountRepository.findAnAccountOfUser(user) renvoie un Optional<Account>tandis que le map méthode ci-dessus nécessite un Account. Pour ce cas d’utilisation précis, Optional fournit un flatMap méthode, qui aplatit imbriqué Optionals. Alors, changer map pour flatMap travaillerait.

        public Optional<Account> findAccountByUserId(int userId) {
            return userRepository
                    .findById(userId)
                    .flatMap(accountRepository::findAnAccountOfUser);
        }
    

    Cool! Préparez-vous pour une mission plus complexe.

    Deuxième affectation

    Lorsqu’un user/account n’est pas trouvé, au lieu de retourner un vide optionalque diriez-vous d’indiquer exactement ce qui n’a pas été trouvé: utilisateur ou compte ?

    Nous pourrions aborder ce problème de plusieurs façons :

    Lancer des exceptions

    Nous pourrions définir des exceptions personnalisées, à savoir. UserNotFoundException et AccountNotFoundExceptionet jetez ceux-ci :

        public Account findAccountByUserIdX(int userId) {
            var user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new);
            return accountRepository.findAnAccountOfUser(user).orElseThrow(AccountNotFoundException::new);
        }
    

    Cependant, l’utilisation d’exceptions pour les cas attendus est considérée comme un anti-modèle: Googling vous permettra d’obtenir de nombreux articles sur le sujet. Alors évitons ça.

    Utiliser une interface de résultat

    Une autre approche serait de retourner une coutume Result objet au lieu de retourner Optional; c’est à dire. Result findAnAccountByUserId(Integer userId). Le résultat serait une interface qui serait implémentée par des classes d’erreurs personnalisées, ainsi que Account et User.

    Utilisez l’un ou l’autre

    Une troisième approche, que je trouve plus simple, consiste à retourner un Either au lieu de Optional. Alors qu’un Optional détient zéro ou un valeur, une Either détient l’un des deux valeurs. Il est généralement utilisé pour contenir soit un erreur ou un succès valeur.

    Contrairement à Optionalvous n’obtenez pas de Java Either mise en œuvre hors de la boîte. Il y a pas mal de bibliothèques. Je préfère utiliser jbock-java/soit parce que c’est léger et simple.

    Alors, définissons d’abord le error interface et classe :

        interface Error {}
        record UserNotFound() implements Error {}
        record AccountNotFound() implements Error {}
    

    Essayons maintenant de coder :

    public Either<Error, Account> findAccountByUserId(int userId) {
      ...
    }

    Avez-vous remarqué ci-dessus que nous avons utilisé Error comme le gauche paramètre générique, alors que Account comme le droite un? Ce n’était pas accidentel : la convention lors de l’utilisation Either est-ce le gauche est utilisé pour les erreurs tandis que le le droit est utilisé pour le succès valeurs.

    Either a une API fonctionnelle similaire comme Optional. Par exemple, nous avons map et flatMap pour cartographier les valeurs de réussite, alors que nous avons mapLeft et flatMapLeft pour cartographier les erreurs. Nous avons aussi des méthodes utilitaires comme Either.left(value) et Either.right(value) créer Either objets. Jetez un œil à son API. Il possède de nombreuses fonctionnalités intéressantes pour la programmation fonctionnelle.

    Ainsi, poursuivant notre chemin, nous pourrions d’abord créer un either avoir le user ou error comme ci-dessous :

    public Either<Error, Account> findAccountByUserId(int userId) {
        var eitherErrorOrUser = userRepository
                    .findById(userId)
                    .map(Either::<Error, User>right)
                    .orElse(Either.left(new UserNotFound()))
        ...
    }
    

    Les lignes 4 et 5 ci-dessus convertissent un Optional<User> pour Either<UserNotFound, User>. Parce que convertir un Optional à un Either serait un cas d’utilisation courant, codons une méthode utilitaire pour cela :

    public class EitherUtils {
    
      public static <L, R>  Either<L, R> of(Optional<R> possibleValue, Supplier<L> errorSupplier) {
            return possibleValue.map(Either::<L, R>right).orElseGet(() -> Either.<L, R>left(errorSupplier.get()));
        }
    }

    Il faut le optional Et un errorSupplier. Le errorSupplier est utilisé pour composer l’erreur si le optional est vide.

    En l’utilisant, notre code ressemble maintenant à ceci :

    public Either<Error, Account> findAccountByUserId(int userId) {
        var eitherErrorOrUser = EitherUtils
            .<Error, User>of(userRepository.findById(userId), UserNotFound::new)
        ...
    }

    Ensuite, comme ci-dessus, eitherErrorOrUser pourrait être mappé pour un compte de la même manière. La solution complète ressemblerait alors à ceci :

        public Either<Error, Account> findAccountByUserId(int userId) {
            return EitherUtils
                    .<Error, User>of(userRepository.findById(userId), UserNotFound::new)
                    .flatMap(user -> of(accountRepository.findAnAccountOfUser(user), AccountNotFound::new));
        }
    

    Ça a l’air mignon, n’est-ce pas ?

    Résumé

    Envisagez d’utiliser les capacités de programmation fonctionnelle de Java dans la mesure du possible et rendez votre code mignon et concis !

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.