182

I'm interested in sorting a list from a stream. This is the code I'm using:

list.stream()
    .sorted((o1, o2)->o1.getItem().getValue().compareTo(o2.getItem().getValue()))
    .collect(Collectors.toList());

Am I missing something? The list is not sorted afterward.

It should sort the lists according to the item with the lowest value.

for (int i = 0; i < list.size(); i++)
{
   System.out.println("list " + (i+1));
   print(list, i);
}

And the print method:

public static void print(List<List> list, int i)
{
    System.out.println(list.get(i).getItem().getValue());
}
0

10 Answers 10

250

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

Sign up to request clarification or add additional context in comments.

3 Comments

Tip: In later versions of Java, you can replace collect( Collectors.toList() ) with toList().
.toList() was added in JDK 16. Comparator.comparing() can replace the boilerplate code here.
River's answer (2nd part) shows exactly how you could do what Pwnstar said
145

Use list.sort instead:

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.

5 Comments

list.sort(Comparator.comparing(o -> o.getItem().getValue())); was new to me. Great!
Somehow, I was able to make it even more concise by removing the Comparator. qualifier.
You can even remove more boilerplate code by using method reference for Lambda: Item::getValue.
@Pwnstar This isn't processing a list of Items, 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.
@River until java upgrades the grammar to allow chained method references, you could still do it Google Guava style like this : pastebin.com/rkqxYbKM java.util.Function already implements the compose and andThen methods, you just need a static function that returns the appropriate lambda (e.g. Function, Predicate, Supplier etc..) but in theory you could do it for anything. If we also take example from C#'s Action lambdas, we could create multiple chain methods with an increasing number of chained functions as parameter (making sure the generic arguments match!).
81

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<Integer> 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<Person> 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;
    }
}

3 Comments

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 "<" to compare like Typescript does with .sort(), right?
4

Using Comparator:

List<Type> result = list
                    .stream()
                    .sorted(Comparator.comparing(Type::getValue))
                    .collect(Collectors.toList());

EDIT: JDK 16+

List<Type> result = list
                    .stream()
                    .sorted(Comparator.comparing(Type::getValue))
                    .toList();

1 Comment

jdk 16+ equivalent added
3

It seems to be working fine:

List<BigDecimal> 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<BigDecimal> 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?

1 Comment

works flawlessly!
2

Using Java 8 onward, if you want to do sorting based on some field, you can use some of the static methods inside the Comparator interface.

Here is an example of sorting a position(Long field) inside Positon object.

private List<Position> sortPosition(List<Position> positions) {
        return positions.stream()
                .sorted(Comparator.comparingLong(Position::getPosition))
                .toList();
    }

Here is the method implementation & Java Doc in the Comparator Interface

    /**
     * Accepts a function that extracts a {@code long} sort key from a type
     * {@code T}, and returns a {@code Comparator<T>} that compares by that
     * sort key.
     *
     * <p>The returned comparator is serializable if the specified function is
     * also serializable.
     *
     * @param  <T> the type of element to be compared
     * @param  keyExtractor the function used to extract the long sort key
     * @return a comparator that compares by an extracted key
     * @see #comparing(Function)
     * @throws NullPointerException if the argument is null
     * @since 1.8
     */
    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
    }

Oracle documentation link:
https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

Comments

1

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.price<item2.price?1:-1)
.forEach(item->item.show());

Comments

0

This is a simple example :

List<String> citiesName = Arrays.asList( "Delhi","Mumbai","Chennai","Banglore","Kolkata");
System.out.println("Cities : "+citiesName);
List<String> 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

Comments

0

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) {
        List<TestData> test = 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, id=1)
         *  TestData(name=saurav, id=4)
         *  TestData(name=asmin, id=2)
         *  TestData(name=Saurav, id=3)
         */

        test.sort(Comparator.comparing(TestData::getName,String::compareToIgnoreCase));
        test.forEach(data-> System.out.println(data));
        /**Sorted Output
         * TestData(name=Asmin, id=1)
         * TestData(name=asmin, id=2)
         * TestData(name=saurav, id=4)
         * TestData(name=Saurav, id=3)
         */
    }
    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{
    private String name;
    private int id;
}

1 Comment

Looks like you don't take advantage of any stream related code.
-1
Collection<Map<Item, Integer>> itemCollection = basket.values();
Iterator<Map<Item, Integer>> itemIterator =   itemCollection.stream().sorted(new TestComparator()).collect(Collectors.toList()).iterator();



package com.ie.util;

import com.ie.item.Item;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class TestComparator implements Comparator<Map<Item, Integer>> {

// comparator is used to sort the Items based on the price


    @Override
    public int compare(Map<Item, Integer> o1, Map<Item, Integer> o2) {


      //  System.out.println("*** compare method will be called *****");


        Item item1 = null;
        Item item2 = null;


        Set<Item> itemSet1 = o1.keySet();
        Iterator<Item> itemIterator1 = itemSet1.iterator();
        if(itemIterator1.hasNext()){
           item1 =   itemIterator1.next();
        }

        Set<Item> itemSet2 = o2.keySet();
        Iterator<Item> itemIterator2 = itemSet2.iterator();
        if(itemIterator2.hasNext()){
            item2 =   itemIterator2.next();
        }


        return -item1.getPrice().compareTo(item2.getPrice());


    }
}

**** this is helpful to sort the nested map objects like Map> here i sorted based on the Item object price .

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.