Comment puis-je écrire le code ci-dessous en utilisant l'expression lambda dans java8. Je suis nouveau sur Java 8.
globalPricingRequests.forEach((globalPricingRequest) -> { if (checkIfValueLessThanZero(globalPricingRequest.getFeePerTransact())) { throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } List<EventTypePricingMapping> eventTypePricingMappings = globalPricingRequest.getEventTypePricingList(); eventTypePricingMappings.forEach((eventTypePricingMapping) -> { if (checkIfValueLessThanZero(eventTypePricingMapping.getFeePerRevenue())) { throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } if (checkIfValueLessThanZero(eventTypePricingMapping.getFeePerReg())) { throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } }); }); private boolean checkIfValueLessThanZero(Object object) { if (object instanceof BigDecimal) { if (object != null && ((BigDecimal) object).intValue() < 0) { return true; } } return false; }
J'ai encore essayé le code ci-dessous selon la suggestion. Y a-t-il autre chose que nous pouvons améliorer dans ce code pour l'écrire en utilisant davantage lambdas.
for (GlobalPricingRequest globalPricingRequest : globalPricingRequests) { BigDecimal feePerTrans = globalPricingRequest.getFeePerTransact(); if (feePerTrans != null && feePerTrans.intValue() < 0) { throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } List<EventTypePricingMapping> eventTypePricingMappings = globalPricingRequest.getEventTypePricingList(); for (EventTypePricingMapping eventTypePricingMapping : eventTypePricingMappings) { BigDecimal feePerRevenue = eventTypePricingMapping.getFeePerRevenue(); if (feePerRevenue != null && feePerRevenue.intValue() < 0) { throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } if (eventTypePricingMapping.getFeePerRevenue().intValue() < 0) { throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } } }
4 Réponses :
Vous pouvez utiliser stream deux fois et améliorer la lisibilité de votre code comme:
Predicate<BigDecimal> feeCheck = feePerTransactOrRevenue -> feePerTransactOrRevenue != null && feePerTransactOrRevenue.intValue() < 0; boolean globalRequestCheck = globalPricingRequests.stream() .map(GlobalPricingRequest::getFeePerTransact) .anyMatch(feeCheck); boolean eventTypeCheck = globalPricingRequests.stream() .map(GlobalPricingRequest::getEventTypePricingList) .flatMap(List::stream) .map(EventTypePricingMapping::getFeePerRevenue) .anyMatch(feeCheck); // if any of the element matches the condition, throw the exception if (globalRequestCheck || eventTypeCheck) { throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); }
Cela peut être basé sur une opinion, cela améliore certainement la lisibilité par rapport aux autres solutions forEach. De plus, le temps d'exécution global dans le pire des cas doit rester le même que O (n * m)
où n
étant la taille de globalPricingRequests
et m
étant la taille maximale d'une liste getEventTypePricingList
.
globalPricingRequest.forEach(data -> { if (data.getFeePerTransact() != null && data.getFeePerTransact().intValue() < 0) { // you can only throw unchecked exception in lambda function throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } data.getEventTypePricingList().forEach(event-> { if (event.getFeePerRevenue() != null && event.getFeePerRevenue().intValue() < 0) { // you can only throw unchecked exception in lambda function throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); }// this if statemnt in your code is twice }); });
Votre problème ne concerne pas les lambdas, mais l'organisation du code. Vous disposez d'une donnée, c'est-à-dire List
et un ensemble de règles de validation . Tout ce dont vous avez besoin pour appliquer ces règles de validation aux données données.
Cette approche vous donne la flexibilité d'ajouter ou de supprimer facilement des règles de validation. Et testez ou vérifiez chaque règle séparément.
La solution optimale consiste à diviser chaque validation en une classe distincte.
D'abord , créer un gestionnaire et une interface pour la règle de validation:
GlobalPricingRequestValidationManager validationManager = new GlobalPricingRequestValidationManager(); List<GlobalPricingRequest> globalPricingRequests = Collections.emptyList(); validationManager.validate(globalPricingRequests);
Deuxièmement , implémentez chaque règle de validation dans la classe séparée (a été ajoutée au gestionnaire):
public final class TransactionFeeEqualOrGreaterThanZeroValidationRule implements GlobalPricingRequestValidationManager.ValidationRule { @Override public void validate(List<GlobalPricingRequest> globalPricingRequests) { if (globalPricingRequests.stream() .map(GlobalPricingRequest::getFeePerTransact) .filter(Objects::nonNull) .anyMatch(val -> val.signum() == -1))) throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } } public final class RevenueFeeEqualOrGreaterThanZeroValidationRule implements GlobalPricingRequestValidationManager.ValidationRule { @Override public void validate(List<GlobalPricingRequest> globalPricingRequests) { if (globalPricingRequests.stream() .map(GlobalPricingRequest::getEventTypePricingList) .flatMap(List::stream) .map(EventTypePricingMapping::getFeePerRevenue) .filter(Objects::nonNull) .anyMatch(val -> val.signum() == -1))) throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); } }
Code Clinet:
public final class GlobalPricingRequestValidationManager { private final List<ValidationRule> validationRules = Arrays.asList( new TransactionFeeEqualOrGreaterThanZeroValidationRule(), new RevenueFeeEqualOrGreaterThanZeroValidationRule()); public void validate(List<GlobalPricingRequest> globalPricingRequests) { validationRules.forEach(validationRule -> validationRule.validate(globalPricingRequests)); } public interface ValidationRule { void validate(List<GlobalPricingRequest> globalPricingRequests); } }
Ce type de validation que vous effectuez est meilleur via l'approche impérative, néanmoins nous pouvons utiliser des lambdas le cas échéant.
Premièrement, j'isolerais les conditions répétitives à un prédicat local avec l'utilisation de signum code> comme également suggéré par @Thomas Kläger sous le message car il est plus approprié dans ce cas précis que
intValue
.
public static void isValidOrElseThrowBadRequestException(BigDecimal data, Predicate<BigDecimal> criteria) throws Exception { // change the exception to the specific one you're using if(criteria.test(data)) throw ExceptionHelper.badRequest("Fee Per Transaction can't be less than zero"); }
Alors votre impératif approche ressemblerait à:
for (GlobalPricingRequest globalPricingRequest : globalPricingRequests) { isValidOrElseThrowBadRequestException(globalPricingRequest.getFeePerTransact(), criteria); for (EventTypePricingMapping eventTypePricingMapping : globalPricingRequest.getEventTypePricingList()) { isValidOrElseThrowBadRequestException(eventTypePricingMapping.getFeePerRevenue(), criteria); } }
Où isValidOrElseThrow
est défini comme:
Predicate<BigDecimal> criteria = b -> b != null && b.signum() < 0;
Juste avec quelques isolations ici et là nous sommes en mesure de rendre le code plus lisible.
Qu'est-ce que vous avez déjà essayé? Nous ne sommes pas là pour réécrire vos trucs.
Je ne comprends même pas comment écrire lambda qui vérifie une condition et lance une exception sur la base si cela, un indice ou une suggestion serait utile
oui si je peux gérer la redondance des conditions
Mise à jour du code que j'ai encore essayé
Veuillez également noter que BigInteger # intValue ( ) est une mauvaise manière de vérifier le signe d'un
BigInteger
. Selon la documentation: Notez que cette conversion peut [...] renvoyer un résultat avec le signe opposé ! Vous devez utiliser BigInteger # signum () à la placeJuste un avis personnel, mais je déconseillerais de longs lambdas comme celui-ci, du point de vue de la maintenance future. Envisagez plutôt d'extraire des méthodes et utilisez une référence de méthode.
notez que
if (eventTypePricingMapping.getFeePerRevenue (). intValue () <0) {...
est redondant comme vous l'avez déjà faitBigDecimal feePerRevenue = eventTypePricingMapping.getFeePerRevenue (); if (feePerRevenue! = null && feePerRevenue.intValue () <0) {...
avant cela.