Kotlin中MutableList存储Edibles对象时无法使用removeAll去重及元素频次统计问题
问题分析与解决方案
嘿,我来帮你梳理下问题和对应的解决思路:
1. 原代码失效的核心原因
- 相等性判断逻辑错误:Kotlin中普通自定义类的
==默认是基于对象引用的(和===效果一致)——也就是说,哪怕两个Edibles对象的name完全相同,只要是不同实例,it == order[0]就会返回false。这直接导致count统计结果错误,removeAll也找不到要移除的元素。 - 循环修改列表的风险:你在
for循环里直接修改原order列表(调用removeAll),这会破坏迭代器的正常遍历逻辑,很容易触发ConcurrentModificationException,或者导致元素被跳过。 - 对Collection接口的误解:你完全不需要让
Edibles实现Collection接口——这个接口是给容器类(比如List、Set)设计的,你的Edibles是单个物品类,和它没有任何关联。
2. 快速修复方案
第一步:让Edibles支持正确的相等判断
最简单的方式是把Edibles改成data class,Kotlin会自动帮你生成基于主构造函数属性的equals()、hashCode()方法,这样相同name(和price)的对象会被判定为相等:
data class Edibles(val name: String, val price: Double): Serializable { }
如果你的需求是「只要name相同就算同一种物品(不管price差异)」,可以手动重写equals()和hashCode(),只基于name判断:
class Edibles(val name: String, val price: Double): Serializable { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as Edibles return name == other.name } override fun hashCode(): Int { return name.hashCode() } }
第二步:用Kotlin标准库优雅统计次数
完全不需要手动循环修改列表,用groupBy就能轻松分组统计,代码简洁又安全:
// 按物品名称分组,统计每组的数量 val orderGroups = order.groupBy { it.name } // 转换成你需要的字符串格式 val totalOrder = orderGroups.entries.joinToString("\n") { "${it.value.size}x ${it.key}" }
这段代码会生成你想要的格式:
9x Juice 5x Steaks 4x Salads
如果需要按Edibles的完整属性(name+price)分组,直接用it作为分组键即可:
val orderGroups = order.groupBy { it } val totalOrder = orderGroups.entries.joinToString("\n") { "${it.value.size}x ${it.key.name}" }
3. 这个方案的优势
- 无副作用:不会修改原
order列表,避免了遍历过程中修改容器的风险。 - 代码简洁:利用Kotlin标准库函数,省去了手动计数、移除元素的繁琐逻辑。
- 性能更优:
groupBy只需要遍历列表一次,比原代码中每次循环都调用count(多次遍历)效率高很多。
内容的提问来源于stack exchange,提问作者lschwb
相关产品推荐
相关产品推荐

