Java TreeMap
在个人记账本系统里面用到了TreeMap:
TreeMap<YearMonth, Map<String, Double>> treeMap = new TreeMap<>(Collections.reverseOrder());
当时我就有疑问了,为什么要用TreeMap,使用HashMap 不行吗?之后我了解到,与HashMap不同,TreeMap它是有序的。下面是官方文档的部分说明:
The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
中文意思:该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造函数。
Java基本类的包装类和一些常用类都实现了Comparable,所以可以直接作为Key。
TreeMap<Integer, String> treeMap1 = new TreeMap<>();
TreeMap<Boolean, String> treeMap2 = new TreeMap<>();
TreeMap<LocalDate, String> treeMap3 = new TreeMap<>();
TreeMap<UUID, String> treeMap4 = new TreeMap<>();
当然我使用的YearMonth也实现了Comparable
@jdk.internal.ValueBased
public final class YearMonth
implements Temporal, TemporalAdjuster, Comparable<YearMonth>, Serializable {
注:如果你在类的继承关系里没找到Comparable,它有可能在被继承类的父类里面。
当你希望键值对按一定顺序来保存你需要的数据时,就可以使用TreeMap,我的需求就是希望按照年月的倒序顺序来保存收入支出的记录。
除了这些实现Comparable接口的类,如果你想把自定义的类当做TreeMap的Key,比如User, Person等, 就需要满足一定的条件:自定义类实现Comparable接口或者在使用TreeMap时提供Comparator。如果没有满足上面的条件的任何一个而直接使用TreeMap,即使编译期没问题,可以顺利编译成字节码文件,但是在运行的时候会报错。下面是一个例子和报错信息:
Map<AccountBook, String> treeMap = new TreeMap<>();
AccountBook accountBook1 = new AccountBook();
accountBook1.setNextId(1);
AccountBook accountBook2 = new AccountBook();
accountBook2.setNextId(2);
treeMap.put(accountBook1, "first");
treeMap.put(accountBook2, "second");
String accountOrder = treeMap.get(accountBook1);
Exception in thread "main" java.lang.ClassCastException: class com.selfimp.accountbook.AccountBook cannot be cast to class java.lang.Comparable (com.selfimp.accountbook.AccountBook is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
at java.base/java.util.TreeMap.compare(TreeMap.java:1604)
at java.base/java.util.TreeMap.addEntryToEmptyMap(TreeMap.java:811)
at java.base/java.util.TreeMap.put(TreeMap.java:820)
at java.base/java.util.TreeMap.put(TreeMap.java:569)
at com.selfimp.accountbook.PersonalAccountBook.run(PersonalAccountBook.java:41)
at com.selfimp.accountbook.Main.main(Main.java:12)
下面简要介绍下自定义类如何实现Comparable接口以及在使用TreeMap时如何提供Comparator。
- 自定义类实现Comparable接口,需要实现compareTo()方法,并且强烈建议重写equals()和hashCode() 方法。下面是YearMonth类的相关方法的实现,以供参考。
@Override
public int compareTo(YearMonth other) {
int cmp = (year - other.year);
if (cmp == 0) {
cmp = (month - other.month);
}
return cmp;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
return (obj instanceof YearMonth other)
&& year == other.year
&& month == other.month;
}
@Override
public int hashCode() {
return year ^ (month << 27);
}
- 在使用TreeMap时提供Comparator,如下:
Map<AccountBook, String> treeMap = new TreeMap<>(Comparator.comparing(AccountBook :: getNextId));
这样TreeMap就会按照nextId(int类型)的顺序来有序的存储每一个AccountBook实例。
更多推荐




所有评论(0)