Skip to content

Instantly share code, notes, and snippets.

@berdario
Created September 3, 2018 07:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save berdario/9914f690815fd677aee2535be4014cf3 to your computer and use it in GitHub Desktop.
Save berdario/9914f690815fd677aee2535be4014cf3 to your computer and use it in GitHub Desktop.
Java type errors can be nasty
> javac -Xlint:unchecked Transpose.java
Transpose.java:8: error: incompatible types: inference variable R has incompatible bounds
return map.entrySet().stream().collect(toMap(e -> e.getValue(), e -> new HashSet<>(Set.of(e.getKey())), (x, y) -> {x.addAll(y); return x;}));
^
equality constraints: Map<K,U>
upper bounds: HashMap<B,HashSet<A#2>>,Object
where R,A#1,T#1,K,T#2,U,B,A#2 are type-variables:
R extends Object declared in method <R,A#1>collect(Collector<? super T#1,A#1,R>)
A#1 extends Object declared in method <R,A#1>collect(Collector<? super T#1,A#1,R>)
T#1 extends Object declared in interface Stream
K extends Object declared in method <T#2,K,U>toMap(Function<? super T#2,? extends K>,Function<? super T#2,? extends U>,BinaryOperator<U>)
T#2 extends Object declared in method <T#2,K,U>toMap(Function<? super T#2,? extends K>,Function<? super T#2,? extends U>,BinaryOperator<U>)
U extends Object declared in method <T#2,K,U>toMap(Function<? super T#2,? extends K>,Function<? super T#2,? extends U>,BinaryOperator<U>)
B extends Object declared in method <A#2,B>transposeMap(HashMap<A#2,B>)
A#2 extends Object declared in method <A#2,B>transposeMap(HashMap<A#2,B>)
1 error
# This is probably an instance of this bug: https://bugs.openjdk.java.net/browse/JDK-8196762 the proper solution (adding a type witness) is described there and here: https://stackoverflow.com/questions/38089827/collector-doesnt-match-wildcard-in-result-type
# though the wildcard in `toMap` makes it quite puzzling to understand what to fill in. Casting the result of the computation is unfortunately much easier :/
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import static java.util.stream.Collectors.toMap;
class Transpose{
static <A, B> HashMap<B, HashSet<A>> transposeMap(HashMap<A, B> map){
return map.entrySet().stream().collect(toMap(e -> e.getValue(), e -> new HashSet<>(Set.of(e.getKey())), (x, y) -> {x.addAll(y); return x;}));
}
}
@gcapizzi
Copy link

gcapizzi commented Sep 3, 2018

Questo compila:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static java.util.stream.Collectors.toMap;

public class Transpose {
    static <A, B> Map<B, HashSet<A>> transposeMap(HashMap<A, B> map) {
        return map
                .entrySet()
                .stream()
                .collect(toMap(
                        Map.Entry::getValue,
                        e -> new HashSet<>(Set.of(e.getKey())),
                        (x, y) -> {
                            x.addAll(y);
                            return x;
                        }
                ));
    }

    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("one", 1);
        map.put("two", 2);
        map.put("three", 3);
        map.put("other-three", 3);

        System.out.println(transposeMap(map));
    }
}

Output:

{1=[one], 2=[two], 3=[other-three, three]}

Il problema è che toMap è un Collector<T, ?, Map<K,U>> e non un Collector<T, ?, HashMap<K,U>>. Stavi assumendo uno specifico tipo di mappa, cosa che toMap non garantisce in nessun modo. Detto questo, il messaggio di errore è terribile.

Inoltre io mi limiterei a dipendere dalle interfacce Map e Set anziché da specifiche implementazioni. La signature di trasposeMap dovrebbe essere:

static <A, B> Map<B, Set<A>> transposeMap(Map<A, B> map)

@berdario
Copy link
Author

berdario commented Sep 3, 2018

👍

As you noticed, a concrete Set implementation is still needed since as you noticed addAll is an optional operation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment