What you want is Comparator#comparing:

userMap.values().stream()
    .sorted(Comparator.comparing(User::getName, UserNameComparator.INSTANCE))
    .collect(Collectors.toList());

For the second part of your question, you would just use

Comparator.comparing(
    u->u.getProfile().getUsername(), 
    UserNameComparator.INSTANCE
)
Answer from Misha on Stack Overflow
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › sorting a stream by multiple fields in java
Sorting a Stream by Multiple Fields in Java - Group by sort example
March 10, 2022 - //first name comparator Comparator<Employee> compareByFirstName = Comparator.comparing( Employee::getFirstName ); //last name comparator Comparator<Employee> compareByLastName = Comparator.comparing( Employee::getLastName ); //Compare by first name and then last name (multiple fields) Comparator<Employee> compareByFullName = compareByFirstName.thenComparing(compareByLastName); //Using Comparator - pseudo code list.stream().sorted( comparator ).collect(); Given below is an example of using thenComparing() to create Comparator which is capable of sorting the employees’ list by their first name
🌐
GeeksforGeeks
geeksforgeeks.org › java › stream-sorted-in-java
Stream sorted() in Java - GeeksforGeeks
January 23, 2026 - import java.util.*; class Point { Integer x, y; Point(Integer x, Integer y) { this.x = x; this.y = y; } public String toString() { return x + ", " + y; } } class GFG { public static void main(String[] args) { List<Point> list = Arrays.asList( new Point(10, 20), new Point(5, 10), new Point(1, 100), new Point(50, 2000) ); list.stream() .sorted((p1, p2) -> p1.x.compareTo(p2.x)) .forEach(System.out::println); } } ... Sorting is stable; the original list is not modified.
🌐
Shirinpars
shirinpars.com › uhrze › article.php
java stream sort by nested property
In this article, You're going to learn how to work with nested list with java 8 streams . . Java Stream distinct() Method. This way, you can create multiple groups by just changing the grouping criterion. Luckily there's a solution to this problem using the method flatMap.
🌐
Baeldung
baeldung.com › home › java › java – powerful comparison with lambdas
Java – Powerful Comparison with Lambdas | Baeldung
January 8, 2024 - We can also sort a collection using Java 8’s Stream sorted() API. We can sort the stream using natural ordering, as well as ordering provided by a Comparator.
Find elsewhere
🌐
Baeldung
baeldung.com › home › java › java collections › sort collection of objects by multiple fields in java
Sort Collection of Objects by Multiple Fields in Java | Baeldung
January 8, 2024 - In this article, we learned different approaches for comparing on multiple fields when sorting collections of objects.
🌐
C# Corner
c-sharpcorner.com › article › how-can-i-sort-a-list-of-objects-by-property-in-java
How Can I Sort a List of Objects by Property in Java?
October 3, 2025 - When we say sorting objects by property, it means arranging them in a particular order (ascending or descending) based on a specific field inside the object. For example: ... In Java, we can achieve this using Comparable, Comparator, Lambdas, ...
🌐
Java67
java67.com › 2021 › 09 › java-comparator-multiple-fields-example.html
How to sort a List or Stream by Multiple Fields in Java? Comparator comparing() + thenComparing Example | Java67
Here is our complete Java program to sort a list of objects by multiple fields. Even though you can implement this logic using Comparable, it's better to use Comparator because Comparable is used to define natural ordering.
🌐
Medium
medium.com › @AlexanderObregon › javas-stream-sorted-method-explained-52b9b25e9f84
Java’s Stream.sorted() Method Explained | Medium
December 26, 2024 - This variation sorts the stream elements based on their natural order, defined by the Comparable interface.
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › stream › Stream.html
Stream (Java Platform SE 8 )
1 month ago - Returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
🌐
Mkyong
mkyong.com › home › java8 › java 8 – how to sort list with stream.sorted()
Java 8 - How to sort list with stream.sorted() - Mkyong.com
March 8, 2019 - /*List<User> sortedList = users.stream() .sorted((o1, o2) -> o1.getName().compareTo(o2.getName())) .collect(Collectors.toList());*/ List<User> sortedList = users.stream() .sorted(Comparator.comparing(User::getName)) .collect(Collectors.toList()); ... Founder of Mkyong.com, passionate Java and open-source technologies. If you enjoy my tutorials, consider making a donation to these charities. ... I always like your examples. All complicated issues solved by you in very simple examples.
Top answer
1 of 1
7

There are others concerns with your code, without going into the sort:

Getter returning mutable data

getCompetitors() returns directly the internal list stored by your factory object. This is generally not a good idea: it means a client of Factory can modify its internal structure, which defeats the OOP principle. It would be preferable instead to have a method sortCompetitors(), that would sort the list, without leaking it:

private List<Competitor> competitors;

public void sortCompetitors() {
    Collections.sort(competitors);
}

and remove completely the method getCompetitors().

Comparator, Comparable

class Factory implements Comparator<Factory>

will be problematic in the future. It seems what you want would be to use Comparable instead, but even this isn't a good idea in this case. There is a difference between the two: a class is Comparable when it can compare itself to another class of the same type, which is what you are doing here: one Factory is comparing itself to another object. On the other hand, a Comparator is a class that is comparing 2 objects of the same type (it does not compare this with another object).

Therefore:

  • It is wrong to have your class implement Comparator: it means the class is doing too much: it knows itself and it is also responsible for comparing any 2 factories (See also on Stack Overflow). More often than not, there are several ways to compare 2 objects given a context: sort by name or sort by price...
  • It is also probably wrong to have your class implements Comparable, but for a different reason. As said before, Comparable is used to compare this with another object of the same type. But this interface is closely related to equals and hashCode: any class that is Comparable should provide a consistent equals method (It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))). In your case, it would imply that two factories are equal when their price is equal, which is probably not what you want.

The solution here is not to make your class implements Comparator and define a custom comparator class, like

class FactoryPriceComparator implements Comparator<Factory>

Using built-in methods

Your compare methods are currently doing:

@Override
public int compare(Factory o1, Factory o2) {
    if (o1.getPrice() < o2.getPrice())
        return -1;
    if (o1.getPrice() > o2.getPrice())
        return 1;
    return 0;
}

This can be written more concisely with the built-in Double.compare (since Java 7), which also properly handles NaN, -0.0 and 0.0, contrary to your current code:

public int compare(Factory o1, Factory o2) {
    return Double.compare(o1.getPrice(), o2.getPrice());
}

Your whole comparator would then become:

public class FactoryPriceComparator implements Comparator<Factory> {
    @Override
    public int compare(Factory o1, Factory o2) {
        return Double.compare(o1.getPrice(), o2.getPrice());
    }
}

Note that you would have the same implementation for the Comparator<Competitor>.

Java 8 API

If you're using Java 8, you can even get rid of the above FactoryPriceComparator and use the built-in Comparator.comparingDouble(keyExtractor), which creates a comparator comparing the double values returned by the key extractor. In this case, the key extractor could be the method reference Factory::getPrice (resp. Competitor::getPrice). So you could simply have:

Collections.sort(factoriesList, Comparator.comparingDouble(Factory::getPrice));

or even

factoriesList.sort(Comparator.comparingDouble(Factory::getPrice));

Finally:

What I am doing require to sort collection of factories and loop through all factories and sort collection of their competitors

This is actually the proper way of doing it: when you sort a Factory, you cannot sort the inner competitors at the same time, because different objects are being compared.

🌐
Medium
kevalpadsumbiya.medium.com › custom-sorting-of-list-of-objects-using-java-stream-b24d93e6e71e
Custom sorting of list of objects using Java Stream | Medium
February 13, 2023 - package com.custom.sorting.service; import com.custom.sorting.model.Seller; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class CustomSorting { public static void main(String[] args) { List<Seller> sellerList = getSampleListOfSellers(); //seller name comparator Comparator<Seller> sellerNameComparator = Comparator.comparing(Seller::getSellerName); //seller location distance comparator Comparator<Seller> sellerLocationDistanceComparator = Comparator.comparing(Seller::getDistanceFromMyLocation); //seller state comparator Co
Top answer
1 of 3
8

A simple Comparator that first compares the name and then the lastName will work with the Collections.sort method.

From the JavaDoc:

Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.


So, here is the example of the Comparator that compares on two properties:

Collections.sort(rowItems, new Comparator<SearchRowItem>() {
    @Override
    public int compare(final SearchRowItem o1, final SearchRowItem o2) {
        int compare = o1.getName().compareToIgnoreCase(o2.getName());
        if (compare != 0) {
            return compare;
        }
        return o1.getLastName().compareToIgnoreCase(o2.getLastName());
    }
});

However, there are other alternatives. Java 8 introduced streams where sorting integrates nicely. Together with the new methods Comparator.comparing and the thenCompare a nice stream can be created like this.

final List<SearchRowItem> collect = rowItems.stream()
        .sorted(
                Comparator.comparing(SearchRowItem::getName, String::compareToIgnoreCase)
                          .thenComparing(SearchRowItem::getLastName, String::compareToIgnoreCase))
        .collect(Collectors.toList());

Note that the latter does not sort the original List but creates a new sorted list.

2 of 3
3

If getName() returns 0 it means that both objects have the same name - only then should you use getLastName():

Collections.sort(rowItems, new Comparator() {

    @Override
    public int compare(Object o1, Object o2) {
        SearchRowItem p1 = (SearchRowItem) o1;
        SearchRowItem p2 = (SearchRowItem) o2;
        int nameComp =  p1.getName().compareToIgnoreCase(p2.getName());
        if (nameComp != 0) {
            return nameComp;
        }
        return p1.getLastName().compareToIgnoreCase(p2.getLastName());
    }
});

EDIT:
The answer above follows the OP's style. However, if possible, you should use generics to clean up the code:

Collections.sort(rowItems, new Comparator<SearchRowItem>() {

    @Override
    public int compare(SearchRowItem p1, SearchRowItem p2) {
        int nameComp =  p1.getName().compareToIgnoreCase(p2.getName());
        if (nameComp != 0) {
            return nameComp;
        }
        return p1.getLastName().compareToIgnoreCase(p2.getLastName());
    }
});
🌐
Stack Abuse
stackabuse.com › java-8-how-to-sort-list-with-stream-sorted
Java 8 – How to Sort List with Stream.sorted()
July 21, 2021 - In this tutorial guide, we'll cover everything you need to know about the Stream.sorted() API. We'll sort integers, strings and custom objects in ascending and descending order as well as define custom comparators in Java.