20

I have a list that I need to custom sort and then convert to a map with its Id vs. name map.

Here is my code:

Map<Long, String> map = new LinkedHashMap<>();
list.stream().sorted(Comparator.comparing(Building::getName)).forEach(b-> map.put(b.getId(), b.getName()));

I think this will do the job but I wonder if I can avoid creating LinkedHashMap here and use fancy functional programming to do the job in one line.

Eran
  • 387,369
  • 54
  • 702
  • 768
Mohammad Adnan
  • 6,527
  • 6
  • 29
  • 47
  • 2
    Besides that using `collect` is preferable you should beware that `sorted(…).forEach(…)` is wrong (despite it sometimes works). What you really mean is `sorted(…).forEachOrdered(…)`… – Holger Apr 20 '15 at 09:12
  • Use `toMap()` of `java.util.stream.Collectors` – mushfek0001 Apr 18 '15 at 18:24

1 Answers1

47

You have Collectors.toMap for that purpose :

Map<Long, String> map = 
    list.stream()
        .sorted(Comparator.comparing(Building::getName))
        .collect(Collectors.toMap(Building::getId,Building::getName));

If you want to force the Map implementation that will be instantiated, use this :

Map<Long, String> map = 
    list.stream()
        .sorted(Comparator.comparing(Building::getName))
        .collect(Collectors.toMap(Building::getId,
                                  Building::getName,
                                  (v1,v2)->v1,
                                  LinkedHashMap::new));
Eran
  • 387,369
  • 54
  • 702
  • 768
  • 3
    toMap will convert this in HashMap right? which doesn't guarantee sorting? – Mohammad Adnan Apr 18 '15 at 18:26
  • 4
    @MohdAdnan The returned implementation is not guaranteed. You can force the implementation you wish by using the [4 parameter version](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-java.util.function.Supplier-). With the last parameter - the Supplier - you can specify which Map implementation will be instantiated. – Eran Apr 18 '15 at 18:32
  • 3
    Please note that, this implementation will omit the second entry for duplicate key. – Masudul Apr 18 '15 at 18:43
  • 1
    @Masud I was assuming there are no duplicates in this use case. If there are, a groupingBy Collector may be more appropriate. – Eran Apr 18 '15 at 18:46
  • 1
    given that the map implementation determines sorting, is there any need for the `.sorted(Comparator.comparing(Building::getName))` line? – Emanuel George Hategan Dec 04 '15 at 10:38
  • @Emanuel that depends on the chosen Map implementation. In this example, LinkedHashMap is used, which keeps track of the insertion order of the keys. Therefore sorted is needed if you wish the keys to by inserted in the order imposed by the Comparator. – Eran Dec 04 '15 at 11:25
  • @Eran got it, sorting only makes sense if the map implementation iterates entries based on insertion order. For other map implementations sorting before insertion is irrelevant. – Emanuel George Hategan Jan 06 '16 at 09:45