views:

400

answers:

2

I have a function which returns a one-sided intersection of values between two input maps:

Map<Key, Value> mergeMaps(Map aKeys<CompositeKey, Key>, 
         Map <CompositeKey, Value> aValues) {

    Map<Key, Value> myResult = Maps.newHashMap();
    for (CompositeKey myKey : aKeys.keySet()) {
        if (aValues.containsKey(myKey)) {
            myResult.put( aKeys.get(myKey), aValues.get(myKey));
        }
    }
    return myResult;
}

This is not a transitive mapping composition i.e.

T->K, K->V ===> T->V

but instead transforming

T->(K,V) ===> K->V

Is there a way in Java to make this function generic such that its signature is as follows?

Map<K, V> mergeMaps(Map aKeys<T, K>, Map <T, V> aValues)
+4  A: 

I think this signature should do what you want:

<T, K, V> Map<K, V> mergeMaps(Map<T, K> aKeys, Map<T, V> aValues)
Daff
haven't compiled yet, but IntelliJ stopped complaining :)
pbh101
Well, I've pretty much only read complaints about Java generics. This syntax irregularity gives me a reason too. I was trying:Mpa<K, V> mergeMaps<T, K, V>(Map<...>, Map<...>)Thanks much!
pbh101
Hm well you have to define the generic parameters in the beginning or in the definition of your class. I agree that the implementation of generics in Java is not perfect, too, but sometimes it is pretty neat.
Daff
I don't think this is really syntax irregularity. `mergeMaps` is not a type. / It is possible to replace `T` with wildcards here, although `TreeMap` could complain at runtime.
Tom Hawtin - tackline
@TomHawtin. Understood, but I'm fairly new at Java and my expectation, based on generic type syntax and C++, was that the generics go after the name. So, not an irregularity per se, but maybe a mismatch between syntax and my mental model based on prior, partial experience.
pbh101
+3  A: 

For a completely generic form you can have

public <T, K, V> Map<K, V> mergeMaps(Map<T, K> aKeys, Map<T, V> aValues)

If K and V are set in the class you can take them out.

For a case where you want to specify a relation between T and K, V you might want something like

public <K, V, T extends CompositeKey<K, V>> ...

possibly with some ? extends or ? super in there, but it depends a bit on the use case.

Kathy Van Stone
Thanks much! CompositeKey is actually a wrapper around an ordered collection and a hashcode() override. Here I was using the composite key essentially as the primary key for mapping a domain from one representation (in-house software) into another (3rd-party). So CompositeKey / T, in this case, is just temporary glue to get K and V aligned.
pbh101