java使用stream对日期排序
Posted prince05
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java使用stream对日期排序相关的知识,希望对你有一定的参考价值。
简介
Stream对对象中的某个日期属性进行排序 对日期属性进行排序,并指定日期为空时的策略 排序策略
nullsFirst():为空时排在最前面 nullsLast():为空时排在最后面 Comparator.naturalOrder 和
Comparator.reverseOrder 对对象中的多个属性进行排序 字符串日期排序 对字段进行排序,考虑空值的其他写法
简介
本文主要讲解Stream对日期字段进行排序时的写法,以及当日期字段为null时的排序策略。或者对多个属性进行排序时的案例
Stream对对象中的某个日期属性进行排序
Student对象
import lombok.Data;
import java.util.Date;
@Data
public class Student
private String name;
private int age;
private Date birthday;
public Student(String name, int age,Date birthday)
this.name = name;
this.age = age;
this.birthday = birthday;
List<Student> list = new ArrayList<>();
Student s1 = new Student("a", 11, new Date(2020, 1, 1));
Student s2 = new Student("b", 12, new Date(2020, 1, 2));
Student s3 = new Student("c", 13, new Date(2020, 1, 3));
list.add(s1);
list.add(s2);
list.add(s3);
list = list.stream().sorted(Comparator.comparing(Student::getBirthday)).collect(Collectors.toList());
注意:当birthday日期属性为空时,再使用Comparator.comparing排序会报空指针异常,此时需要指定策略,即当日期为空时排在最前面或排在最后面。
对日期属性进行排序,并指定日期为空时的策略
List<Student> list = new ArrayList<>();
Student s1 = new Student("a", 11, new Date(2020, 1, 1));
Student s2 = new Student("b", 12, new Date(2020, 1, 2));
Student s3 = new Student("c", 13, null);
list.add(s1);
list.add(s2);
list.add(s3);
list = list.stream().sorted(Comparator.comparing(Student::getBirthday,Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Collectors.toList());
System.out.println(list);
执行结果:
[Student(name=c, age=13, birthday=null), Student(name=a, age=11, birthday=Sun Feb 01 00:00:00 CST 3920), Student(name=b, age=12, birthday=Mon Feb 02 00:00:00 CST 3920)
排序策略
nullsFirst():为空时排在最前面
此方法返回比较器,其是空型比较,并认为空值小于非空。null首先通过以下逻辑进行操作:
1.null元素被认为小于non-null(即值是null的小于非空的)。
2.当两个元素都为空时,则认为它们相等。
3.当两个元素都不为空时,指定的Comparator确定顺序。
4.如果指定的比较器为null,则返回的比较器将所有非null元素视为相等。
5.如果指定的比较器可序列化,则返回的比较器可序列化。
nullsLast():为空时排在最后面
方法返回比较器,其是空型比较,并认为比非空更大空值。null首先通过以下逻辑进行操作:
1.null元素被认为大于非null。
2.当两个元素都为空时,则认为它们相等。
3.当两个元素都不为空时,指定的Comparator确定顺序。
4.如果指定的比较器为null,则返回的比较器将所有非null元素视为相等。
5.如果指定的比较器可序列化,则返回的比较器可序列化。
Comparator.naturalOrder 和 Comparator.reverseOrder
很多时候我们会面临这样的场景,那就是排序逻辑不变,一会儿根据升序排序,一会根据降序排序,这个时候如果我们的Comparable 中的排序逻辑可以满足上面的排序,就是排序类型(升序还是降序)是不满足的,这个时候我们就可以配合Comparator,来改变原来默认的排序类型(其实就是升序)
nullsFirst与naturalOrder的结合使用
如下示例:当字段为空时排在最前面,剩下的升序排列
List<Student> list = new ArrayList<>();
Student s1 = new Student("a", 11, new Date(2020, 1, 1));
Student s2 = new Student("b", 12, new Date(2020, 1, 2));
Student s3 = new Student("c", 13, null);
list.add(s1);
list.add(s2);
list.add(s3);
list = list.stream().sorted(Comparator.comparing(Student::getBirthday,Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Collectors.toList());
Comparator.nullsFirst(Comparator.naturalOrder()))
空值放前面,剩下的升序排序
Comparator.nullsFirst(Comparator.reverseOrder()))
空值放前面,剩下的倒叙排序
Comparator.nullsLast(Comparator.naturalOrder()))
空值放最后,剩下的升序排序
Comparator.nullsLast(Comparator.reverseOrder()))
空值放最后,剩下的倒叙排序
对对象中的多个属性进行排序
先根据生日排序,再根据年龄排序
List<Student> list = new ArrayList<>();
Student s1 = new Student("a", 11, new Date(2020, 1, 1));
Student s2 = new Student("b", 12, new Date(2020, 1, 2));
Student s3 = new Student("c", 13, null);
Student s4 = new Student("d", 13, null);
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list = list.stream().sorted(Comparator.comparing(Student::getBirthday,Comparator.nullsFirst(Comparator.naturalOrder())).thenComparing(Student::getAge)).collect(Collectors.toList());
System.out.println(list);
字符串日期排序
写法一
List<String> maxUpdateTime = updateTimeList.stream().sorted(Comparator.comparing(s -> DateUtil.convertStringToDate(s.toString(),"yyyy-MM-dd HH:mm:ss").getTime()).reversed()).collect(Collectors.toList());
写法二:
List<String> maxUpdateTime = updateTimeList.stream().sorted(new Comparator<String>()
@Override
public int compare(String o1, String o2)
try
Date d1 = DateUtil.convertStringToDate(o1, "yyyy-MM-dd HH:mm:ss");
Date d2 = DateUtil.convertStringToDate(o2, "yyyy-MM-dd HH:mm:ss");
return d2.compareTo(d1);
catch (Exception e)
e.printStackTrace();
return 0;
).collect(Collectors.toList());
对字段进行排序,考虑空值的其他写法
* 请注意,根据单属性name进行排序,若需要将name为null的对象也参与排序,则需要:
* .sorted(Comparator.comparing(User::getName, Comparator.nullsLast((o1,o2)->o1.compareTo(o2))))
* 使用方法引用优化(注意name的类型是String)即为:
* .sorted(Comparator.comparing(User::getName, Comparator.nullsLast(String::compareTo)))
*/
voList = voList.stream().sorted(Comparator.comparing(User::getUserName,Comparator.nullsLast(String::compareTo))) .collect(Collectors.toList());
使用Java8 Stream API对Map按键或值进行排序
一、什么是Java 8 Stream
使用Java 8 Streams,我们可以按键和按值对映射进行排序。下面是它的工作原理:
- 将Map或List等集合类对象转换为Stream对象
- 使用Streams的
sorted()
方法对其进行排序
- 最终将其返回为
LinkedHashMap
(可以保留排序顺序)
sorted()
方法以Comparator
作为参数,从而可以按任何类型的值对Map进行排序。如果对Comparator不熟悉,可以看本号前几天的文章,有一篇文章专门介绍了使用Comparator对List进行排序。
二、学习一下HashMap的merge()函数
在学习Map排序之前,有必要讲一下HashMap的merge()函数,该函数应用场景就是当Key重复的时候,如何处理Map的元素值。这个函数有三个参数:
- 参数一:向map里面put的键
- 参数二:向map里面put的值
- 参数三:如果键发生重复,如何处理值。可以是一个函数,也可以写成lambda表达式。
String k = "key";
HashMap<String, Integer> map = new HashMap<String, Integer>() {{
put(k, 1);
}};
map.merge(k, 2, (oldVal, newVal) -> oldVal + newVal);
看上面一段代码,我们首先创建了一个HashMap,并往里面放入了一个键值为k:1的元素。当我们调用merge函数,往map里面放入k:2键值对的时候,k键发生重复,就执行后面的lambda表达式。表达式的含义是:返回旧值oldVal加上新值newVal(1+2),现在map里面只有一项元素那就是k:3。
其实lambda表达式很简单:表示匿名函数,箭头左侧是参数,箭头右侧是函数体。函数的参数类型和返回值,由代码上下文来确定。
三、按Map的键排序
下面一个例子使用Java 8 Stream按Map的键进行排序:
// 创建一个Map,并填入数据
Map<String, Integer> codes = new HashMap<>();
codes.put("United States", 1);
codes.put("Germany", 49);
codes.put("France", 33);
codes.put("China", 86);
codes.put("Pakistan", 92);
// 按照Map的键进行排序
Map<String, Integer> sortedMap = codes.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(
Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldVal, newVal) -> oldVal,
LinkedHashMap::new
)
);
// 将排序后的Map打印
sortedMap.entrySet().forEach(System.out::println);
看上文中第二段代码:
- 首先使用entrySet().stream() 将Map类型转换为Stream流类型。
- 然后使用sorted方法排序,排序的依据是Map.Entry.comparingByKey(),也就是按照Map的键排序
- 最后用collect方法将Stream流转成LinkedHashMap。 其他参数都好说,重点看第三个参数,就是一个merge规则的lambda表达式,与merge方法的第三个参数的用法一致。由于本例中没有重复的key,所以新值旧值随便返回一个即可。
上面的程序将在控制台上打印以下内容,键(国家/地区名称)以自然字母顺序排序:
China=86
France=33
Germany=49
Pakistan=92
United States=1
请注意使用LinkedHashMap
来存储排序的结果以保持顺序。默认情况下,Collectors.toMap()
返回HashMap
。HashMap
不能保证元素的顺序。
如果希望按照键进行逆向排序,加入下图中红色部分代码即可。
四、按Map的值排序
当然,您也可以使用Stream API按其值对Map进行排序:
Map<String, Integer> sortedMap2 = codes.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldVal, newVal) -> oldVal,
LinkedHashMap::new));
sortedMap2.entrySet().forEach(System.out::println);
这是显示Map按值排序的输出:
United States=1
France=33
Germany=49
China=86
Pakistan=92
五、使用TreeMap按键排序
大家可能都知道TreeMap内的元素是有顺序的,所以利用TreeMap排序也是可取的一种方法。您需要做的就是创建一个TreeMap
对象,并将数据从HashMap
put到TreeMap
中,非常简单:
// 将 `HashMap` 转为 `TreeMap`
Map<String, Integer> sorted = new TreeMap<>(codes);
这是输出:
China=86
France=33
Germany=49
Pakistan=92
United States=1
如上所示,键(国家/地区名称)以自然字母顺序排序。
期待您的关注
以上是关于java使用stream对日期排序的主要内容,如果未能解决你的问题,请参考以下文章
利用Java8 stream对Map排序
Java8使用Stream流实现List列表的查询统计排序分组
java8完全解读二
java 怎么对日期列进行排序
Java 8 Map & Stream - 按值 desc 和组排序
使用stream()按元素属性的Java排序列表[重复]