从 LinkedHashMap 的 keySet() 创建的 ArrayList 是否保留插入顺序?
Does an ArrayList created from the keySet() of LinkedHashMap preserves the order of insertion?
我得到的数据类似于
{"Employee 1 of ABC", "ABCX"}, {"Employee 2 of ABC", "ABCY"},
{"Employee 3 of ABC", "ABCZ"}
通过 RefCursor
.
从数据库
我有一个案例需要保留从数据库中读取数据的顺序。
因为我的数据有点像 'key-value' ,所以我想到了使用 Map
的实现,它是有序的。因此选择了LinkedHashMap
//defined as a static map inside a common utlity class
public class Common{
public static final LinkedHashMap<String, String> empMap = new LinkedHashMap<String, String>();
}
//rs is the resultset
if (rs != null) {
while (rs.next()) {
key = rs.getString("name_text");
value = rs.getString("id");
Common.empMap.put(key, value);
}
}
我必须按照从数据库(游标)检索密钥的相同顺序将密钥传递给客户端。
List<String> empList = new ArrayList<String>(Common.empMap.keySet());
keySet() - The documentation says "Returns a Set view of the keys
contained in this map. The set is backed by the map, so changes to
the map are reflected in the set, and vice-versa"
我期望的是,由于 ArrayList
也是一个有序集合,我应该以与 retrieved/inserted 相同的方式将密钥获取到 Map
。
当我做一个示例测试程序时,我得到了预期的结果。
public class LinkedMap {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("Employee 1 of ABC", "ABCX");
map.put("Employee 2 of ABC", "ABCY");
map.put("Employee 3 of ABC", "ABCZ");
ArrayList<String> list = new ArrayList<String>(map.keySet());
System.out.println(list);
}
}
output: [Employee 1 of ABC, Employee 2 of ABC, Employee 3 of ABC]
但是我的问题是,如果这是有保证的输出,或者是我随机得到的,它可能会有所不同(?),
- 2019 年 9 月 14 日更新
我将答案与问题分开以避免混淆。
它是保证的。
即使 Set
接口本身不能保证任何顺序(好吧,LinkedHashSet
可以),Map
实现本身保证插入顺序这一事实几乎可以保证您也将按此顺序获得钥匙。 .keySet()
返回的接口恰好是 Set
,因为 Map
中的键保证是唯一的。
如果不是,请考虑在这种情况下会发生什么:
// case 1
for (final Map.Entry<K, V> entry: map.entrySet()) {
// entry.getKey(), entry.getValue()
}
// case 2
for (final K key: map.keySet()) {
V value = map.get(key);
}
如果这两个代码有两种不同的行为,呃...
是的,有保证。
在 Oracle JDK 中,class LinkedHashMap
重新实现方法 newKeyIterator()
,其中 returns class 的实例继承 LinkedHashIterator
。那个是订的。
其他答案解释说 LinkedHashMap#keySet().iterator()
按指定顺序迭代,所以让我添加:
ArrayList
Javadoc 说 ArrayList(Collection)
:
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
所以可以保证 ArrayList
项的顺序相同。
LinkedHashSet
的迭代顺序保证与插入键的顺序相同(假设您不使用允许您请求按最近访问顺序排序的特殊构造函数).您可以在 its documentation.
中找到它
我想你可能会争辩说迭代顺序保证仅适用于条目集,而不适用于其他视图,但文档支持得不好(因为它们指的是 the 迭代顺序),实际上集合视图共享一个公共迭代顺序。
就其本身而言,构造函数 ArrayList(Collection)
is documented 按照指定 Collection
的迭代器返回元素的顺序填充列表。
正如这个问题 Does entrySet() in a LinkedHashMap also guarantee order? and noted in the JavaDocs 中所解释的,迭代类型操作被定义为在 LinkedHashMap
的插入顺序中。这会影响 keySet
,因为它会影响 entrySet
。
ArrayList
的构造函数将按迭代器的顺序插入 List
。
这两个条件结合起来,意味着 API 保证了这种行为。
谢谢大家,你们每个人都贡献了有效积分。
总结所有答案,
保证顺序不变
根据 Javadocs、
LinkedHashMap is Hash table and linked list implementation of the Map
interface, with predictable iteration order. This implementation
differs from HashMap in that it maintains a doubly-linked list running
through all of its entries. This linked list defines the iteration
ordering, which is normally the order in which keys were inserted into
the map (insertion-order)
即:LinkedHashMap
将按照条目放入地图的顺序进行迭代。
所以 LinkedHashMap#keySet()
会给我相同的键插入地图的顺序,因为
LinkedHashMap#keySet().iterator()
按指定顺序迭代。
深入实施iterator()
我们可以看到,
LinkedHashMap 实现了方法 newKeyIterator(),其中 returns 一个 class 继承 LinkedHashIterator 的实例,负责 'ordering'
// These Overrides alter the behavior of superclass view iterator() methods
Iterator<K> newKeyIterator() { return new KeyIterator(); } ...
private class KeyIterator extends LinkedHashIterator<K> {...
private abstract class LinkedHashIterator<T> implements Iterator<T> { ...
为此:ArrayList<String> list = new ArrayList<String>(map.keySet());
构造函数 ArrayList(Collection) 是 documented 以指定 Collection 的迭代器返回元素的顺序填充列表。
我得到的数据类似于
{"Employee 1 of ABC", "ABCX"}, {"Employee 2 of ABC", "ABCY"}, {"Employee 3 of ABC", "ABCZ"}
通过 RefCursor
.
我有一个案例需要保留从数据库中读取数据的顺序。
因为我的数据有点像 'key-value' ,所以我想到了使用 Map
的实现,它是有序的。因此选择了LinkedHashMap
//defined as a static map inside a common utlity class
public class Common{
public static final LinkedHashMap<String, String> empMap = new LinkedHashMap<String, String>();
}
//rs is the resultset
if (rs != null) {
while (rs.next()) {
key = rs.getString("name_text");
value = rs.getString("id");
Common.empMap.put(key, value);
}
}
我必须按照从数据库(游标)检索密钥的相同顺序将密钥传递给客户端。
List<String> empList = new ArrayList<String>(Common.empMap.keySet());
keySet() - The documentation says "Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa"
我期望的是,由于 ArrayList
也是一个有序集合,我应该以与 retrieved/inserted 相同的方式将密钥获取到 Map
。
当我做一个示例测试程序时,我得到了预期的结果。
public class LinkedMap {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("Employee 1 of ABC", "ABCX");
map.put("Employee 2 of ABC", "ABCY");
map.put("Employee 3 of ABC", "ABCZ");
ArrayList<String> list = new ArrayList<String>(map.keySet());
System.out.println(list);
}
}
output: [Employee 1 of ABC, Employee 2 of ABC, Employee 3 of ABC]
但是我的问题是,如果这是有保证的输出,或者是我随机得到的,它可能会有所不同(?),
- 2019 年 9 月 14 日更新
我将答案与问题分开以避免混淆。
它是保证的。
即使 Set
接口本身不能保证任何顺序(好吧,LinkedHashSet
可以),Map
实现本身保证插入顺序这一事实几乎可以保证您也将按此顺序获得钥匙。 .keySet()
返回的接口恰好是 Set
,因为 Map
中的键保证是唯一的。
如果不是,请考虑在这种情况下会发生什么:
// case 1
for (final Map.Entry<K, V> entry: map.entrySet()) {
// entry.getKey(), entry.getValue()
}
// case 2
for (final K key: map.keySet()) {
V value = map.get(key);
}
如果这两个代码有两种不同的行为,呃...
是的,有保证。
在 Oracle JDK 中,class LinkedHashMap
重新实现方法 newKeyIterator()
,其中 returns class 的实例继承 LinkedHashIterator
。那个是订的。
其他答案解释说 LinkedHashMap#keySet().iterator()
按指定顺序迭代,所以让我添加:
ArrayList
Javadoc 说 ArrayList(Collection)
:
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
所以可以保证 ArrayList
项的顺序相同。
LinkedHashSet
的迭代顺序保证与插入键的顺序相同(假设您不使用允许您请求按最近访问顺序排序的特殊构造函数).您可以在 its documentation.
我想你可能会争辩说迭代顺序保证仅适用于条目集,而不适用于其他视图,但文档支持得不好(因为它们指的是 the 迭代顺序),实际上集合视图共享一个公共迭代顺序。
就其本身而言,构造函数 ArrayList(Collection)
is documented 按照指定 Collection
的迭代器返回元素的顺序填充列表。
正如这个问题 Does entrySet() in a LinkedHashMap also guarantee order? and noted in the JavaDocs 中所解释的,迭代类型操作被定义为在 LinkedHashMap
的插入顺序中。这会影响 keySet
,因为它会影响 entrySet
。
ArrayList
的构造函数将按迭代器的顺序插入 List
。
这两个条件结合起来,意味着 API 保证了这种行为。
谢谢大家,你们每个人都贡献了有效积分。
总结所有答案,
保证顺序不变
根据 Javadocs、
LinkedHashMap is Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order)
即:LinkedHashMap
将按照条目放入地图的顺序进行迭代。
所以 LinkedHashMap#keySet()
会给我相同的键插入地图的顺序,因为
LinkedHashMap#keySet().iterator()
按指定顺序迭代。
深入实施iterator()
我们可以看到,
LinkedHashMap 实现了方法 newKeyIterator(),其中 returns 一个 class 继承 LinkedHashIterator 的实例,负责 'ordering'
// These Overrides alter the behavior of superclass view iterator() methods
Iterator<K> newKeyIterator() { return new KeyIterator(); } ...
private class KeyIterator extends LinkedHashIterator<K> {...
private abstract class LinkedHashIterator<T> implements Iterator<T> { ...
为此:ArrayList<String> list = new ArrayList<String>(map.keySet());
构造函数 ArrayList(Collection) 是 documented 以指定 Collection 的迭代器返回元素的顺序填充列表。