- Java Stream Sort — Comparator with 2 or more Criteria for Objects
- Sorting a list with stream.sorted() in Java
- 9 Answers 9
- sorting Integer using streamAPI
- Java Streams Comparators with Examples
- Java Streams Comparators with Examples
- Sorting with Comparator Natural Order and Reverse Order
- Outputs
- NaturalOrder Test Output
- ReverseOrder Test Output
- Java Streams Comparator.comparing() Examples
- GitHub Project
Java Stream Sort — Comparator with 2 or more Criteria for Objects
Issue: I am trying to check if I can sort the list (ArrayList of data type Object), using 2 or more criteria’s. Please note I am aware of using Comparator with thenComparing feature. I wish to check if there is a way to sort with 2 or more criteria w/o having to use a custom data type where I can easily use Comparator feature. For 1 criteria sorting, the below code works. In this case if I do the below, the IntelliJ IDE immediately gives a error saying — ‘Cannot resolve method ‘get(int)’ for o.get(3)
.sorted(Comparator.comparing(o -> o.get(3).toString()).thenComparing(. )
I have also referred to many threads in this forum sample — Link1 Link2 Code (This works well for single criteria)
List> listOutput = new ArrayList<>(); . . listOutput = listOutput .stream() .sorted(Comparator.comparing(o -> o.get(3).toString())) .collect(Collectors.toList());
Added (Details of Object) (Note) String dataType — exchange, broker,segment, coCode LocalDate dataType — tradeDate LocalTime dataType — tradeTime double dataType — sellPrice, buyPrice
List lineOutput = new ArrayList<>(); lineOutput.add(exchange); lineOutput.add(broker); lineOutput.add(segment); lineOutput.add(tradeDate); // Entry Date lineOutput.add(tradeTime); // Entry Time lineOutput.add(coCode); lineOutput.add(sellPrice - buyPrice); // Profit / Loss listOutput.add(lineOutput); // Add line to Output
Sorting a list with stream.sorted() in Java
Am I missing something? The list is not sorted afterward. It should sort the lists according to the item with the lowest value.
public static void print(List list, int i)
9 Answers 9
This is not like Collections.sort() where the parameter reference gets sorted. In this case you just get a sorted stream that you need to collect and assign to another variable eventually:
List result = list.stream().sorted((o1, o2)->o1.getItem().getValue(). compareTo(o2.getItem().getValue())). collect(Collectors.toList());
You’ve just missed to assign the result
list.sort((o1, o2) -> o1.getItem().getValue().compareTo(o2.getItem().getValue()));
and make it more succinct using Comparator.comparing :
list.sort(Comparator.comparing(o -> o.getItem().getValue()));
After either of these, list itself will be sorted.
Your issue is that list.stream.sorted returns the sorted data, it doesn’t sort in place as you’re expecting.
@Pwnstar This isn’t processing a list of Item s, it’s processing a list of objects with an Item field. I’m not aware of a way in Java to do a nested method reference, e.g. MyObject::getItem::getValue . Lmk if there is such way, but otherwise the above boilerplate is required.
Java 8 provides different utility api methods to help us sort the streams better.
If your list is a list of Integers(or Double, Long, String etc.,) then you can simply sort the list with default comparators provided by java.
List integerList = Arrays.asList(1, 4, 3, 4, 5);
Creating comparator on fly:
integerList.stream().sorted((i1, i2) -> i1.compareTo(i2)).forEach(System.out::println);
With default comparator provided by java 8 when no argument passed to sorted():
integerList.stream().sorted().forEach(System.out::println); //Natural order
If you want to sort the same list in reverse order:
integerList.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println); // Reverse Order
If your list is a list of user defined objects, then:
List personList = Arrays.asList(new Person(1000, "First", 25, 30000), new Person(2000, "Second", 30, 45000), new Person(3000, "Third", 35, 25000));
Creating comparator on fly:
personList.stream().sorted((p1, p2) -> ((Long)p1.getPersonId()).compareTo(p2.getPersonId())) .forEach(person -> System.out.println(person.getName()));
Using Comparator.comparingLong() method(We have comparingDouble(), comparingInt() methods too):
personList.stream().sorted(Comparator.comparingLong(Person::getPersonId)).forEach(person -> System.out.println(person.getName()));
Using Comparator.comparing() method(Generic method which compares based on the getter method provided):
personList.stream().sorted(Comparator.comparing(Person::getPersonId)).forEach(person -> System.out.println(person.getName()));
We can do chaining too using thenComparing() method:
personList.stream().sorted(Comparator.comparing(Person::getPersonId).thenComparing(Person::getAge)).forEach(person -> System.out.println(person.getName())); //Sorting by person id and then by age.
Person class
public class Person < private long personId; private String name; private int age; private double salary; public long getPersonId() < return personId; >public void setPersonId(long personId) < this.personId = personId; >public Person(long personId, String name, int age, double salary) < this.personId = personId; this.name = name; this.age = age; this.salary = salary; >public String getName() < return name; >public void setName(String name) < this.name = name; >public int getAge() < return age; >public void setAge(int age) < this.age = age; >public double getSalary() < return salary; >public void setSalary(double salary) < this.salary = salary; >>
I feel like this answer is way too detailed for the question, and yet doesn’t address the question at all. Consider using this answer in a self-answered Q/A instead.
I also feel that this is the best and correct answer. using Comparator.comparing* is the way better and more JDK8 oriented approach
@River welcome to Java, it’s terrible. It would just make way too much sense to use «>» and »
It seems to be working fine:
List list = Arrays.asList(new BigDecimal("24.455"), new BigDecimal("23.455"), new BigDecimal("28.455"), new BigDecimal("20.455")); System.out.println("Unsorted list: " + list); final List sortedList = list.stream().sorted((o1, o2) -> o1.compareTo(o2)).collect(Collectors.toList()); System.out.println("Sorted list: " + sortedList);
Example Input/Output
Unsorted list: [24.455, 23.455, 28.455, 20.455] Sorted list: [20.455, 23.455, 24.455, 28.455]
Are you sure you are not verifying list instead of sortedList [in above example] i.e. you are storing the result of stream() in a new List object and verifying that object?
sorting Integer using streamAPI
arr.stream() .sorted((item1,item2)-> Integer.compare(item1.price, item2.price)) .forEach(item-> item.show()); //asc System.out.println("--------------------"); //desc arr.stream() .sorted((item1,item2)-> item1.priceitem.show());
List result = list .stream() .sorted(Comparator.comparing(Type::getValue)) .collect(Collectors.toList());
List result = list .stream() .sorted(Comparator.comparing(Type::getValue)) .toList();
List citiesName = Arrays.asList( "Delhi","Mumbai","Chennai","Banglore","Kolkata"); System.out.println("Cities : "+citiesName); List sortedByName = citiesName.stream() .sorted((s1,s2)->s2.compareTo(s1)) .collect(Collectors.toList()); System.out.println("Sorted by Name : "+ sortedByName);
It may be possible that your IDE is not getting the jdk 1.8 or upper version to compile the code.
Set the Java version 1.8 for Your_Project > properties > Project Facets > Java version 1.8
This might help for people ending up here searching how to sort list alphabetically.
import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class SortService < public static void main(String[] args) < Listtest = new ArrayList<>(); test.add(prepareTestData("Asmin",1)); test.add(prepareTestData("saurav",4)); test.add(prepareTestData("asmin",2)); test.add(prepareTestData("Saurav",3)); test.forEach(data-> System.out.println(data)); /** Output * TestData(name=Asmin, * TestData(name=saurav, * TestData(name=asmin, * TestData(name=Saurav, */ test.sort(Comparator.comparing(TestData::getName,String::compareToIgnoreCase)); test.forEach(data-> System.out.println(data)); /**Sorted Output * TestData(name=Asmin, * TestData(name=asmin, * TestData(name=saurav, * TestData(name=Saurav, */ > private static TestData prepareTestData(String name, int id) < TestData testData= new TestData(); testData.setId(id); testData.setName(name); return testData; >> @Getter @Setter @ToString class TestData
Java Streams Comparators with Examples
Hi all, in this article, we will learn Java Streams Comparators like Comparator.comparing(), Comparator.naturalOrder(), Comparator.reverseOrder(), etc. The Comparator Interface provides us comparison and sorting options that we can use with Java Streams. Let’s start to do some examples and learn these tricks.
Java Streams Comparators with Examples
We will start with Sorting with Comparator examples then we will see Comparator.comparing() examples.
Sorting with Comparator Natural Order and Reverse Order
Let’s start with some sorting examples. We can use the Comparator interface’s naturalOrder() and reverseOrder() method to sort the elements of a stream in Ascending and Descending order.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class StreamSorted < Listnumbers = new ArrayList<>(); @BeforeEach public void setup(TestInfo testInfo) < System.out.println("Test name: " + testInfo.getDisplayName()); numbers.add(5); numbers.add(8); numbers.add(3); numbers.add(7); numbers.add(2); numbers.add(6); numbers.add(1); numbers.add(10); numbers.add(9); numbers.add(4); >@AfterEach public void tearDown() < numbers.clear(); System.out.println(""); >/** * Natural sort is Ascending Sort */ @Test @Order(1) public void streamNaturalOrderSortTest() < numbers.stream() .peek(number ->System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes. .filter(number -> number % 2 == 1) //Filter the odd numbers .sorted(Comparator.naturalOrder()) //Natural order of sorting. (Ascending Sort) .limit(4) //After 4th element stop the stream. Process first 4 element. .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes. .map(number -> number * 2) //Transform the number to number*2 .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results. > /** * Reverse sort is Descending Sort */ @Test @Order(2) public void streamReverseOrderSortTest() < numbers.stream() .peek(number ->System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes. .filter(number -> number % 2 == 1) //Filter the odd numbers .sorted(Comparator.reverseOrder()) //Reverse order of sorting. (Descending Sort) .limit(4) //After 4th element stop the stream. Process first 4 element. .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes. .map(number -> number * 2) //Transform the number to number*2 .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results. > >
Outputs
NaturalOrder Test Output
The test code:
- Prints the debugging texts with peek().
- Filters the odd numbers.
- Then, sorts all elements with Natural Order which is Ascending Order.
- With limit(4), when the 4th odd number is filtered which is “1”, it does not continue to do operations for other elements.
- Prints the debugging texts with peek(),
- Transform the elements to (elements*2).
- Prints the results with forEach().
ReverseOrder Test Output
The test code:
- Prints the debugging texts with peek().
- Filters the odd numbers.
- Then, sorts all elements with Reverse Order which is Descending Order.
- With limit(4), when the 4th odd number is filtered which is “1”, it does not continue to do operations for other elements.
- Prints the debugging texts with peek(),
- Transform the elements to (elements*2).
- Prints the results with forEach().
Java Streams Comparator.comparing() Examples
The Comparator Interface provides us several comparisons and sorting options as seen below screenshot. We have already learned the reverseOrder() and naturalOrder() sorting with the Comparator Interface.
Now, let’s do some examples with Comparator.comparing(). We have a Footballer class which contains the footballer’s name, team, and age. We can do comparisons on each element of the footballers by using comparator.comparing() method. We can find the footballer who has minimum age or the footballer who has maximum age etc.
Footballer Class
I used Lombok library’s Getter, Setter, and AllArgConstructor annotations to construct the Footballer class.
@Setter @Getter @AllArgsConstructor public class Footballer < String name; String team; int age; @Override public String toString() < return "Footballerpublic class ComparatorExamples < Listfootballers = new ArrayList<>(); @BeforeEach public void setup() < Footballer ronaldo = new Footballer("Ronaldo", "Manchester United", 36); Footballer messi = new Footballer("Messi", "Paris Saint German", 33); Footballer ozil = new Footballer("Ozil", "Fenerbahce", 32); footballers.add(ronaldo); footballers.add(messi); footballers.add(ozil); >/** * Comparator.comparing example */ @Test public void comparatorComparingTest() < OptionalyoungestFootballer = footballers.stream() .min(Comparator.comparing(Footballer::getAge)); Optional eldestFootballer = footballers.stream() .max(Comparator.comparing(Footballer::getAge)); youngestFootballer.ifPresent(footballer -> System.out.println("Youngest Footballer: " + footballer)); eldestFootballer.ifPresent(footballer -> System.out.println("Eldest Footballer: " + footballer)); > >
As you see below, by using Comparator.comparing() inside Stream’s min() and max() methods, we can easily find the youngest and eldest football players. Min and max method’s return type is Optional that’s why I wrapped the Footballer class with Optional. I will explain Optional class details in another article. Simply, it will help us not to get null pointer exceptions in Java.
GitHub Project
In this article, I shared with you the most common usages of the Comparator Interface in Java. I hope you enjoyed reading it. See you in the next articles.
Thanks for reading,
Onur Baskirt
Onur Baskirt is a Software Engineering Leader with international experience in world-class companies. Now, he is a Software Engineering Lead at Emirates Airlines in Dubai.