为什么 EnumMap 在 Java 中不是 SortedMap?
Why is EnumMap not a SortedMap in Java?
EnumMap<K extends Enum<K>, V>
in Java 显然是根据关联枚举的定义排序的,您也可以在 javadoc 中看到:
枚举映射按照其键的自然顺序(声明枚举常量的顺序)进行维护。这反映在集合视图(keySet()
、entrySet()
和 values()
)返回的迭代器中。
我需要的是 SortedMap
使用枚举作为键类型。我想使用 headMap()
或 firstKey()
之类的方法,但我想从 EnumMap
s 添加的 cpu+ 内存性能中获利。 TreeMap
在这里听起来开销太大了。
问题:这是否只是在实施中遗漏了,是因为懒惰(源自 AbstractMap
)还是有充分的理由为什么 EnumMap
不是一个 SortedMap
?
这不会回答您的主要问题(因为只有原始设计者有答案),但我正在考虑的一种方法是让您自己实现它。在尝试基于 EnumMap
进行 SortedMap
实施时,我想出了以下 class.
这肯定是一个快速而肮脏的实现(请注意,它不完全符合 SortedMap
- 因为不满足 view 要求),但是 如果你需要一个,你可以改进它:
class SortedEnumMap<K extends Enum<K>, V>
extends EnumMap<K, V>
implements SortedMap<K, V> {
private Class<K> enumClass;
private K[] values;
public SortedEnumMap(Class<K> keyType) {
super(keyType);
this.values = keyType.getEnumConstants();
this.enumClass = keyType;
if (this.values.length == 0) {
throw new IllegalArgumentException("Empty values");
}
}
@Override
public Comparator<? super K> comparator() {
return Comparator.comparingInt(K::ordinal);
}
@Override
public SortedMap<K, V> subMap(K fromKey, K toKey) {
List<K> keys = Arrays.stream(this.values)
.dropWhile(k -> k.ordinal() < fromKey.ordinal())
.takeWhile(k -> k.ordinal() < toKey.ordinal())
.collect(Collectors.toList());
return this.forKeys(keys);
}
@Override
public SortedMap<K, V> headMap(K toKey) {
List<K> keys = new ArrayList<>();
for (K k : this.values) {
if (k.ordinal() < toKey.ordinal()) {
keys.add(k);
} else {
break;
}
}
return this.forKeys(keys);
}
@Override
public SortedMap<K, V> tailMap(K fromKey) {
List<K> keys = new ArrayList<>();
for (K k : this.values) {
if (k.ordinal() >= fromKey.ordinal()) {
keys.add(k);
}
}
return this.forKeys(keys);
}
//Returned map is NOT a "view" or the current one
private SortedEnumMap<K, V> forKeys(List<K> keys) {
SortedEnumMap<K, V> n = new SortedEnumMap<>(this.enumClass);
keys.forEach(key -> n.put(key, super.get(key)));
return n;
}
@Override
public K firstKey() {
return this.values[0];
}
@Override
public K lastKey() {
return this.values[this.values.length - 1];
}
}
并进行快速测试(尚未发现错误):
SortedMap<Month, Integer> m = new SortedEnumMap(Month.class);
for (Month v : Month.values()) {
m.put(v, v.getValue());
}
System.out.println("firstKey(): " + m.firstKey());
System.out.println("lastKey(): " + m.lastKey());
System.out.println("headMap/June: " + m.headMap(Month.JUNE));
System.out.println("tailMap/June: " + m.tailMap(Month.JUNE));
System.out.println("subMap/April-July " + m.subMap(Month.APRIL, Month.JULY));
我得到:
firstKey(): JANUARY
lastKey(): DECEMBER
headMap/June: {JANUARY=1, FEBRUARY=2, MARCH=3, APRIL=4, MAY=5}
tailMap/June: {JUNE=6, JULY=7, AUGUST=8, SEPTEMBER=9, OCTOBER=10, NOVEMBER=11, DECEMBER=12}
subMap/April-July {APRIL=4, MAY=5, JUNE=6}
打开功能请求
我找到了 this issue for OpenJDK。它是 2005 年的,但仍然 open/unresolved。
我假设没有任何 "good reason" 未实施。
EnumMap<K extends Enum<K>, V>
in Java 显然是根据关联枚举的定义排序的,您也可以在 javadoc 中看到:
枚举映射按照其键的自然顺序(声明枚举常量的顺序)进行维护。这反映在集合视图(keySet()
、entrySet()
和 values()
)返回的迭代器中。
我需要的是 SortedMap
使用枚举作为键类型。我想使用 headMap()
或 firstKey()
之类的方法,但我想从 EnumMap
s 添加的 cpu+ 内存性能中获利。 TreeMap
在这里听起来开销太大了。
问题:这是否只是在实施中遗漏了,是因为懒惰(源自 AbstractMap
)还是有充分的理由为什么 EnumMap
不是一个 SortedMap
?
这不会回答您的主要问题(因为只有原始设计者有答案),但我正在考虑的一种方法是让您自己实现它。在尝试基于 EnumMap
进行 SortedMap
实施时,我想出了以下 class.
这肯定是一个快速而肮脏的实现(请注意,它不完全符合 SortedMap
- 因为不满足 view 要求),但是 如果你需要一个,你可以改进它:
class SortedEnumMap<K extends Enum<K>, V>
extends EnumMap<K, V>
implements SortedMap<K, V> {
private Class<K> enumClass;
private K[] values;
public SortedEnumMap(Class<K> keyType) {
super(keyType);
this.values = keyType.getEnumConstants();
this.enumClass = keyType;
if (this.values.length == 0) {
throw new IllegalArgumentException("Empty values");
}
}
@Override
public Comparator<? super K> comparator() {
return Comparator.comparingInt(K::ordinal);
}
@Override
public SortedMap<K, V> subMap(K fromKey, K toKey) {
List<K> keys = Arrays.stream(this.values)
.dropWhile(k -> k.ordinal() < fromKey.ordinal())
.takeWhile(k -> k.ordinal() < toKey.ordinal())
.collect(Collectors.toList());
return this.forKeys(keys);
}
@Override
public SortedMap<K, V> headMap(K toKey) {
List<K> keys = new ArrayList<>();
for (K k : this.values) {
if (k.ordinal() < toKey.ordinal()) {
keys.add(k);
} else {
break;
}
}
return this.forKeys(keys);
}
@Override
public SortedMap<K, V> tailMap(K fromKey) {
List<K> keys = new ArrayList<>();
for (K k : this.values) {
if (k.ordinal() >= fromKey.ordinal()) {
keys.add(k);
}
}
return this.forKeys(keys);
}
//Returned map is NOT a "view" or the current one
private SortedEnumMap<K, V> forKeys(List<K> keys) {
SortedEnumMap<K, V> n = new SortedEnumMap<>(this.enumClass);
keys.forEach(key -> n.put(key, super.get(key)));
return n;
}
@Override
public K firstKey() {
return this.values[0];
}
@Override
public K lastKey() {
return this.values[this.values.length - 1];
}
}
并进行快速测试(尚未发现错误):
SortedMap<Month, Integer> m = new SortedEnumMap(Month.class);
for (Month v : Month.values()) {
m.put(v, v.getValue());
}
System.out.println("firstKey(): " + m.firstKey());
System.out.println("lastKey(): " + m.lastKey());
System.out.println("headMap/June: " + m.headMap(Month.JUNE));
System.out.println("tailMap/June: " + m.tailMap(Month.JUNE));
System.out.println("subMap/April-July " + m.subMap(Month.APRIL, Month.JULY));
我得到:
firstKey(): JANUARY
lastKey(): DECEMBER
headMap/June: {JANUARY=1, FEBRUARY=2, MARCH=3, APRIL=4, MAY=5}
tailMap/June: {JUNE=6, JULY=7, AUGUST=8, SEPTEMBER=9, OCTOBER=10, NOVEMBER=11, DECEMBER=12}
subMap/April-July {APRIL=4, MAY=5, JUNE=6}
打开功能请求
我找到了 this issue for OpenJDK。它是 2005 年的,但仍然 open/unresolved。
我假设没有任何 "good reason" 未实施。