Map.Entry 接口
map.entry
map
接口下面的entry
接口。
该接口,定义一个键值对实体接口。map.entryset
方法返回的 set
集合中的实体就是实现这个 它。只有一种方法可以获得 map.entry
对象的引用,那就是通过集合的迭代器。并且 map.entry
只在迭代期间有效,更加准确的是意思是,如果在获得迭代器以后,修改了集合,那么 map.entry
的行为是未定义的。除非调用 map.entry
的 setvalue
设置下修改的值。
api
文档中的这段话,说的让我有点费解。修改集合以后,map.entry
的行为是未定义的,lz 做了实验,发现并没有触发到什么非法,未定义的操作。
map<string, string> stringmap = new hashmap<>(16); stringmap.put("key1", "value1"); stringmap.put("key2", "value2"); stringmap.put("key3", "value3"); stringmap.put("key4", "value4"); stringmap.put("key5", "value5"); stringmap.put("key6", "value6"); iterator<map.entry<string, string>> iterator = stringmap.entryset().iterator(); map.entry<string, string> next = iterator.next(); stringmap.remove(next.getkey()); stringmap.put(next.getkey(),"value7");
就如上面的代码所示,在得到 entry
以后,对集合进行了修改,也没有触发什么非法的状态,抛出什么异常来。这里的未定义,其实是一个很无懈可击的答案,既然是未定义的,那么它们做出的任何行为,都是可以被理解的,所以它没抛出什么异常,那也是对的,抛出异常也是对的,你不应该单方面的任认为它应该怎样怎样,因为它是未定义,不同的实现有不同的反应。
而且这里的合法与非法,是针对 entry
的值来说,在你获取以后,有人又修改了集合的内容,这时候你获取的 entry
的内容,也会随之改变,但是你可能不知道集合被修改过,所以这里的合法与非法,是 entry
是否可以再被信任的问题,所以想要修改值的时候,应该用 entry
的 setvalue()
方法,显示的去改。
k getkey()
返回实体对应的 key
。
可能抛出的异常 illegalstateexception
,这个异常可以 选择性 的实现。如果实现了,则异常的抛出条件:如果对应的 entry
已经被移除了,则抛出该异常。
比如,hashmap
的 entry
就没有实现抛出该异常:
static class node<k,v> implements map.entry<k,v> { ... public final k getkey() { return key; } ... }
而enummap
则实现了该异常,并且遵守了异常抛出条件:
private class entry implements map.entry<k,v> { ... public k getkey() { checkindexforentryuse(); return keyuniverse[index]; } ... private void checkindexforentryuse() { if (index < 0) throw new illegalstateexception("entry was removed"); } }
v getvalue()
返回 entry
实体对应的 value
。
如果集合中此 entry
的映射关系已经被移除,即使是通过 iterator
的 remove
方法,getvalue()
方法的返回值也是 未定义。因此,不同的实现,对此方法有不同的做法,hashmap
对其没做什么,正常返回值,即使映射关系被删除了。enummap
则抛出异常。
可能抛出的异常 illegalstateexception
,这个异常可以 选择性 的实现。如果实现了,则异常的抛出条件:如果对应的 entry
已经被移除了,则抛出该异常。
v setvalue(v value)
替换当前 entry
的 value
为传进来的给定的 value
,(map
中对应的 value
也被改变)。如果集合中 entry
的映射关系已经被通过迭代器的 remove()
方法移除,则调用这个方法的行为是 未定义 的。看具体的实现如何操作。同样的 hashmap
对此行为,返回正确的值。enummap
则抛出异常。
返回设置值之前,当前 entry
对应的值。
可能抛出的异常:
-
unsupportedoperationexception
:如果集合不支持put
操作,则抛出此异常。 -
classcastexception
:如果传入的参数,不能转换存储到集合中,则抛出此异常,类型转换异常。 -
nullpointerexception
:如果集合不允许存入null
,其传入的参数确实是null
,则抛出此异常。 -
illegalargumentexception
:如果传入的值的某些属性,阻止其存入集合中,则抛出此异常。 -
illegalstateexception
:此异常可选择是否实现。如果entry
已经被移除了,则抛出此异常。
boolean equals(object o)
将传入的参数对象与当前的 entry
比较,如果传入的对象也是一个 entry
类型,并且它们具有相同的映射关系,则返回 true
。
更确切的说,相同的映射关系,应该写成下面的代码: key
,value
分别相等。
(e1.getkey()==null ? e2.getkey()==null : e1.getkey().equals(e2.getkey())) && (e1.getvalue()==null ? e2.getvalue()==null: e1.getvalue().equals(e2.getvalue()))
这样做以后,可以确保 equals
方法在不同的 map.entry
实现之前都能正确的工作。
int hashcode()
返回当前 entry
的哈希码。entry
的哈希码计算方法如下:
(e.getkey()==null ? 0 : e.getkey().hashcode()) ^ (e.getvalue()==null ? 0 : e.getvalue().hashcode())
这样做,确保 e1.equals(e2)
时,e1.hashcode()==e2.hashcode()
,当前前提是,这个两个 entry
的 kv
的 hashcode
方法一致 。
下面几个方法是 1.8 添加进来的。属于静态方法
comparingbykey()
public static <k extends comparable<? super k>, v> comparator<map.entry<k,v>> comparingbykey() { return (comparator<map.entry<k, v>> & serializable) (c1, c2) -> c1.getkey().compareto(c2.getkey()); }
返回一个 comparator
,该比较器对 entry
的 key
进行 自然排序,即按照字典顺序,0-9,a-z 。
返回的比较器,实现了 serializable
接口。代码中 (comparator<map.entry<k, v>> & serializable)
是强转的含义。强转可以这样写,转为二者的结合,但是 &
后面必须是 接口 。
可能抛出的异常:nullpointerexception
,如果比较的 entry
的 key
是 null
,则抛出此异常。
comparingbyvalue( )
public static <k, v extends comparable<? super v>> comparator<map.entry<k,v>> comparingbyvalue() { return (comparator<map.entry<k, v>> & serializable) (c1, c2) -> c1.getvalue().compareto(c2.getvalue()); }
返回一个 comparator
,该比较器对 entry
的 key
进行 自然排序 。
返回的比较器,实现了 serializable
接口。
可能抛出的异常:nullpointerexception
,如果比较的 entry
的 key
是 null
,则抛出此异常。
comparingbykey(comparator<? super k> cmp)
public static <k, v> comparator<map.entry<k, v>> comparingbykey(comparator<? super k> cmp) { objects.requirenonnull(cmp); return (comparator<map.entry<k, v>> & serializable) (c1, c2) -> cmp.compare(c1.getkey(), c2.getkey()); }
返回一个比较器,该比较器对 entry
的 key
进行比较,根据传入的比较器。如果传入的比较器实现了 serializable
接口,那么返回的比较器也一并实现该接口。
comparingbyvalue(comparator<? super v> cmp)
public static <k, v> comparator<map.entry<k, v>> comparingbyvalue(comparator<? super v> cmp) { objects.requirenonnull(cmp); return (comparator<map.entry<k, v>> & serializable) (c1, c2) -> cmp.compare(c1.getvalue(), c2.getvalue()); }
返回一个比较器,该比较器对 entry
的 value
进行比较,根据传入的比较器。如果传入的比较器实现了 serializable
接口,那么返回的比较器也一并实现该接口。
可以参考下 coderanch 上面的回答 。真是令人惊叹,上面关于这个疑问的讨论,还是十七年前的回答,当时的他们又是人几何年呢。如果也如我一样,那十七年过去了,现在也是不惑之年了。
上一篇: i++和++i