现在的位置: 首页 > 综合 > 正文

Java 中TreeSet关于添加Key为空问题

2013年08月21日 ⁄ 综合 ⁄ 共 2881字 ⁄ 字号 评论关闭

TreeMap 中的get(Object)方法调用是 Entry<K,V> getEntry(Object key)

该方法如果 key == null 会抛出异常,所以这个要注意,在添加的时候,如果比较器不为空的话,就根据比较器比较结果进行插入,如果比较为空,如果插入Key为空的

话,就直接异常,为什么会这样做呢,因为TreeMap是一个红黑树结构,其结构是根据键值的排序进行建立的,之所以比较器不为空的情况不抛异常,是因为

比较器中可能会有与NULL比较的情况,所以可能会有这种树中为结点Key为空的情况,还有就是如果Key=NULL作为根结点会直接插入,不会进行比较

但这里要注意了,如果树中有Key为NULL情况,在get(Object) 方法执行的时候是调用 getEntry(Object),我们来看一下getEntry(Object)源码:

 final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
	Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }
 final Entry<K,V> getEntryUsingComparator(Object key) {
	K k = (K) key;
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            Entry<K,V> p = root;
            while (p != null) {
                int cmp = cpr.compare(k, p.key);
                if (cmp < 0)
                    p = p.left;
                else if (cmp > 0)
                    p = p.right;
                else
                    return p;
            }
        }
        return null;
    }

可见对于取方法也是分为两种情况,一种如果比较器为空,另一种比较器不为空,如果比较器为空的情况下,get(NULL)会直接异常,

所以这个要说的是,在比较器为空,且NULL作为根结点插入后,就不可能再取出这个Key=null 的值

下面是插入算法,至于红黑树的插入这里就不再细说了

 public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
	    // TBD:
	    // 5045147: (coll) Adding null to an empty TreeSet should
	    // throw NullPointerException
	    //
	    // compare(key, key); // type check
            root = new Entry<K,V>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<K,V>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

TreeMap tree = new TreeMap();
		tree.put(null,1);
		System.out.println(tree.size());
		System.out.println(tree.get(null));// 会抛异常

自定义Comparator

package Trees;
import static java.lang.System.out;
import java.util.TreeMap;
import java.util.Comparator;
public class TreeMapTest {
	
	public static void main(String args[]) {
		TreeMap<Integer,Integer> tree = new TreeMap<Integer,Integer>(new Com());
		tree.put(1, 1);
		tree.put(null, 2);
		System.out.println(tree.size());		// 2
		System.out.println(tree.get(null));		// 不会异常
	}
}
class Com implements Comparator<Integer>{

	@Override
	public int compare(Integer o1, Integer o2) {
		if(o1==null&& o2==null)
			return 0;
		if(o1!=null)
			return 1;
		if(o2!=null)return -1;
		return o1.compareTo(o2);
	}
	
}


因此,在使用 TreeSet 过程中,如果是自定义的比较器中

在比较器方法 int compare(o1,o2)中,如果没有判断  o1,o2 与 null 所有关系的话,可能会造成  tree.put(null,1) 存入后无法 get(null) 的情况

如:我们只是简单的 if(o1==null || o2 == null) return -1 ;

那么 tree.put(1,1); tree.put(null,2)后, tree.get(null) 得到的值将会是空

说了这么多,就一句话,

如果要在 treeSet 中存放 Key = null 的键值,就要自定义 comparactor ,并且在自定义的 comparactor 中要指明 o1 , o2 与 null 的所有关系

如果不自定义 Comparactor 就不要存放 键值为 null 的值

抱歉!评论已关闭.