【JAVA基础】List、Map排序总结

0 前言 对List(主要指ArrayList)和Map(主要指HashMap)的排序是最常见的业务场景,因此,有必要对其进行系统地梳理和学习,本文总结了常用的排序方法。
1 List排序 1.1 基本数据类型的排序
a.数值型数据

// 此处包括本文涉及的所有import,后面的案例不再重复 import org.junit.Test; import java.text.Collator; import java.util.*; import java.util.stream.Collectors; @Test public void intTest() { List intList = new ArrayList<>(); intList.add(1); intList.add(5); intList.add(4); System.out.println("原始:" + intList); // 倒置 Collections.reverse(intList); System.out.println("倒置:" + intList); // 排序 intList.sort(Comparator.naturalOrder()); System.out.println("正序:" + intList); intList.sort(Comparator.reverseOrder()); System.out.println("倒序:" + intList); }

输出结果:
原始:[1, 5, 4] 倒置:[4, 5, 1] 正序:[1, 4, 5] 倒序:[5, 4, 1]

b.字符型数据
英文字符的排序按照字母表顺序,具体操作与数值型排序类似,不再赘述。此处,特别介绍下中文字符的排序,常见的方式是以首个汉字的拼音首字母顺序排。
@Test public void strTest() { List strList = new ArrayList<>(); strList.add("武汉"); strList.add("北京"); strList.add("上海"); System.out.println("原始:" + strList); // 排序 Collator instance = Collator.getInstance(Locale.CHINA); // 据说遇到生僻字时会有bug,暂未涉及不深究 strList.sort(instance); System.out.println("正序:" + strList); strList.sort(instance.reversed()); System.out.println("倒序:" + strList); }

输出结果:
原始:[武汉, 北京, 上海] 正序:[北京, 上海, 武汉] 倒序:[武汉, 上海, 北京]

1.2 JavaBean类型的排序
自定义一个JavaBean:
public class A implements Comparable { private String name; private Integer order; public A(String name, Integer order) { this.name = name; this.order = order; }public String getName() { return name; }public void setName(String name) { this.name = name; }public Integer getOrder() { return order; }public void setOrder(Integer order) { this.order = order; }@Override public String toString() { return "order=" + order+ " name=" + name; }@Override public int compareTo(A a) { return this.order.compareTo(a.getOrder()); } }

对于自定义的JavaBean类型,有以下几种常见的排序方法:
@Test public void objectTest() { List listA = new ArrayList<>(); listA.add(new A("a2", 1)); listA.add(new A("a3", 3)); listA.add(new A("a3", 2)); listA.add(new A("a1", 3)); System.out.println("原始:" + listA); // 1.基于A的order升序排序 //方法一:list中的对象A实现Comparable接口,直接sort listA.sort(Comparator.naturalOrder()); System.out.println("1.基于order升序——方法1:" + listA); //方法二:若A没有实现Comparable接口,使用Comparator.comparing listA.sort(Comparator.comparing(A::getOrder)); System.out.println("1.基于order升序——方法2:" + listA); // 2.基于A的order及name的升序排序 List result1 = listA.stream().sorted(Comparator.comparing(A::getOrder).thenComparing(A::getName)).collect(Collectors.toList()); System.out.println("2.基于A的order及name的升序排序——方法2扩展:" + result1); // 3.基于A的order及name的降序排序 List result2 = listA.stream().sorted(Comparator.comparing(A::getOrder).thenComparing(A::getName).reversed()).collect(Collectors.toList()); System.out.println("3.基于A的order及name的降序排序——方法2扩展:" + result2); // 4.基于A的order升序以及name的降序排序 Comparator comparatorName = (a1, a2) -> -a1.getName().compareTo(a2.getName()); listA.sort(Comparator.comparing(A::getOrder).thenComparing(comparatorName)); System.out.println("4.基于A的order升序以及name的降序排序——方法2扩展:" + listA); //方法三:自定义排序 Comparator comparator = (a1, a2) -> { if (a1.getOrder().equals(a2.getOrder())) { return -a1.getName().compareTo(a2.getName()); } return a1.getOrder().compareTo(a2.getOrder()); }; listA.sort(comparator); System.out.println("4.基于order升序及name降序——方法3:" + listA); }

运行结果:
原始:[order=1 name=a2, order=3 name=a3, order=2 name=a3, order=3 name=a1] 1.基于order升序——方法1:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1] 1.基于order升序——方法2:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1] 2.基于A的order及name的升序排序——方法2扩展:[order=1 name=a2, order=2 name=a3, order=3 name=a1, order=3 name=a3] 3.基于A的order及name的降序排序——方法2扩展:[order=3 name=a3, order=3 name=a1, order=2 name=a3, order=1 name=a2] 4.基于A的order升序以及name的降序排序——方法2扩展:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1] 4.基于order升序及name降序——方法3:[order=1 name=a2, order=2 name=a3, order=3 name=a3, order=3 name=a1]

2 Map排序 2.1 基本数据类型的排序
常用的存储数据的map结构是HashMap,它有着高效的增删改查效率,但是HashMap无法记录数据的顺序,因此排序时常用linkedHashMap存储有序数据。
HashMap、LinkedHashMap的详细介绍参考:
1、 https://blog.csdn.net/qq_2876...
2、 https://www.cnblogs.com/coder...
@Test public void test(){ Map map = new HashMap<>(); map.put("b", 0.08); map.put("a", 0.1); map.put("c", 0.02); map.put("d", 0.91); System.out.println("原始:"+map); Map result = new LinkedHashMap<>(); map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); System.out.println("按key升序排:"+result); Map result2 = new LinkedHashMap<>(); map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEachOrdered(e -> result2.put(e.getKey(), e.getValue())); System.out.println("按value升序排:"+result2); }

运行结果:
原始:{a=0.1, b=0.08, c=0.02, d=0.91} 按key升序排:{a=0.1, b=0.08, c=0.02, d=0.91} 按value升序排:{c=0.02, b=0.08, a=0.1, d=0.91}

逆序可以在comparingByKey或comparingByValue后添加reversed,将排序方法封装如下:
/* * 基于value排序 * @paramisReverse 表示是否逆序排 * @return */ public > Map sortByValue(Map map, boolean isReverse) { Map result = new LinkedHashMap<>(); if (isReverse) { map.entrySet().stream().sorted(Map.Entry.comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); } else { map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); } return result; }/* * 基于key排序 * @paramisReverse 表示是否逆序排 * @return */ public , V> Map sortByKey(Map map, boolean isReverse) { Map result = new LinkedHashMap<>(); if (isReverse) { map.entrySet().stream().sorted(Map.Entry.comparingByKey().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); } else { map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); } return result; }

除了HashMap和LinkedHashMap之外,还有一种不需要额外的排序操作,数据存储时就是有序的结构,称之为TreeMap。
TreeMap的详细介绍参考:
1、 https://blog.csdn.net/chenssy...
2、 https://www.liaoxuefeng.com/w...
其使用方法如下:
@Test public void treeMapTest(){ TreeMap map = new TreeMap<>(); map.put("b", 0.08); map.put("a", 0.1); map.put("c", 0.02); System.out.println("默认按key正序:"+map); TreeMap map2 = new TreeMap<>(new Comparator() { @Override public int compare(String o1, String o2) { return -o1.compareTo(o2); } }); map2.put("b", 0.08); map2.put("a", 0.1); map2.put("c", 0.02); System.out.println("自定义按key逆序:"+map2); }

注意:TreeMap仅支持对key排序,如需对value排序,则需要转换成list之后再sort,不再赘述。
2.2 JavaBean类型的排序
常见的场景是:map的value存储的JavaBean,需要按照JavaBean中的字段排序。
比如按照A的order升序及name的降序排序,代码如下:
@Test public void objectTest(){ Map map = new HashMap<>(); map.put("b", new A("a2", 1)); map.put("a", new A("a3", 3)); map.put("c", new A("a3", 2)); map.put("d", new A("a1", 3)); Map result = new LinkedHashMap<>(); Comparator comparator = (c1, c2) -> { A a1=c1.getValue(); A a2=c2.getValue(); if (a1.getOrder().equals(a2.getOrder())) { return -a1.getName().compareTo(a2.getName()); } return a1.getOrder().compareTo(a2.getOrder()); }; map.entrySet().stream().sorted(comparator).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); System.out.println("按value升序排:"+result); }

【【JAVA基础】List、Map排序总结】运行结果:
按照value中的order升序及name的降序排序{b=order=1 name=a2, c=order=2 name=a3, a=order=3 name=a3, d=order=3 name=a1}

    推荐阅读