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 OverflowWhat 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
)
for comparing in the level two, you can proceed like that : for the object
public class ArticleChannel {
private Long id;
private String label;
private ArticleBusiness business;
}
public class ArticleBusiness {
private Long id;
private String name;
}
articleChannelList.sort(Comparator.comparing((ArticleChannel articleChannel) -> **articleChannel.getBusiness().getName()**).thenComparing(ArticleChannel::getLabel));
This is the part of the code that causes an error
Sell::getClient.name
Your can create a reference to a (static or non-static) method of an arbitrary object of a particular type. A reference to the getClient method of any object of Sell type looks like this :
Sell::getClient
But method references are not objects and don't have members to access. With this code you are trying to access a member variable of the reference (and can't)
Sell::getClient.name
Also, method references are not classes so you can't get another method reference from them. You couldn't do something like that if you tried :
Sell::getClient::getName
Correct syntax for your particular case was provided by @mlk :
x -> x.getClient().nameSell::getClientName(doesn't have to be a static method)
In order to access the nested property and sort in reversed order, I am doing as:
Comparator<Sell> comparator = Comparator.comparing(h -> h.getAudit().getCreatedTs());
sells.sort(comparator.reversed());
You can use lambda expression in Comparator.comparing instead of method reference
List<Foo> res = foos.stream()
.sorted(Comparator.comparing(fo->fo.getSelect().getFooKey()))
.collect(Collectors.toList());
For just sorting you don't even need stream
foos.sort(Comparator.comparing(fo->fo.getSelect().getFooKey()));
Remove the map. The map changes the object in the stream. Update the sorted statement as
.sorted(Comparator.comparing(f -> f.getSelect().getFoosKey()))
The following will sort the foos and the bars for each foo, but since the peek operation is mutating f, this will have unexpected behaviour if parallelism is involved.
List<Foo> foosSorted = foos.stream()
.sorted(Comparator.comparingInt(o -> o.sort))
.peek(f -> {
f.bars = f.bars.stream().sorted(Comparator.comparingInt(o -> o.sort)).collect(Collectors.toList());
})
.collect(Collectors.toList());
What I suggest is for you to add a constructor of Foo taking sort and bars and use map instead of peek. This way, we are not mutating any Foo object, so this can be run in parallel without trouble.
List<Foo> foosSorted = foos.stream()
.sorted(Comparator.comparingInt(o -> o.sort))
.map(f -> {
return new Foo(f.sort, f.bars.stream().sorted(Comparator.comparingInt(o -> o.sort)).collect(Collectors.toList()));
})
.collect(Collectors.toList());
with:
class Foo {
public int sort;
public List<Bar> bars;
public Foo(int sort) {
this.sort = sort;
}
public Foo(int sort, List<Bar> bars) {
this.sort = sort;
this.bars = new ArrayList<>(bars);
}
}
List<Foo> foosSort = foos.stream()
.sorted((o1, o2) -> (o1.sort - o2.sort))
.map(f -> {
List<Bar> bars = f.bars.stream()
.sorted((o1, o2) -> (o1.sort- o2.sort))
.collect(Collectors.toList());
f.bars = bars;
return f;
})
.collect(Collectors.toList());
Probably the type inference isn't strong enough. This worked for me:
return cars.stream()
.sorted(Comparator.comparing(car -> ((Car) car).getDriver().getGender())
.thenComparingInt(car -> ((Car) car).getDriver().getAge()))
.collect(Collectors.toList());
The answer by @Kartik works. But if you want to avoid casting, you have two more options:
Option 1:
Comparator<Car> com1 = Comparator.comparing(car -> car.getDriver().getGender());
Comparator<Car> com2 = Comparator.comparing(car -> car.getDriver().getAge());
then:
cars.stream().sorted(com1.thenComparing(com2)).collect(Collectors.toList());
Option 2:
Let the compiler know you are comparing Cars:
cars.stream().sorted(Comparator.comparing((Car car) -> car.getDriver().getGender())
.thenComparing(car -> car.getDriver().getAge()))
.collect(Collectors.toList());
EDIT: Actually, you have even more options. Per @Andreas' comment, you can pass the type by Comparator.<Car, String>comparing or you can just write your own comparing function which will look like:
sorted((car1, car2) -> {/*function body that returns -1, 0, 1 */}
Also, if you have a List<Car> you want to sort, you can directly use sort() method:
cars.sort(com1.thenComparing(com2));
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
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.
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.
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());
}
});