java-sort

遇到一个排序需求,按照数字、字母、汉字的顺序排序。

<!-- https://mvnrepository.com/artifact/com.ibm.icu/icu4j -->
<dependency>
    <groupId>com.ibm.icu</groupId>
    <artifactId>icu4j</artifactId>
    <version>4.8</version>
</dependency>

Collections.sort(datas, new Comparator<TestVo>() {
	@Override
	public int compare(TestVo o1, TestVo o2) {
		// 
		if (o1.getField1() == null) {
			return 1;
		} else if (o2.getField1() == null) {
			return -1;
		} else if (!o1.getField1().equals(o2.getField1())) {
			return com.ibm.icu.text.Collator.getInstance(com.ibm.icu.util.ULocale.SIMPLIFIED_CHINESE).compare(o1.getField1(), o2.getField1());
		}

		// 
		if (o1.getField2() == null) {
			return 1;
		} else if (o2.getField2() == null) {
			return -1;
		}
		if (!o1.getField2().equals(o2.getField2())) {
			return com.ibm.icu.text.Collator.getInstance(com.ibm.icu.util.ULocale.SIMPLIFIED_CHINESE).compare(o1.getField2(), o2.getField2());
		}

		// 
		if (o1.getField3() == null) {
			return 1;
		} else if (o2.getField3() == null) {
			return -1;
		}
		if (!o1.getField3().equals(o2.getField3())) {
			return com.ibm.icu.text.Collator.getInstance(com.ibm.icu.util.ULocale.SIMPLIFIED_CHINESE).compare(o1.getField3(), o2.getField3());
		}

		// 
		if (o1.geField4() == null) {
			return -1;
		} else if (o2.geField4() == null) {
			return 1;
		}
		if (!o1.geField4().equals(o2.geField4())) {
			return com.ibm.icu.text.Collator.getInstance(com.ibm.icu.util.ULocale.SIMPLIFIED_CHINESE).compare(o2.geField4(), o1.geField4());
		}

		return 0;
	}
});
		
java.lang.IllegalArgumentException: Comparison method violates its general contract!
        at java.util.TimSort.mergeLo(TimSort.java:777) ~[?:1.8.0_71]
        at java.util.TimSort.mergeAt(TimSort.java:514) ~[?:1.8.0_71]
        at java.util.TimSort.mergeCollapse(TimSort.java:439) ~[?:1.8.0_71]
        at java.util.TimSort.sort(TimSort.java:245) ~[?:1.8.0_71]
        at java.util.Arrays.sort(Arrays.java:1512) ~[?:1.8.0_71]
        at java.util.ArrayList.sort(ArrayList.java:1454) ~[?:1.8.0_71]
        at java.util.Collections.sort(Collections.java:175) ~[?:1.8.0_71]

JDK7中的Collections.Sort方法实现中,你的返回值需要严谨全面;
如果两个值是相等的,那么compare方法需要返回0,否则 可能 会在排序时抛错,而JDK6是没有这个限制的。
在在 JDK7 版本以上,Comparator 要满足自反性,传递性,对称性

说明:

  1. 自反性:x,y 的比较结果和 y,x 的比较结果相反。
  2. 传递性:x>y,y>z,则 x>z。
  3. 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同

文件排序

文件按日期排序

Arrays.sort(files, new Comparator<File>() {
	public int compare(File f1, File f2) {
		long diff = f1.lastModified() - f2.lastModified();
		if (diff > 0)
			return 1;
		else if (diff == 0)
			return 0;
		else
			return -1;
	}

	public boolean equals(Object obj) {
		return true;
	}

});

按照文件名称排序

Arrays.sort(files, new Comparator<File>() {
	@Override
	public int compare(File o1, File o2) {
		if (o1.isDirectory() && o2.isFile())
			return -1;
		if (o1.isFile() && o2.isDirectory())
			return 1;
		return o1.getName().compareTo(o2.getName());
	}
});

按照文件大小排序

Arrays.sort(files, new Comparator<File>() {
	public int compare(File f1, File f2) {
		long diff = f1.length() - f2.length();
		if (diff > 0)
			return 1;
		else if (diff == 0)
			return 0;
		else
			return -1;
	}

	public boolean equals(Object obj) {
		return true;
	}
});
String number = name.replaceAll("[^\\d]", "");

References

[1] Comparison method violates its general contract 问题的处理
[2] Comparison method violates its general contract!
[3] file.listFiles()按文件名称、日期、大小排序方法 总结
[4] file.listFiles()按文件大小、名称、日期排序方法