Search code examples
javalistcollectionshashmap

Sort the values in a map of type Map<String, List<String>>


I have a map of type

Map<String, List<String>>

I want to sort the elements in each List. No need to sort the map, but, need to sort each list of the map i.e. sort the values independently. Hope I am clear.

I tried using keySet and entrySet elements on a Map, but, getting the following error:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at java.util.ComparableTimSort.binarySort(ComparableTimSort.java:232)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:176)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
    at java.util.Arrays.sort(Arrays.java:472)
    at java.util.Collections.sort(Collections.java:155)

Looks like I am having null in the List I am trying to sort.

Is there any way to sort a List having null in it?


Solution

  • Since list you want to sort can contain null and you can't call compareTo on null (since it doesn't have any methods nor fields) you will need to provide your own Comparator which will handle null and use it with sorting method.

    For instance if you would like to place null at end of ascending order you will need to implement rules like:

    • null null - don't swap, there is no point (return 0)
    • null "someString" - swap, null is bigger and should be placed after "someString" (return 1)
    • "someString" null - don't swap, first argument ("someString") is smaller than null (return -1)
    • "string1" "string2" - return default result of comparing both non-null values

    and your Comparator can look like

    Comparator<String> myComparator = new Comparator<String>() {
        @Override
        public int compare(String s1, String s2) {
            if (s1==null && s2==null) return 0;//swapping has no point here
            if (s1==null) return  1;
            if (s2==null) return -1;
            return s1.compareTo(s2);
        }
    };
    

    Now you can use it

    for (List<String> list : yourMap.values()) {
        Collections.sort(list, myComparator);
    }
    

    Java 8 update

    Since Java 8 Comparator provides methods which can wrap other comparator and create another one which will place nulls at start or end of our collection. This methods are:

    • Comparator.nullsFirst(Comparator)
    • Comparator.nullsLast(Comparator)

    Also sort(Comparator) method was added to List interface which means we don't need to call explicitly Collections.sort(list,comparator).

    So your code can look like:

    for (List<String> list : yourMap.values()) {
        list.sort(Comparator.nullsLast(Comparator.naturalOrder()));
    }
    

    But nothing stops you from using other comparator instead of Comparator.naturalOrder() like one stored in String.CASE_INSENSITIVE_ORDER which now can also be created with String::compareToIgnoreCase method reference.