在分段随机实践—模拟线上流量一文中,我将流量模型统计成为一个个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.16INFO-> +-----------+---+| 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(Functionsuper 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);
其中四个参数解释如下:
- keyMapper:Key 的映射函数
- valueMapper:Value 的映射函数
- mergeFunction:当 Key 冲突时,调用的合并方法
- 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.16INFO-> +-----------+---+| f | 1 || funtest | 7 || funtester | 9 || fun | 3 |+-----------+---+
Process finished with exit code 0
❝「Have Fun ~ FunTester !」
❞