无法解析Java流中的方法Character :: hashCode

时间:2019-07-05 13:01:40

标签: java lambda java-8 java-stream

在我的示例中,我尝试从一系列字符创建一个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 个答案:

答案 0 :(得分:5)

.chars()给您一个IntStream,它是原始int的流,而不是字符流(more info)。这就是为什么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. 静态方法int hashCode(char value)

您可以从这段代码中看到,它们都满足toMap()的第一个参数:

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

要解决此问题,可以将Object::hashCode用于非静态方法调用。

答案 1 :(得分:2)

首先,您需要将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),因为Character类使用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()));

答案 2 :(得分:2)

由于在CharBuffer::chars之后使用方法collect()返回了IntStream,所以唯一可以使用的收集方法是IntStream::collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)接受3个参数。

如果要使用单参数收集方法,请将IntStream::boxed放在其前面以返回Stream<Integer>。然后方法Character::hashCode变得模棱两可,无法使用lambda表达式:

要避免这种情况,只需使用更好的方法mapToObj直接转换为char,而无需装箱,然后使用从`Object继承的Object::hashCode

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