1

I need to represent each entry of a Map as type T and I don't know how to do that.

Here is the definition of entryset:

public Set<Map.Entry<K,V>> entrySet()

so I need something like this:

Map<?,?> -> Set<T>

This will compile:

  public static <T, E> void Each(Map i, IEacher<T, E> m, Asyncc.IEachCallback<E> f) {
    NeoEach.Each(Integer.MAX_VALUE, i.<T>entrySet(), m, f);
  }

but I get a warning:

Unchecked assignment: 'java.util.Set' to 'java.lang.Iterable'. Reason: 'i' has raw type, so result of entrySet is erased

but what's weird is that this won't compile:

  public static <T, E> void Each(Map<Object,Object> i, IEacher<T, E> m, Asyncc.IEachCallback<E> f) {
    NeoEach.Each(Integer.MAX_VALUE, i.<T>entrySet(), m, f);
  }

using Map i compiles, but Map<Object,Object> i won't it says:

expected:

i:java.lang.Iterable<T>

actual:

i.<T>entrySet()  (java...java.lang.Object,java.lang.Object>>)
Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • Can you explain *why* you don't want to use `values()`? – shmosel Feb 22 '19 at 22:39
  • 2
    Also, what's with the C# naming style? – shmosel Feb 22 '19 at 22:39
  • I need to use entryset because I need key-value pairs not just the value. For static variables sometimes I use capitals, I might change it, besides the point here. – Alexander Mills Feb 22 '19 at 22:42
  • Then you'll need some sort of transformation function. – shmosel Feb 22 '19 at 23:08
  • @AlexanderMills *"I might change it"*? Well, you should definitely follow the Java Naming Conventions. Variable names *always* start with lowercase. – MC Emperor Feb 22 '19 at 23:54
  • @MCEmperor instead of variable I think to be more precise you mean method names. According to the Java Naming Conventions local variables are distinct from method/field names. – Alexander Mills Feb 23 '19 at 00:21
  • @AlexanderMills Variable names (both local variables and instance variables) are written in camelCase, as well as method names. – MC Emperor Feb 23 '19 at 00:22

2 Answers2

2

Your NeoEach.Each method accepts Iterable<T> but you are trying to force it to consume entry set of Map<Object,T>. This seems to me somewhat ambiguous. What should the method do with Map.Entry better than with T itself? If you utilize map key in Each method, pass entry set there instead of Iterable or pass Iterable of entries:

static <T, E> void Each(int limit, Iterable<Map.Entry<Object,T>> i, Asyncc.IEacher<T, E> m, Asyncc.IEachCallback<E> f) {

In extreme case, some reflection or proxy-based hacks could probably be done to fake Map.Entry to look like T but I believe that's not what both you and me actually want.

EDIT: And what compiles to you does not mean it will run. Declaring raw Map just masks the problem, doesn't solve it. The attempt of treating rawtype Map.Entry as value type will fail on ClassCastException sometimes in the future.

Tomáš Záluský
  • 10,735
  • 2
  • 36
  • 64
1

You can leverage Java Streams API to transform each Entry to T, but you must define how you would do that. You could then pass a transformation function to do the transformation to T.

public static <K, V, T> Set<T> transform(Map<K, V> map, Function<Map.Entry<K, V>, T> transformationFunction) {
    return map.entrySet().stream()
        .map(transformationFunction)
        .collect(Collectors.toSet());
}

The reason why you cannot use Map<Object, Object> is that generics are invariant.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
  • map.entrySet() should return Set – Alexander Mills Feb 23 '19 at 21:11
  • @AlexanderMills "`map.entrySet()` should return `Set`"? That can't be done, since the `Map` interface requires the `entrySet` method to return an `Entry`; this cannot be magically changed to `Set` ... or you need to implement your own map, adding a method which returns such a set. – MC Emperor Feb 23 '19 at 22:22