Не удается разрешить метод Character :: hashCode в потоке Java - PullRequest
3 голосов
/ 05 июля 2019

В моем примере я пытаюсь создать таблицу ASCII из последовательности символов.Мне удалось сделать это с List строк, но не удалось с массивом символов.

Я получаю сообщение об ошибке, которое Character::hashCode не может быть разрешено в Collectors.toMap().

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)

Есть ли способ сделать это?

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);
    }
}

Ответы [ 3 ]

5 голосов
/ 05 июля 2019

.chars() дает вам IntStream, который является потоком примитива int, а не потоком символов ( больше информации ).Вот почему никакие ссылки на методы на Character не будут работать.

Чтобы достичь того, что вы ищете, вам сначала понадобится Stream<Character>:

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

Теперь у вас все еще есть проблема использования ссылки на метод для получения хеша.код.Вы не можете использовать Character::hashCode, потому что это неоднозначно относительно того, какой метод вы хотите, так как есть два возможных:

  1. Переопределение Object # hashCode,
  2. Статическийmethod int hashCode(char value)

Из этого кода видно, что оба они удовлетворяют первому аргументу toMap():

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

Чтобы решить эту проблему, вы можете использовать Object::hashCodeдля вызова нестатического метода.

2 голосов
/ 05 июля 2019

Поскольку вы используете метод collect() после CharBuffer::chars, который возвращает IntStream, единственный метод сбора, который вы можете использовать, это IntStream::collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner) принимая 3 параметра.

Если вы хотите использовать метод сбора с одним параметром, поместите IntStream::boxed перед тем, как он вернет Stream<Integer>. Тогда метод Character::hashCode становится неоднозначным, и лямбда-выражение не может быть использовано:

Чтобы избежать этого, просто используйте лучший метод mapToObj для непосредственного приведения к char без необходимости в боксе, а затем используйте Object::hashCode, унаследованное от `Object:

Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
    .mapToObj(ch -> (char) ch)
    .collect(Collectors.toMap(Object::hashCode, Function.identity()));
2 голосов
/ 05 июля 2019

Сначала вам нужно сопоставить IntStream с Stream<Character>.Но после этого вы не можете использовать ссылку на метод Character::hashCode, потому что она неоднозначна (уровень объекта и уровень класса):

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

В качестве альтернативы вы можете просто использовать Object::hashCode вместо i -> Character.hashCode(i), потому что *Класс 1009 * переопределяет метод hashCode(), используя Character.hashCode():

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

Итак, наконец, вы можете просто использовать это:

Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
        .mapToObj(i -> (char) i)
        .collect(Collectors.toMap(Object::hashCode, Function.identity()));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...