项目中经常用到stream流的sorted排序,用的时候老感觉迷迷糊糊的,于是今天看了看顺便记录一下,以后再来复习。
stream中有两个sorted方法:
(1)一个无参的方法
Stream<T> sorted();
查看它的实现类,往里进,发现它默认使用的是自然排序compareTo
(2)一个有参的方法
Stream<T> sorted(Comparator<? super T> comparator);
该方法需要传一个比较器参数
1)你可以通过实现 java.util.Comparator定制一个比较器
list.stream().sorted((o1, o2) -> {
if((o1.getAge() - o2.getAge()) < 0){
return -1
}else if ((o1.getAge() - o2.getAge()) > 0){
return 1
}else {
return 0;
}
}
上面的也可以写成下面这样,定制排序里使用自然排序
list.stream().sorted((o1, o2) -> o1.getAge().compareTo(o2.getAge()));
2)处理实现util包下的Comparator,还可以使用stream中封装的Comparator接口
stream下的Comparator有多个方法用来自定义排序规则来生成一个比较器给sorted方法。经常用的有comparing和thenComparing来配合使用,当comparing中的条件相同时按thenComparing中的条件进行排序,其他的比如comparingInt、comparingLong、comparingDouble等方法会将你的条件转成对应的类型,通过包装类下的compare进行排序
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
}
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));
}
public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
}
在这里着重记录一下comparing方法,它有两个重载方法
1、有一个入参的方法
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
入参keyExtractor是一个获取比较条件的表达式,例如对List<User>按User中的age排序,可以这样写
list.stream().sorted(Comparator.comparing(User::getAge));
//或者
list.stream().sorted(Comparator.comparing(e -> e.getAge()));
//项目中有的数据不是用实体类接收的,而是用map接收的数据库数据,可以这样写
List<Map<String, Object>> listMap = server.getAllUserInfo();
listMap.stream.sorted(Comparator.comparing(
e -> Integer.parseInt(String.valueOf(e.get("age")))
))
Objects.requireNonNull(keyExtractor);是对入参的一个判空,为空就抛出 throw new NullPointerException();异常
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
个人对这段代码的理解是,传入集合中用于比较的两个参数c1,c2,keyExtractor.apply(c1)会将c1根据传入的表达式进行获取比较字段,例如:c1 是一个User对象,
执行代码keyExtractor.apply(c1) 后会返回一个age年龄数据,两个年龄数据会通过compareTo方法进行自然排序
2、有两个入参的方法
public static <T, U> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor,
Comparator<? super U> keyComparator)
{
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (Comparator<T> & Serializable)
(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
和一个入参的方法一样,keyExtractor是获取用于比较字段的表达式;
一个入参的方法底层使用的是compareTo的自然比较器,该两个入参的方法里第二个参数是传入一个自定义的比较器,例如:
//一个简单的例子
List<User> list = server.getAllUserInfo2();
list.stream().sorted(Comparator.comparing(e -> e, (o1, o2) -> {
if((o1.getAge() - o2.getAge()) < 0){
return -1;
}else if((o1.getAge() - o2.getAge()) > 0){
return 1;
}else{
return 0;
}
}));
//用多个属性排序,和使用thenComparing方法相同
list.stream().sorted(Comparator.comparing(e -> e, (o1, o2) -> {
if((o1.getAge() - o2.getAge()) < 0){
return -1;
}else if((o1.getAge() - o2.getAge()) > 0){
return 1;
}else{
//年龄相等时,用另一个属性排序
if((o1.getUserName().hashCode() - o2.getUserName().hashCode()) < 0){
return -1;
}else if((o1.getUserName().hashCode() - o2.getUserName().hashCode()) > 0){
return 1;
}else {
return 0;
}
}
}));
最后说一下comparator接口中的reversed()方法
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
//进入reverseOrder
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
if (cmp == null)
return reverseOrder();
if (cmp instanceof ReverseComparator2)
return ((ReverseComparator2<T>)cmp).cmp;
return new ReverseComparator2<>(cmp);
}
//进入reverseOrder
public static <T> Comparator<T> reverseOrder() {
return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
}
//查看ReverseComparator.REVERSE_ORDER
private static class ReverseComparator
implements Comparator<Comparable<Object>>, Serializable {
private static final long serialVersionUID = 7207038068494060240L;
static final ReverseComparator REVERSE_ORDER
= new ReverseComparator();
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
private Object readResolve() { return Collections.reverseOrder(); }
@Override
public Comparator<Comparable<Object>> reversed() {
return Comparator.naturalOrder();
}
}
//可以看到一个compare方法里使用了c2.compareTo(c1)来进行实现倒叙,c1.compareTo(c2)是正序
好了,对于sorted的浅显分析到此为止,有错误的地方请各位大佬指出,谢谢。