一、需求
实际项目中经常存在对集合某个或多个属性进行排序,例如根据姓名排序,根据金额排序;或者多个字段排序,例如姓名首字母升序+金额降序两个字段排序等等。
但是有时候姓名或金额会为空,之前我们排序的时候需要拿出这些属性做判空处理,然后再排序,不然会报错。今天这个方法不用自己处理空字段判读了,并且值为空也参与排序。
二、了解Comparator.nullsFirst和Comparator.nullsLast
1、Comparator.nullsFirst
- 空元素被认为小于非空元素。
- 当两个元素都是空的时候,那么它们被认为是相等的。
- 当两个元素都是非空的时候,指定的比较器决定了顺序。
- 如果指定的比较器是空的,那么返回的比较器认为所有非空的元素是相等的。
2、Comparator.nullsLast
- 空元素被认为是大于非空元素的。
- 当两个元素都是空的时候,那么它们被认为是相等的。
- 当两个元素都是非空的时候,指定的比较器决定了顺序。
- 如果指定的比较器是空的,那么返回的比较器认为所有非空的元素是相等的。
三、了解Comparator.naturalOrder和Comparator.reverseOrder
1、Comparator.naturalOrder
- 自然排序,升序
2、Comparator.reverseOrder
- 扭转自然排序,降序
四、定义实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @Author:
* @Description
* @Date: 下午2:09 2024/1/23
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SortEmpty implements Serializable {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 奖学金
*/
private BigDecimal amount;
}
五、测试排序
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author:
* @Description
* @Date: 下午2:10 2024/1/23
*/
@Slf4j
public class SortTest {
/**
* 单个字段排序
*/
public static void oneFiledSort() {
//mock 数据
List<SortEmpty> list = getData();
//根据奖学金降序排序,并且奖学金为空的放到最后
List<SortEmpty> amountSort = list.stream().sorted(Comparator.comparing(SortEmpty::getAmount, Comparator.nullsFirst(BigDecimal::compareTo)).reversed()).collect(Collectors.toList());
log.info("************amountSort根据奖学金降序排序,并且奖学金为空的放到最后,排序后结果如下");
amountSort.forEach(e -> log.info("" + e));
//根据姓名升序排序,并且名字为空的放到最后
List<SortEmpty> nameSort = list.stream().sorted(Comparator.comparing(SortEmpty::getName, Comparator.nullsLast(String::compareTo))).collect(Collectors.toList());
log.info("************根据姓名升序排序,并且名字为空的放到最后,排序后结果如下");
nameSort.forEach(e -> log.info("" + e));
}
/**
* 多个字段排序
* 根据姓名首字母升序,奖学金降序
*/
public static void manyFiledSort() {
//mock 数据
List<SortEmpty> list = getData();
// 多字段排序规则
Comparator<SortEmpty> comparator5 = Comparator.comparing(SortEmpty::getName, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(SortEmpty::getAmount, Comparator.nullsLast(Comparator.reverseOrder()));
List<SortEmpty> orderList = list.parallelStream().sorted(comparator5).collect(Collectors.toList());
log.info("************多个字段排序,根据姓名首字母升序,奖学金降序结果如下");
orderList.forEach(e -> log.info("" + e));
}
/**
* mock 数据
*
* @param
*/
public static List<SortEmpty> getData() {
List<SortEmpty> list = new ArrayList<>();
list.add(new SortEmpty("abc", 11, null));
list.add(new SortEmpty("gbc", 112, BigDecimal.valueOf(50)));
list.add(new SortEmpty(null, 13, BigDecimal.valueOf(1000)));
list.add(new SortEmpty("lbc", 119, null));
list.add(new SortEmpty("lbc", 119, BigDecimal.valueOf(300)));
list.add(new SortEmpty("lbc", 119, BigDecimal.valueOf(600)));
return list;
}
/**
* 测试
*
* @param args
*/
public static void main(String[] args) {
oneFiledSort();
manyFiledSort();
}
}