在 lambda 表达式内部访问外部 hashmap 是合适的操作吗?

2020-03-30 23:12:07 +08:00
 1oNflow

比如我使用优先队列给一批数据排序(存在 map 里的 k-v 对),先比较 k 大小,如果相同再比较 v 大小,所以直接在 lambda 里

(a, b)->{
if (a.equals(b)) return map.get(a)-map.get(b);
return a.compareTo(b);
}

访问外部的 map,没有做修改所以编译器没有报错,但是不知道这么做有没有什么隐患,有更好的方法吗?

2375 次点击
所在节点    Java
10 条回复
arjen
2020-03-30 23:37:11 +08:00
lambda 会隐式让调用的外面容器变成 final 的。
arjen
2020-03-30 23:39:57 +08:00
如果想达到排序的目的用 TreeMap ?
mazai
2020-03-30 23:42:29 +08:00
函数表达式里面涉及到的所有都应该是无状态的,所以不要存有侥幸心理。
1194129822
2020-03-31 00:08:27 +08:00
很明显并没有任何隐患,和 java 只有值传递一样,java 只有值捕获,lambda 还是匿名对象都一样,在 lambad 里别说使用对象,就是修改对象的值也是正常操作,只要注意 lamdba 有没有在另外线程执行如果在另外线程执行注意所捕获使用的对象是不是线程安全就好了,想想 list. forEach 里修改 bean 不是很正常操作。而你的功能是什么,选用什么方法实现,就是你自己的事了。stream api 学会了绝对让你爽翻起飞
zzl22100048
2020-03-31 00:12:33 +08:00
直接 stream 操作 hashmap
rosu
2020-03-31 08:11:55 +08:00
可以考虑匿名内部类引用外部类属性的场景。虽然 lambda 和匿名内部类不一样,lambda 是一个闭包,但这不影响引用外部属性的这个场景。

这个引用会让该属性必须使用 final 修饰,因为防止你在闭包内进行修改。同理,你对集合进行修改,需要考虑线程安全问题(也就是闭包内启用另一个线程对 map 进行修改,在 Android 上,你还要考虑闭包内持有 ctx 导致的内存泄漏的问题)。

另一个角度是函数尽量无状态。不要引用超过函数生命周期的变量,这样会使逻辑清晰很多,知道输入就知道输出。

所以 stream api 还是香的。
siweipancc
2020-03-31 08:38:16 +08:00
你可以试试 String 的 threadLocal,能做到类似无状态就行了
LudwigWS
2020-03-31 10:18:29 +08:00
我觉得没有。另外向楼上各位学习了。
aguesuka
2020-03-31 12:45:14 +08:00
没有隐患,如果是给 map 排序可以直接用这个 public <K extends Comparable<K>,V extends Comparable<V>> List<K> sortKey(Map<K, V> map, int maxSize){
return map.entrySet().stream()
.sorted(mapComparator())
.limit(maxSize)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
private <K extends Comparable<K>,V extends Comparable<V>> Comparator<Map.Entry<K, V>> mapComparator(){
return Map.Entry.<K,V>comparingByKey()
.thenComparing(Map.Entry.comparingByValue());
}
Aresxue
2020-03-31 15:23:20 +08:00
不涉及修改就不会有问题。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/657759

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX