4

I initially sorted a list by an attribute of an object (let's say a User by its firstName) with:

Collections.sort(userList, (u1, u2) -> (u1.getFirstName()).compareTo(u2.getFirstName()));

which I was able to replace with:

Collections.sort(userList, Comparator.comparing(User::getFirstName));

But now the User has a list of Roles with a roleName each and I want to sort the list by the roleName of the Role of the User. I came up with this:

Collections.sort(userList, (u1, u2) -> (u1.getUserRoles().get(0).getRoleName()).compareTo(u2.getUserRoles().get(0).getRoleName()));

which seems to work fine.

In the IDE, there is now the message: Can be replaced with Comparator.comparing ..., but I do not know how to exactly do this. Is this even possible? Something like this don't work:

Collections.sort(userList, Comparator.comparing(User::getUserRoles.get(0).getRoleName());

How can I sort this with Comparator.comparing?

And after sorting by roleName, how is it possible to sort by the firstName as a second property?

8
  • 1
    What IDE are you using? When you see a hint like that in IntelliJ, you can simply hit alt + enter and it will do it for you. Commented Jan 18, 2018 at 13:26
  • 1
    Don't feel you have to take the IDE's suggestion just because it's being offered. And don't be too surprised if, after you've changed your code as the IDE suggested (or, better yet, made the IDE do the change), the IDE then suggests changing it back to what you originally had! Commented Jan 18, 2018 at 13:28
  • 1
    As law of Demeter says you shall not call user.getUserRoles.get(0).getRoleName() but rather implement a getUserRoleName (or getUsersFirstRoleName) on the User. You can then use Comparator.comparing(...).thenComparing(...) chain. Given that user might not have a role at all you also might consider looking into Comparator.nullsLast / Comparator.nullsFirst. Commented Jan 18, 2018 at 13:57
  • @Michal: I wasn't aware of that, but it sounds logic. What if the user can have more than one roles? Commented Jan 18, 2018 at 14:00
  • @Michal: Could you please provide an example of avoiding the law of Demeter? Commented Jan 18, 2018 at 14:26

1 Answer 1

6

You can't use a method reference in this case, but you can use a lambda expression:

Collections.sort(userList, Comparator.comparing(u -> u.getUserRoles().get(0).getRoleName()));

To sort by two properties:

Collections.sort(userList, Comparator.comparing((Function<User,String>)u -> u.getUserRoles().get(0).getRoleName())
                                     .thenComparing(User::getFirstName));

or

Collections.sort(userList, Comparator.comparing((User u) -> u.getUserRoles().get(0).getRoleName())
                                     .thenComparing(User::getFirstName));
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. I had to add (): Collections.sort(userList, Comparator.comparing(u -> u.getUserRoles().get(0).getRoleName())); Now I'm struggling with thenComparing, because I would then like to sort the list by the first name. Any ideas how to solve this?
@Eran: The sorting by two properties does not work. It gives me Cannot resolve method 'getUserRoles()'.
@manu It seems the compiler has some problem with type inference. I tried a similar sorting (of different elements), and casting the lambda expression to the correct type seemed to help. See edit
This works. I am now sorting first by the userRoles's roleName, then by the lastName and then by the firstName with Collections.sort(userList, Comparator.comparing((Function<User, String>) u -> u.getUserRoles().get(0).getRoleName()).thenComparing(User::getLastName).thenComparing(User::getFirstName)); Thank you very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.