crmepham
crmepham

Reputation: 4740

Java generics - incompatible equality constraint

I am attempting to filter down a map to a sub set of itself. To achieve this I have attempted to implement the following utils method:

/**
* Reduces the size of the map. Starts from the first entry in the map.
* @param map The map.
* @param size The size to reduce the map by.
* @return The reduced size map.
*/
public static <T> Map<T, T> subList(@NonNull Map<T, T> map, int size) {
  val sub = new HashMap<T, T>();
  for (Map.Entry<T, T> entry : map.entrySet()) {
      if (sub.size() > size) {
          break;
      }

      sub.put(entry.getKey(), entry.getValue());
  }
  return sub;
}

I am then attempting to use it like this:

@Override
public Set<FileTransfer> upload(@NonNull ConnectionConfiguration target, @NonNull Map<FileTransfer, File> fileExports) {
    val batchSize = getBatchSize();
    if (fileExports.size() > batchSize) {
        fileExports = (Map<FileTransfer, File>) MapUtils.subList(fileExports, batchSize);
    }

    ...
}

But I am getting the error:

reason: Incompatible equality constraint: FileTransfer and File

I had assumed that I could pass a Map<FileTransfer, File> to the method because both types extend Object. What am I doing wrong here?

Upvotes: 1

Views: 4813

Answers (1)

Sweeper
Sweeper

Reputation: 271185

subList accepts a Map<T, T>. Note that the two generic parameters are the same, so you can only pass things like Map<Integer, Integer>, Map<String, String> or Map<FileTransfer, FileTransfer>. You are trying to pass Map<FileTransfer, File>, which has different generic parameters.

You should rewrite the subList method so that it accepts a Map<K, V>. Note now that the generic parameters are different, so maps with different key type and value type can be passed in.

public static <K, V> Map<K, V> subList(@NonNull Map<K, V> map, int size) {
  val sub = new HashMap<K, V>();
  for (Map.Entry<K, V> entry : map.entrySet()) {
      if (sub.size() > size) {
          break;
      }

      sub.put(entry.getKey(), entry.getValue());
  }
  return sub;
}

Now you don't even need the cast at the caller's side:

fileExports = MapUtils.subList(fileExports, batchSize);

Upvotes: 3

Related Questions