有一些事情需要考虑,它们会影响您真正想要的解决方案。
您正在使用 a ,这意味着您需要 a -typeHashMap<K, V>
的关联和键查找行为。Map
HashMap
它本身并不关心排序 - 每当您插入键值对时,hashCode()
都会调用键的方法,并且映射使用该哈希码存储配对。String
对象已经有了正确的hashCode()
实现,因此您可以毫无问题地将它们用作键。
当然,在检索或迭代您HashMap
的 .
由于您想“排序”您的数据,我假设您的意思是您希望您的配对返回,按键排序(按您输入的名称排序)。
现在这里是需要考虑的地方:
保持数据始终排序
如果您希望始终对数据进行排序,即每次插入新的键值对时,都希望保持元素的自然顺序,那么您可以使用 Java API 中的一些方便的数据结构:
使用TreeMap
正如 Dilum 已经提到的,您可以使用java.util.TreeMap
实现java.util.SortedMap
接口的 ,这将保证对映射中的键进行排序。
例子:
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class SortedMapExample {
public static void main(String[] args) {
SortedMap<String, String> map = new TreeMap<String, String>();
map.put("Amit","Java");
map.put("Saral","J2EE");
map.put("ty","Spring");
map.put("Anupam","Hibernate");
map.put("Ravi",".Net");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
for (Map.Entry<String, String> e : map) {
System.out.println(String.format("%s - %s", e.getKey(), e.getValue()));
}
}
}
如果您运行此代码,您将得到它:
λ > java SortedMapExample
Amit - Java
Anupam - Hibernate
Nitin - PHP
Ravi - .Net
Saral - Andriod
hj - Spring1
ty - Spring
使用ConcurrentSkipListMap
ConcurrentSkipListMap是一种较新的数据结构,首先在 Java 6 中可用。它还实现了SortedMap
接口,底层实现涉及跳过列表。
它也是一个并发集合,您可以在Brian Goetz 的这篇文章中了解更多信息。简而言之, Java 并发集合java.util.concurrent
是高性能的线程安全集合。
将前面的示例更改为使用ConcurrentSkipListMap
.
import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentSkipListMap; // this changed
public class SortedMapExample {
public static void main(String[] args) {
// the following line changed - now you know the power of programming to interfaces
SortedMap<String, String> map = new ConcurrentSkipListMap<String, String>();
map.put("Amit","Java");
map.put("Saral","J2EE");
map.put("ty","Spring");
map.put("Anupam","Hibernate");
map.put("Ravi",".Net");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
for (Map.Entry<String, String> e : map) {
System.out.println(String.format("%s - %s", e.getKey(), e.getValue()));
}
}
}
运行此代码,您将获得完全相同的输出:
λ > java SortedMapExample
Amit - Java
Anupam - Hibernate
Nitin - PHP
Ravi - .Net
Saral - Andriod
hj - Spring1
ty - Spring
按需排序
也许在您的用例中,您不希望始终保持数据排序。也许这是一个性能问题(如果这是您关心的问题,请进行基准测试),并且您实际上只需要在请求时对数据进行排序。
在您的情况下,您可以在Collections.sort
数据键上使用。
坚持你的HashMap
例子:
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
public class UnsortedExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("Amit", "Java");
map.put("Saral","J2EE");
map.put("ty","Spring");
map.put("Anupam","Hibernate");
map.put("Ravi",".Net");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys);
for (String key : keys) {
System.out.println(String.format("%s - %s", key, map.get(key)));
}
}
}
在这里,我keySet()
从地图中提取了 ,它返回了一个Set
包含地图中所有键的对象。然后我把它变成一个ArrayList
并排序列表,然后遍历列表并将值从地图中提取出来。
java.util.TreeSet
拔出来的时候也可以用keySet()
,和和TreeSet
自然一样是有序TreeMap
的ConcurrentSkipListMap
。
使用示例SortedSet
:
java.util.SortedSet<String> keys = new java.util.TreeSet<String>(map.keySet());
顺便说一句,还有一个java.util.concurrent.ConcurrentHashMap
类,它是 Java Concurrency 版本,java.util.HashMap
并且在将发生并发访问的多线程环境中运行良好。
哇哇,为什么排序很奇怪?
此示例使用英语(我对“排序”的非英语语言了解不多),但您可以看到排序有些奇怪。
例如,在前面示例的输出中,"hj"
出现在 之后"Saral"
,而人类可能会真正按字母顺序排列列表,例如"hj"
介于"Anupam"
和之间"Nitin"
。
默认情况下,java.lang.String
实现Comparable
接口,定义自然排序。Java 与几乎所有其他正在使用的编程语言一样,将大写英文字母排在小写字母之前。
简单的解释是,在 ASCII/UTF-8 中,英文大写字母排在英文小写字母之前。
但是,您可能需要忽略大小写的不同字母排序。为此,您必须编写自己的实现类Comparator
,并将其传递给 or 的构造函数,TreeMap
或传递ConcurrentSkipListMap
给Collections.sort
采用比较器对象的方法。
如果你想实现这样的排序,我会把它作为练习留给你。
结论
从表面上看,您的问题只是对您的Map
-like 对象中的数据进行排序。
您可以选择使用:
java.util.TreeMap
- 按自然顺序保持元素排序
java.util.concurrent.ConcurrentSkipListMap
- 与上面相同,但具有良好的线程安全性
- 使用按需排序
Collections.sort()
我不知道你对这个数据结构有什么用,或者它在什么环境中使用。例如,如果你的 有多线程访问HashMap
,那么你需要同步机制,而同步机制HashMap
本身没有。为此,它更容易使用java.util.concurrent.ConcurrentSkipListMap
or java.util.concurrent.ConcurrentHashmap
。
因此,根据您使用数据的方式,有不同的方法可以对数据进行排序。如果您想要始终排序,那么我建议您使用ConcurrentSkipListMap
(for multithreaded) 或TreeMap
. 如果您需要HashMap
分期 O(1) 的插入性能,那么您可能需要使用HashMap
和排序“按需”方式,或者保留一个单独的数据结构来排序您的键。如果您对特定用途有性能问题,请进行分析。
还有一些额外的细节:
- 我正在使用每个循环来遍历我上面的数据结构。如果您只需要元素访问(而不是突变/删除),那么 for-each 是显式迭代器的非常好的语法糖。
- 在我的示例中,我使用接口作为变量的类型,而不是具体的类(在您的代码中,您有
HashMap<...> map = new HashMap<...>();
.