除了JVM版本之外,有没有理由使用SortedMap
而不是NavigableMap
? (NavigableMap
自1.6以来一直存在; SortedMap
自1.2以来一直存在
我正在尝试找到具有最大键的值,使得键< =引用键K0。我似乎无法弄明白如何使用SortedMap
(如果它严格是<,那么我会调用headMap()
然后调用lastKey()
然后调用{{1} }),但NavigableMap.floorEntry()
似乎正是我需要的。
澄清:就像一个例子,我正在处理具有不同行为模型的稀疏版本号范围。键可能是[0,2,5],因此版本号0和1由键#0处的值处理,版本号2-4由键#2处的值处理,版本号> gt; = 5由键#5处的值处理。
答案 0 :(得分:9)
就个人而言,我非常相信使用最不具体的界面可以满足您的需求。这使您的意图更加清晰,对您可能的实施设置的限制更少。
大多数开发人员希望Sorted集合用于迭代目的,也许还需要随机访问性能。我看到很少有需要关闭元素的情况。
如果您需要该功能,请继续。我认为TreeMap实际上实现了NavigableMap。但是当你不需要它时,为什么限制自己呢?
答案 1 :(得分:8)
除了JVM版本之外,有没有理由使用SortedMap而不是NavigableMap?
是的,我可以想到一个例子。地图的提供者可能已将其与Collections.unmodifiableSortedMap
包装在一起,因此即使源是TreeMap
(实现NavigableMap
),您也只能引用SortedMap
和你不能把它投到NavigableMap
。
我正在尝试找到具有最大键的值,使得键< =引用键K0。我似乎无法弄清楚如何使用SortedMap
来做到这一点
有两种情况:地图包含密钥的完全匹配,或者不包含。因此,首先要查找完全匹配,只有当它不存在时,m.headMap(key).lastKey()
才能给出正确答案。
这样做(虽然它没有真正的NavigableMap
那么高效):
static <K, V> Map.Entry<K, V> floorEntry(final SortedMap<K, V> m, K key) {
final SortedMap<K, V> tail;
if (m.containsKey(key)) {
tail = m.tailMap(key);
} else {
SortedMap<K, V> head = m.headMap(key);
if (head.isEmpty()) {
return null;
} else {
tail = head.tailMap(head.lastKey());
}
}
return tail.entrySet()
.iterator()
.next();
}
答案 2 :(得分:3)
使用整数时,可以使用x&lt; A + 1而不是x <= A,你已经完成了。我的意思是headMap(A + 1)等,应该做的工作。否则,我会选择finnw的解决方案,因为它比我能提出的任何内容都要清楚。
答案 3 :(得分:2)
我认为使用迭代器比使用headMap和tailMap更好,因为它效率不高。我测试了以下代码的情况,它运行良好,floorEntry2比floorEntry1快三倍。
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.*;
import java.util.Map.Entry;
import org.junit.Before;
import org.junit.Test;
class TestMapUtils <K,V> {
public TestMapUtils()
{
}
public Map.Entry<K, V> floorEntry1(final SortedMap<K, V> m, K key) {
final SortedMap<K, V> tail;
if (m.containsKey(key)) {
tail = m.tailMap(key);
} else {
SortedMap<K, V> head = m.headMap(key);
if (head.isEmpty()) {
return null;
} else {
tail = head.tailMap(head.lastKey());
}
}
return tail.entrySet()
.iterator()
.next();
}
public Map.Entry<K, V> floorEntry2(final NavigableMap<K, V> m, K key) {
Iterator<Map.Entry<K,V>> i = m.entrySet().iterator();
Entry<K,V> tailEntry = null;
if (key==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
return null;
}
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
{
return e;
}
else
{
if (((Integer) e.getKey()).intValue() < (((Integer) key).intValue())) {
tailEntry = e;
}
}
}
}
return tailEntry;
}
}
public class TestSortedMap {
protected TestMapUtils<Integer, Integer> testMapUtils;
private NavigableMap<Integer, Integer> sortedMap;
@Before
public void setUp()
{
testMapUtils = new TestMapUtils<Integer, Integer>();
sortedMap = addElementsToMap();
}
private NavigableMap<Integer, Integer> addElementsToMap() {
NavigableMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
map.put(10, 1);
map.put(20, 2);
map.put(30, 3);
map.put(40, 4);
map.put(50, 5);
map.put(60, 6);
return map;
}
@Test
public void testFloorEntry()
{
long startTime1 = System.nanoTime();
Entry<Integer, Integer> entry = testMapUtils.floorEntry2(sortedMap, 30);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 30);
entry = testMapUtils.floorEntry2(sortedMap, 60);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 60);
entry = testMapUtils.floorEntry2(sortedMap, 70);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 60);
entry = testMapUtils.floorEntry2(sortedMap, 55);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 50);
entry = testMapUtils.floorEntry2(sortedMap, 31);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 30);
entry = testMapUtils.floorEntry2(sortedMap, 0);
assertNull(entry);
long endTime1 = System.nanoTime() - startTime1;
long startTime2 = System.nanoTime();
entry = testMapUtils.floorEntry1(sortedMap, 30);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 30);
entry = testMapUtils.floorEntry1(sortedMap, 60);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 60);
entry = testMapUtils.floorEntry1(sortedMap, 70);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 60);
entry = testMapUtils.floorEntry1(sortedMap, 55);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 50);
entry = testMapUtils.floorEntry1(sortedMap, 31);
assertNotNull(entry);
assertEquals(entry.getKey().intValue(), 30);
entry = testMapUtils.floorEntry1(sortedMap, 0);
assertNull(entry);
long endTime2 = System.nanoTime() - startTime2;
if ( endTime2 > endTime1 )
{
System.out.println("First Execution is faster.. "+endTime1+", "+endTime2);
} else if ( endTime1 > endTime2 ) {
System.out.println("Second Execution is faster.. "+endTime1+", "+endTime2);
} else {
System.out.println("Execution times are same");
}
}
}
答案 4 :(得分:2)
除了JVM版本之外,有没有理由使用SortedMap而不是NavigableMap?
是的,如果您需要返回不可修改的地图而您没有使用Google Guava。
NavigableMap旨在取代SortedMap。 NavigableMap为SortedMap接口添加了经常需要的方法,Map实现者很容易添加,但是根据现有的SortedMap方法编写起来很尴尬。返回SortedMap而不是NavigableMap将导致代码的调用者不必要的工作。
很遗憾没有提供Collections.unmodifiableNavigableMap。 IMO这可能是一个疏忽,但在JDK 1.7中没有得到纠正,所以也许有人有理由不予理睬。我建议使用com.google.common.collect.Maps.unmodifiableNavigableMap。
答案 5 :(得分:0)
“[NavigableMap]旨在取代SortedMap界面。” http://download.oracle.com/javase/6/docs/technotes/guides/collections/changes6.html
尽管如此,我同意Uri:使用最不具体的界面。