3
votes

Impossible de résoudre la méthode Character :: hashCode dans un flux Java

Dans mon exemple, j'essaye de créer une table ASCII à partir d'une séquence de caractères. J'ai réussi à le faire avec une List de chaînes mais j'ai échoué avec un tableau de caractères.

J'obtiens une erreur indiquant que Character :: hashCode ne peut pas être résolu dans Collectors.toMap () .

public class JavaCollectToMapEx2 {

    public static void main(String[] args) {
        // list of ASCII characters
        var chars = List.of("a", "b", "c", "d", "e", "f",
                "g", "h", "i", "j", "k", "l", "m", "n",
                "o", "p", "q", "r", "s", "t", "u", "v",
                "w", "x", "y", "z");

//      CharSequence chars2 = "abcdefghijklmnopqrstuvwxyz";
        char[] letters = "abcdefghijklmnopqrstuvwxyz".toCharArray();

        // Map to represent ASCII character table
        Map<Integer, String> asciiMap = chars.stream()
           .collect(Collectors.toMap(String::hashCode, Function.identity()));

        Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars() 
            .collect(Collectors.toMap(Character::hashCode, Function.identity()));

        System.out.println(asciiMap);
        System.out.println(asciiMap2);
    }
}

Y a-t-il un moyen de le faire?

Error:(26, 17) java: method collect in interface java.util.stream.IntStream cannot be applied to given types;
  required: java.util.function.Supplier<R>,java.util.function.ObjIntConsumer<R>,java.util.function.BiConsumer<R,R>
  found: java.util.stream.Collector<java.lang.Object,capture#1 of ?,java.util.Map<java.lang.Object,java.lang.Object>>
  reason: cannot infer type-variable(s) R
    (actual and formal argument lists differ in length)
Error:(26, 42) java: incompatible types: cannot infer type-variable(s) T,K,U,T
    (argument mismatch; invalid method reference
      incompatible types: java.lang.Object cannot be converted to char)


2 commentaires

et aucun message d'erreur ???


J'ai ajouté le message d'erreur complet.


3 Réponses :


6
votes

.chars () vous donne un IntStream , qui est un flux de int primitif, et non un flux de caractères ( plus d'infos ). C'est pourquoi aucune référence de méthode sur Character ne fonctionnera.

Pour réaliser ce que vous recherchez, vous aurez d'abord besoin d'un Stream :

Function<Character, Integer> f1 = e -> Character.hashCode(e);
Function<Character, Integer> f2 = e -> e.hashCode();

Maintenant, vous avez toujours le problème de l'utilisation d'une référence de méthode pour obtenir le code de hachage. Vous ne pouvez pas utiliser Character :: hashCode car il est ambigu de savoir quelle méthode vous voulez, car il y en a deux possibles:

  1. Le remplacement de l'objet # hashCode,
  2. La méthode statique int hashCode (char value)

Vous pouvez voir à partir de ce code, que les deux satisfont le premier argument de toMap():

Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters)
        .chars()
        .mapToObj(e -> (char) e)
        .collect(Collectors.toMap(e -> e.hashCode(), Function.identity()));

Pour résoudre ce problème , vous pouvez utiliser Object :: hashCode pour l'appel de méthode non statique.


1 commentaires

Le problème réel, concernant l'erreur du compilateur publiée, était que IntStream n'a pas de méthode collect (Collector) . Une alternative aurait été CharBuffer.wrap (lettres) .chars () .boxed () .collect (Collectors.toMap (Function.identity (), e -> (char) e));



2
votes

Vous devez d'abord mapper le IntStream à un Stream . Mais après cela, vous ne pouvez pas utiliser la référence de méthode Character :: hashCode car elle est ambiguë (niveau objet et niveau classe):

Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
        .mapToObj(i -> (char) i)
        .collect(Collectors.toMap(Object::hashCode, Function.identity()));

Sinon, vous pouvez simplement utiliser Object :: hashCode au lieu de i -> Character.hashCode (i) car la classe Character remplace son hashCode () code > méthode utilisant Character.hashCode():

public final class Character ... {
    @Override
    public int hashCode() {
        return Character.hashCode(value);
    }
}

Enfin, vous pouvez simplement utiliser ceci:

Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
        .mapToObj(i -> (char) i)
        .collect(Collectors.toMap(i -> Character.hashCode(i), Function.identity()));


0 commentaires

3
votes

Puisque vous utilisez la méthode collect () après CharBuffer :: chars qui renvoie IntStream , la seule méthode de collecte que vous pouvez utiliser est IntStream :: collect (fournisseur fournisseur, accumulateur ObjIntConsumer , combineur BiConsumer ) prenant 3 paramètres.

Si vous souhaitez utiliser la méthode de collecte à un paramètre, placez IntStream :: boxed avant de renvoyer Stream . Ensuite, la méthode Character :: hashCode devient ambiguë et l'expression lambda ne peut pas être utilisée:

Pour éviter cela, utilisez simplement une meilleure méthode mapToObj pour convertir directement en char sans avoir besoin de boxer, puis utiliser Object :: hashCode hérité de `Object:

Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
    .mapToObj(ch -> (char) ch)
    .collect(Collectors.toMap(Object::hashCode, Function.identity()));


0 commentaires