5
votes

Manière élégante de surmonter le type d'argument improbable pour equals (): Stream semble être sans rapport avec String

Je recherche un moyen élégant de surmonter tout en comparant n'importe quel objet Wrapper à Stream.

Lien de travail Github: https://github.com/vishwaratna/Unl Susceptible-argument-type-for-equals-Stream-String-/commit/d2380eb77f77731 / p>

Question de référence : Filtrage des clés d'une carte à un attribut de liste dans java-8

Récemment, je l'ai affronté en comparant le membre de List à une clé d'un Carte . Je sais qu'il existe d'autres moyens de comparer sans faire ce que je fais, mais je recherche un casting général, s'il est disponible.

System.out.println( stulist.stream()
                    .filter(s->s.getId()
                    .equals(map.entrySet()
                    .stream() 
                    .map(Map.Entry::getKey)))
                    .count());

        Map<String,String> map = new HashMap() {{
             put("1","20");
             put("2","30");
           }};


9 commentaires

Votre indentation peut vous tromper. Vous comparez s-> s.getID (). Equals (map.entrySet (). Stream (). Map (...)) . Donc, en fait, vous comparez le ID (qui est une chaîne) à un flux que vous avez créé à partir d'un ensemble. Vous devez vous assurer que votre comparaison porte sur des éléments du même type.


Je demande comment puis-je convertir le dernier en ancien être dans le flux?


Alors je ne suis pas sûr de ce que vous demandez. Vous ne pouvez pas diffuser entre un flux et une chaîne. Vous devez définir exactement ce que vous voulez faire avec ce flux. Voulez-vous comparer chacun de ses éléments à l ' ID ? Si oui, que faites-vous si certains sont égaux et les autres non? Quel est le résultat que vous souhaitez obtenir?


Qu'est-ce que votre code est censé faire? Vouliez-vous vérifier si la carte a la clé? Ce serait simplement .filter (s-> map.containsKey (s.getId ())


Mon code est censé compter sur la base du champ id, je connais l'autre moyen de le réaliser mais je veux savoir comment convertir le flux en type String si un type de cast est disponible.


Je n’insiste pas vraiment sur la solution mais sur la conversion de type


Vous devez suivre les conventions de dénomination Java: les noms de classe sont toujours écrits en PascalCase, c'est-à-dire que student doit être Student . Deuxièmement, vous utilisez le type brut HashMap , ce devrait être HashMap<> . Troisièmement, vous ne devriez pas utiliser la "construction à double accolade", car elle crée une sous-classe anonyme inutile de HashMap .


@Mc J'utilise la question d'une autre personne qui est en référence. Merci pour un coup de pouce sur les conventions, je l'apprécie vraiment.


Qu'entendez-vous exactement par conversion entre un flux et une chaîne? Ce sont deux choses totalement différentes qui ne peuvent être comparées. Ce sont des concepts différents. C'est comme demander comment convertir une pomme en distance. Qu'est-ce que vous essayez de faire exactement?


3 Réponses :


2
votes

Premièrement, ce que vous pourriez avoir l'intention de faire pourrait être:

// here the 's.getId' is a String while 'map.entrySet()...map()' provides 'Stream<String>'
.filter(s -> s.getId().equals(map.entrySet().stream().map(Map.Entry::getKey)))

Deuxièmement, la comparaison utilisant est égal à dans votre code est incorrecte car elle est entre des objets de deux différents types de String et Stream.

System.out.println(stulist.stream()
        .filter(s -> map.keySet().contains(s.getId()))
        .count());


4 commentaires

Vous avez fait la même chose dans le 2ème code ce que j'ai fait, et ce n'est vraiment pas une sortie correcte monsieur.


@CommonMan .filter (s -> map.keySet (). Contains (s.getId ())) est assez différent de ce que faisait votre filtre. Si le résultat n'est pas ce que vous désirez, pourriez-vous ajouter à la question que recherchez-vous de plus?


J'apprécie vraiment vos efforts, mais y a-t-il un moyen de diffuser du flux vers String ou vers n'importe quel wrapper en général?


@CommonMan Vous ne savez pas vraiment ce que vous entendez par le cast d'un Stream en String , voulez-vous les rejoindre par hasard?



2
votes

Vous pouvez utiliser map.containsKey pour éviter d'exécuter un flux sur l'ensemble d'entrées pour chaque entrée d'élève:

long count = stulist.stream()
                .filter(s -> map.entrySet()
                                .stream()
                                .map(Map.Entry::getKey)
                                .anyMatch(s.getId()::equals))
                .count();

Vous recevez l'avertissement car il est a détecté que vous testez String.equals (Stream ) , ce qui est bien sûr susceptible d'être un bogue (dans votre exemple, c'est certainement le cas).

Si vous deviez utiliser votre logique actuelle, la vérification appropriée devrait être:

long count = stulist.stream().map(student::getId).filter(map::containsKey).count();


2 commentaires

Merci ernest, j'apprécie vraiment vos efforts, je peux obtenir une sortie par une autre logique mais je veux savoir pourquoi aucune erreur de compilation ci-dessus ce que je fais?


La signature de Object.equals est equals (Object other) . Vous pouvez donc appeler "string" .equals (new Student ()) ou Integer.valueOf (1) .equals (new ArrayList ()) et vous ne 'pas une erreur du compilateur. C'est exactement ce qui se passe. Mais les IDE (ou le compilateur peut-être) peuvent détecter qu'il est très peu probable que ce soit ce que vous vouliez taper (car "string" et Student sont une sorte de comparaison pomme-orange)



3
votes

En gros, pour comprendre pourquoi le compilateur ne donne pas d'erreur, vous devriez regarder dans String.equals () implémentation de la méthode

System.out.println(
  stulist.stream()
         .map(Student::getId)
         .filter(map::containsKey)
         .count());

Revenons maintenant à cette ligne:

s.getId().equals(map.entrySet().stream().map(Map.Entry::getKey))

Comme nous le savons, s.getId () est de type String et map.entrySet (). stream (). map (Map.Entry :: getKey) est de type Stream.

Depuis Stream n'est pas instanceof String , il est clair que la méthode String.equals () renverra false à chaque fois s.getId () est comparé à map.entrySet (). stream (). map (Map.Entry :: getKey) (d'où, 0 compter à la fin). Et le compilateur n'émet pas d'erreur, car rien d'illégal ne s'est réellement passé (en tenant compte de l'implémentation de String.equals()).

Aussi, probablement , le moyen le plus propre de trouver count sans avertissement serait:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }


0 commentaires