In my example, I try to create an ASCII table from a sequence of characters. I managed to do it with a List
of strings but failed with an array of chars.
I get an error that Character::hashCode
cannot be resolved in 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)
Is there a way to do it?
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);
}
}
.chars()
is giving you an IntStream
, which is a stream of primitive int
, and not a stream of characters ( more info ). This is why no method references on Character
will work.
To achieve what you're looking for, you'll need a Stream<Character>
first:
Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters)
.chars()
.mapToObj(e -> (char) e)
.collect(Collectors.toMap(e -> e.hashCode(), Function.identity()));
Now, you still have the issue of using a method reference for getting the hash code. You can't use Character::hashCode
because it's ambiguous as to which method you want, as there are two that are possible:
int hashCode(char value)
You can see from this code, that both satisfy the first argument to toMap()
:
Function<Character, Integer> f1 = e -> Character.hashCode(e);
Function<Character, Integer> f2 = e -> e.hashCode();
To resolve this, you can use Object::hashCode
for the non-static method call.
First you need to map the IntStream
to a Stream<Character>
. But after that you can not use the Method reference Character::hashCode
because it is ambiguous (object level and class level):
Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
.mapToObj(i -> (char) i)
.collect(Collectors.toMap(i -> Character.hashCode(i), Function.identity()));
Alternatively you can just use Object::hashCode
instead of i -> Character.hashCode(i)
because the Character
class overrides it's hashCode()
method using Character.hashCode()
:
public final class Character ... {
@Override
public int hashCode() {
return Character.hashCode(value);
}
}
So finally you can just use this:
Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
.mapToObj(i -> (char) i)
.collect(Collectors.toMap(Object::hashCode, Function.identity()));
Since you are using the method collect()
after CharBuffer::chars
which returns IntStream
, the only collecting method you can use is IntStream::collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)
taking 3 parameters.
If you wish to use one-parameter collecting method, place IntStream::boxed
before it to return Stream<Integer>
. Then the method Character::hashCode
becomes ambiguous and the lambda expression cannot be used:
To avoid this, simply use a better method mapToObj
to cast to char
directly without need of boxing and then use Object::hashCode
inherited from the `Object:
Map<Integer, Character> asciiMap2 = CharBuffer.wrap(letters).chars()
.mapToObj(ch -> (char) ch)
.collect(Collectors.toMap(Object::hashCode, Function.identity()));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.