3
votes

Comment retourner false pour une liste vide si vous utilisez Stream.allMatch ()?

Je souhaite utiliser une seule instruction avec les flux Java.

Je veux filtrer tous les objets Servicework, où les exigences sont "vraies", puis vérifier si tous les objets Servicework ont ​​le statut "Terminé".

Mais si le serviceworkList est vide, alors la variable "validate" est fausse. Je connais la spécification de allMatch, que si la liste est vide, alors le retour est vrai.

Des suggestions sur la façon dont je pourrais reconstruire le flux, que si la liste est vide, j'aurais faux?

enum Status {
    DONE, NOT_DONE
}

class ServiceWork {

    private Status status;
    private boolean isRequirement;

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public boolean isRequirement() {
        return isRequirement;
    }

    public void setRequirement(boolean requirement) {
        isRequirement = requirement;
    }
}

public class Service{

    List<ServiceWork> serviceWorkList = new ArrayList<>();


    boolean validate = serviceWorkList
        .stream()
        .filter(ServiceWork::isRequirement)
        .allMatch(a -> a.getStatus() == Status.DONE);

}


5 commentaires

Voulez-vous dire "si serviceWorkList est vide" ou "s'il n'y a aucun élément correspondant au prédicat ServiceWork :: isRequirement "?


@Holger: je veux dire s'il n'y a pas d'élément correspondant au prédicat


serviceWorkList .stream () .filter (ServiceWork :: isRequirement) .map (a -> a.getStatus () == Status.DONE) .reduce (Boolean :: logicalAnd) .orElse (false);


Vérifiez ceci stackoverflow.com/a/56744122/6505418


Ressemble à un double de stackoverflow.com/questions/46075776


3 Réponses :


9
votes

Ajoutez simplement une vérification supplémentaire que la liste n'est pas vide:

Set<Status> status = serviceWorkList
    .stream()
    .filter(ServiceWork::isRequirement)
    .map(ServiceWork::getStatus())
    .collect(Collectors.toCollection(() -> EnumSet.noneOf(Status.class)));

boolean validate = status.remove(Status.DONE) == Status.DONE && status.isEmpty();

Après votre commentaire, vous pouvez utiliser ceci:

boolean validate = !serviceWorkList.isEmpty() && serviceWorkList
    .stream()
    .filter(ServiceWork::isRequirement)
    .allMatch(a -> a.getStatus() == Status.DONE);

Il rassemble d'abord tous les statuts dans un EnumSet , puis supprime Status.DONE de l'ensemble et si l'ensemble est vide, chaque élément a getStatus () == Status.DONE .

Cela supprime le court-circuit, donc il continuera à itérer sur la serviceWorkerList même si un Status autre que Status.DONE a été rencontré


1 commentaires

je veux dire s'il n'y a pas d'élément correspondant au prédicat ServiceWork :: isRequirement



1
votes

Stream.allMatch () retournera toujours vrai pour une liste vide

Vous devriez ajouter une autre validation, comme

boolean validate = !serviceWorkList.isEmpty() && serviceWorkList
    .stream()
    .filter(ServiceWork::isRequirement)
    .allMatch(a -> a.getStatus() == Status.DONE);


1 commentaires

je veux dire s'il n'y a pas d'élément correspondant au prédicat ServiceWork :: isRequirement



0
votes

Il ne sera pas pratique de faire votre validation complète en une seule opération de flux. Je suggère deux opérations de flux:

    boolean allRequirementsDone = serviceWorkList.stream()
            .filter(ServiceWork::isRequirement)
            .allMatch(a -> a.getStatus() == Status.DONE);
    boolean atLeastOneRequirement = serviceWorkList.stream()
            .anyMatch(ServiceWork::isRequirement);
    boolean validate = allRequirementsDone && atLeastOneRequirement;


0 commentaires