Skip to content

Display a LinkedHashMap list

I have a problem displaying the data right. I have an sql query that returns the following data:

| count (long) | country  (string)|
---------------| ------------------
| 6            | null             |
| 3            | spain            |
| 6            | italy            |

And I have the following method:

private Map<String, Long> countryCount (List<CountryCount> summary) {
    Map<String, Long> result = new HashMap<>();
    summary.forEach(sum -> {
      var country= sum.getCountry(); 
      if (country == null) {
        country= "unknown";
      }
      var count = result.get(country);
      if (count == null) {
        count = 0L;
      }
      result.put(country, count + sum.getCount());
    });
    return result.entrySet().stream().sorted(Map.Entry.comparingByKey())
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
  }

In my method I want to return an object like {"unknown" : 5, "spain" : 3, "italy" : 6} but instead I get {"unknown" : 15}

Answer

Perhaps this simpler code.

Map < String, Long > map =
        listOfCountryCount
                .stream()
                .collect(
                        Collectors.toMap(
                                countryCount -> Objects.isNull( countryCount.getCountry() ) ? "unknown" : countryCount.getCountry() ,
                                countryCount -> Objects.isNull( countryCount.getCount() ) ? Long.valueOf( 0 ) : countryCount.getCount()
                        )
                );

If you want a sorted map, pass that map to constructor of a SortedMap or NavigableMap implementation.

NavigableMap< String , Long > mapNav = new TreeMap<>( map ) ;

Full example code.

package work.basil.demo;

import java.util.*;
import java.util.stream.Collectors;

class Ideone
{
    public static void main ( String[] args ) throws java.lang.Exception
    {
        List < CountryCount > listOfCountryCount = List.of(
                new CountryCount( "Peru" , 17L ) ,
                new CountryCount( "Xanadu" , 128L ) ,
                new CountryCount( null , 42L ) ,
                new CountryCount( "Andorra" , null )
        );

        Map < String, Long > map =
                listOfCountryCount
                        .stream()
                        .collect(
                                Collectors.toMap(
                                        countryCount -> Objects.isNull( countryCount.getCountry() ) ? "unknown" : countryCount.getCountry() ,
                                        countryCount -> Objects.isNull( countryCount.getCount() ) ? Long.valueOf( 0 ) : countryCount.getCount()
                                )
                        );
        NavigableMap < String, Long > mapNav = new TreeMap <>( map );  // Keys are maintained in sorted order.

        System.out.println( "listOfCountryCount = " + listOfCountryCount );
        System.out.println( "map = " + map );
        System.out.println( "mapNav = " + mapNav );
    }
}

final class CountryCount
{
    private final String country;
    private final Long count;

    CountryCount ( String country , Long count )
    {
        this.country = country;
        this.count = count;
    }

    public String getCountry ( ) { return country; }

    public Long getCount ( ) { return count; }

    @Override
    public boolean equals ( Object obj )
    {
        if ( obj == this ) return true;
        if ( obj == null || obj.getClass() != this.getClass() ) return false;
        var that = ( CountryCount ) obj;
        return Objects.equals( this.country , that.country ) &&
                Objects.equals( this.count , that.count );
    }

    @Override
    public int hashCode ( )
    {
        return Objects.hash( country , count );
    }

    @Override
    public String toString ( )
    {
        return "CountryCount[" +
                "country=" + country + ", " +
                "count=" + count + ']';
    }
}

When run.

listOfCountryCount = [CountryCount[country=Peru, count=17], CountryCount[country=Xanadu, count=128], CountryCount[country=null, count=42], CountryCount[country=Andorra, count=null]]
map = {Andorra=0, Xanadu=128, Peru=17, unknown=42}
mapNav = {Andorra=0, Peru=17, Xanadu=128, unknown=42}

If you are not sure about your data being distinct, let’s add a third argument to that Collectors.toMap call. We pass a lambda function to be called in case of duplicate keys. In our case here, we go with a policy of first occurrence wins.

Map < String, Long > map =
        listOfCountryCount
                .stream()
                .collect(
                        Collectors.toMap(
                                countryCount -> Objects.isNull( countryCount.getCountry() ) ? "unknown" : countryCount.getCountry() ,
                                countryCount -> Objects.isNull( countryCount.getCount() ) ? Long.valueOf( 0 ) : countryCount.getCount() ,
                                ( existing , replacement ) -> existing   // In case of duplicate key conflict, first one wins.
                        )
                );

We can shorten this code further. Rather than create a TreeMap separately, we can pass a constructor method reference as a fourth argument to our Collectors.toMap: TreeMap :: new. And we change the declaration of the returned map from Map to NavigableMap.

NavigableMap < String, Long > map =
        listOfCountryCount
                .stream()
                .collect(
                        Collectors.toMap(
                                countryCount -> Objects.isNull( countryCount.getCountry() ) ? "unknown" : countryCount.getCountry() ,
                                countryCount -> Objects.isNull( countryCount.getCount() ) ? Long.valueOf( 0 ) : countryCount.getCount() ,
                                ( existing , replacement ) -> existing ,  // In case of duplicate key conflict, first one wins.
                                TreeMap :: new 
                        )
                );

See this code run live at IdeOne.com.

listOfCountryCount = [CountryCount[country=Peru, count=17], CountryCount[country=Xanadu, count=128], CountryCount[country=null, count=42], CountryCount[country=Andorra, count=null]]
map = {Andorra=0, Peru=17, Xanadu=128, unknown=42}