Jerome P Mrozak Jerome P Mrozak - 3 months ago 10
Java Question

My use of Java generics with Collections.sort and Map won't compile

I'm processing user data, grouping users by some external phrase and ordering on (external phrase, user name). I'm doing this in Java and am trying to make the phrase object and user object generic. My target is Java 6.

Although everything is generic, in this example the external phrase is a String and the user is of type JUser. My code refuses to compile, having issues with Collections.sort() and Map.put().

JUser:

import java.util.*;
public class JUser implements Comparable<JUser> {
private String name = "";

public JUser(String name) {
setName(name);
}

public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
public int compareTo(JUser other) { return this.getName().compareTo(other.getName()); }
}


JLabeled:

public class JLabeled<K, V> {
private K label = null;
private V value = null;

public JLabeled(K label, V value) {
this.label = label;
this.value = value;
}

public K getLabel() { return this.label; }
public V getValue() { return this.value; }
}


JCollated:

import java.util.*;

public class JCollated<K, V> {
private Map<K, List<V>> keyedList = new HashMap<K, List<V>>();

public <V> List<JLabeled<K, V>> getAll() {
List<JLabeled<K, V>> labeled = new ArrayList<JLabeled<K, V>>();
List<K> keys = new ArrayList<K>(keyedList.keySet());
java.util.Collections.sort(keys);
for(K key : keys) {
List<V> values = keyedList.get(key);
java.util.Collections.sort(values);
for(V value : values) labeled.add(new JLabeled<K, V>(key, value));
}
return labeled;
}

public <K, V> void createKey(K key) {
if(keyedList.get(key) == null) keyedList.put(key, new ArrayList<V>());
}
}


JTest:

import java.util.*;
public class JTest {

public static void main( String[] args ) {
System.out.println("hello from JTest\n\n");
testStuff();
System.out.println("\n\ngoodbye from JTest\n");
}

public static void testStuff() {
JCollated<String, List<JUser>> myCollated = new JCollated<String, List<JUser>>();
List<JLabeled<String, JUser>> labeledList = myCollated.getAll();

for(JLabeled<String, JUser> labeled : labeledList) {
JUser user = labeled.getValue();
System.out.println("Key: " + labeled.getLabel() + ", name: " + user.getName());
}
}
}


When compiling javac JTest.java the compiler says:

.\JCollated.java:9: cannot find symbol
symbol : method sort(java.util.List<K>)
location: class java.util.Collections
java.util.Collections.sort(keys);
^
.\JCollated.java:11: incompatible types
found : java.util.List<V>
required: java.util.List<V>
List<V> values = keyedList.get(key);
^
.\JCollated.java:12: cannot find symbol
symbol : method sort(java.util.List<V>)
location: class java.util.Collections
java.util.Collections.sort(values);
^
.\JCollated.java:19: put(K,java.util.List<V>) in java.util.Map<K,java.util.List<V>> cannot be applied to (K,java.util.ArrayList<V>)
if(keyedList.get(key) == null) keyedList.put(key, new ArrayList<V>());
^
4 errors


I am grimly amused by the statement that List and List are not compatible. Can someone tell me what is really wanted here?

Thanks,
Jerome.

Answer

You have several issues in your code:

  1. If you want to be able to sort a List using Collections.sort(List), the elements of the collection must be Comparable
  2. Don't set any bounded type parameter in your method's definition otherwise it won't be understood by the compiler as the same types as those defined in your class's definition even if you use K or V in both places.

The code should then be:

public class JCollated<K extends Comparable<? super K>, V extends Comparable<? super V>> {
    ...

    public List<JLabeled<K, V>> getAll() {
        ...
    }

    public void createKey(K key) {
        ...
    }
}

Response Update:

In the method testStuff(), you don't define properly your object of type JCollated, it should rather be:

JCollated<String, JUser> myCollated = new JCollated<String, JUser>();
Comments