0

i have a code like these

@Data
public class person{
  String firstName;
  String lastName;
  int orderNum;
}

List<person> personList = new ArrayList<person>();

i am trying to sort object and trying get map based on order number.

i wrote a logic these this and didn't work for me

Map<String, String> xza = personList.stream()
  .sorted(Comparator.comparing(refDataDto::getOrderNum))
  .collect(Collectors.toList())
  .stream()
  .collect(Collectors.toMap(refDataDto::getFirstName, refDataDto::getastName));
Chaosfire
  • 4,818
  • 4
  • 8
  • 23
Hanuman
  • 3
  • 2
  • 3
    [`Collectors.toMap`](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/util/stream/Collectors.html#toMap(java.util.function.Function,java.util.function.Function,java.util.function.BinaryOperator)): “*There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned.*” This includes that you can not assume the map to maintain insertion order. Use `Collectors.toMap(refDataDto::getFirstName, refDataDto::getastName, …, LinkedHashMap::new)` instead. Besides that, there’s no sense in inserting `.collect(Collectors.toList()).stream()` in the stream – Holger May 25 '23 at 10:50

2 Answers2

3

You are sorting a list according to the order number, collecting it into a list, creating a stream from the list and then collecting the stream to an unsorted map. Maps don't, by default, preserve the order in which the key-value pairs are inserted.

What you need is a LinkedHashMap, but since there is not a ready made collector helper for it, you have to set it up manually (and you don't need to collect the data to a list in between):

Also, since you are working on streams containing Person objects, the lambdas need to refer to the Person class, not refDataDto.

Map<String, String> xza = personList.stream()
    .sorted(Comparator.comparing(Person::getOrderNum))
    .collect(Collectors.toMap(
            Person::getFirstName,
            Person::getLastName,
            (v1, v2) -> {
                throw new IllegalStateException("Key conflict");
            },
            LinkedHashMap::new));
Torben
  • 3,805
  • 26
  • 31
2

Collectors.toMap(key,value), will by default create a HashMap, which is unordered. You have to use a LinkedHashMap to order it in the same order of elements that were inserted in.

Also, .collect(Collectors.toList()).stream() is not useful. sorted would have given you a sorted stream, and on top of it, you are converting it to a list and then back to stream, so it is useless.

So, try Collectors.toMap overloaded method with 4 parameters instead of 2: 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-

Map<String, String> xza = personList.stream()
  .sorted(Comparator.comparing(Person::getOrderNum))
  .collect(Collectors.toMap(
    Person::getFirstName,
    Person::getastName,
    (u, v) -> {
      throw new IllegalStateException(String.format("Duplicate key %s", u));
    },
    LinkedHashMap::new));
Ishan
  • 400
  • 2
  • 8
  • 1
    You have copied the Java 8 version of the merge function which has a bug. `u` is *not* the key. Besides that, I consider `String.format("Duplicate key %s", u)` a horrible way to express exactly the same as `"Duplicate key " + u`. The latter is easier to read *and* way more efficient. – Holger May 26 '23 at 09:13