在分段随机实践—模拟线上流量一文中,我将流量模型统计成为一个个​Map<F, Integer>​​形式数据保存起来。

由于​​HashMap​​本身是无序的,我希望能够按照各个流量模型的​​value​​值进行排序输出,所以我又开始了学习​​Java​​的短暂旅途。

没想到除了java一行代码打印心形以外,又发现了一行代码。

LinkedHashMap

我自己最常用的​​HashMap​​。HashMap是一种非常常见、非常有用的集合,但在多线程情况下使用不当会有线程安全问题。

所以通常情况下只要不涉及线程安全问题,​​Map​​基本都可以使用HashMap,不过​​HashMap​​本身是一个无序的,不会记录每一个​​Entry​​数据插入的次序。

​LinkedHashMap​​就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,​​LinkedHashMap​​保证了元素迭代的顺序。

基础写法

这是一个比较基础的写法,思路是先将​​HashMap​换成​​List<Map.Entry>​​数据,然后使用​​Collections.sort​​方法进行排序,然后重新添加到​​LinkedHashMap​​集合对象当中。

public class Map_FunTester extends SourceCode {

public static void main(String[] args) {
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("fun", 3);
hashMap.put("funtest", 7);
hashMap.put("funtester", 9);
hashMap.put("f", 1);
output(hashMap);
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(hashMap.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o1.getValue() - o2.getValue();
}
});
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
for (Map.Entry<String, Integer> entry : list) {
linkedHashMap.put(entry.getKey(), entry.getValue());
}
output(linkedHashMap);
}

}

复制代码

控制台输出:

INFO-> 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO->
+-----------+---+
| f | 1 |
| funtest | 7 |
| funtester | 9 |
| fun | 3 |
+-----------+---+
INFO->
+-----------+---+
| f | 1 |
| fun | 3 |
| funtest | 7 |
| funtester | 9 |
+-----------+---+

Process finished with exit code 0
复制代码

Lambda写法

其实这个功能完全可以使用​​Lambda​​写法来简化整个过程。如下:

LinkedHashMap<String, Integer> linkedHashMap = hashMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1 + v2, LinkedHashMap::new));
output(linkedHashMap);
复制代码

哈哈,又是一行代码创造的奇迹。

这个​​Lambda​​写法的重点就在于​​Collectors.toMap​​,​​Collectors.toMap​​有三个重载方法:

toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper);
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction);
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);
复制代码

其中四个参数解释如下:


  1. keyMapper:Key 的映射函数
  2. valueMapper:Value 的映射函数
  3. mergeFunction:当 Key 冲突时,调用的合并方法
  4. mapSupplier:Map 构造器,在需要返回特定的 Map 时使用

虽然从​​HashMap​​获取​​keys​​的时候不会出现重复,但是最后一个参数是​​mapSupplier​​,必须使用​​toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);​​这个构造方法。

控制台输出:

如上
复制代码

适用拓展

​Collectors.toMap​​最常用的地方还说将​​List​换成​​Map​​数据常用。例子如下:

public static void main(String[] args) {
List<String> list = Arrays.asList("f", "fun", "funtest", "funtester");
Map<String, Integer> collect = list.stream().collect(Collectors.toMap(f -> f, f -> f.length(), (v1, v2) -> v2));
output(collect);
}
复制代码

控制台输出:

INFO-> 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO->
+-----------+---+
| f | 1 |
| funtest | 7 |
| funtester | 9 |
| fun | 3 |
+-----------+---+

Process finished with exit code 0

复制代码

Have Fun ~ Tester !

FunTester,腾讯云年度作者、Boss直聘签约作者,GDevOps官方合作媒体,非著名测试开发,欢迎关注。