Java中TreeSet无法删除自定义Edificio对象问题求助
问题分析与解决方案
你遇到的TreeSet无法删除元素的问题,主要有两个核心原因:遍历删除的方式错误,以及Edificio类的compareTo方法实现不符合TreeSet的底层逻辑。下面一步步给你拆解问题并提供修复方案:
1. 遍历删除时误用集合的remove方法,而非迭代器的remove
在使用迭代器遍历集合时,直接调用alberobello.remove(edificio)会触发集合的fail-fast机制,导致迭代器失效——不仅可能抛出ConcurrentModificationException异常,还会让删除操作无法正确执行。
正确的做法是使用迭代器自带的remove()方法,这是遍历过程中修改集合的唯一安全方式。
2. Edificio的compareTo方法实现错误,破坏了TreeSet的元素判断逻辑
TreeSet是基于自然排序(通过compareTo方法)来管理元素的,它判断两个元素是否相等的依据是compareTo返回0,而非equals方法。你的compareTo存在两个严重问题:
- 注释掉了
distanza相等时返回0的逻辑,导致两个distanza相同的元素会被TreeSet判定为“互小于”,违反了排序的对称性,造成内部存储结构混乱; - 没有处理类型校验,且泛型使用不规范,容易引发类型转换错误;
- 甚至连
this.compareTo(this)都会返回-1,违反了排序的自反性,彻底打乱TreeSet的内部逻辑。
另外,你实现的Iterable接口完全无效(迭代器永远没有下一个元素),属于冗余代码,建议直接移除。
修复后的完整代码
修复demolish方法
private void demolish(int y, String p) { // 使用带泛型的迭代器,避免强制类型转换 Iterator<Edificio> iterator = alberobello.iterator(); while (iterator.hasNext()) { Edificio edificio = iterator.next(); if (edificio.getPinodeipalazzi().equals(p) && edificio.getAnno() == y) { // 使用迭代器的remove方法安全删除当前元素 iterator.remove(); dimension--; System.out.println("Removed: " + edificio.getPinodeipalazzi() + " " + edificio.getAnno() + " " + alberobello.size()); // 如果只需要删除第一个匹配的元素,可在此处添加break终止循环 // break; } } }
修复Edificio类
// 正确使用Comparable泛型,避免强制类型转换和类型错误 public class Edificio implements Comparable<Edificio> { private int anno; private String pinodeipalazzi; private String lato; private int distanza; private int base; private int altezza; public Edificio(int y, String p, String l, int d, int b, int h) { this.anno = y; this.pinodeipalazzi = p; this.lato = l; this.distanza = d; this.base = b; this.altezza = h; } // 保留所有getter方法 public int getAltezza() { return altezza; } public int getAnno() { return anno; } public int getBase() { return base; } public int getDistanza() { return distanza; } public String getLato() { return lato; } public String getPinodeipalazzi() { return pinodeipalazzi; } @Override public int compareTo(Edificio o) { // 先判断对象是否为null if (o == null) { return 1; } // 按distanza升序排序,相等时返回0,符合排序规范 Integer thisDistanza = this.distanza; Integer otherDistanza = o.distanza; int distanzaCompare = thisDistanza.compareTo(otherDistanza); // 如果需要更复杂的排序逻辑(比如distanza相同时按anno排序),可以扩展: // if (distanzaCompare != 0) { // return distanzaCompare; // } // return Integer.compare(this.anno, o.anno); return distanzaCompare; } // 建议同时重写equals和hashCode,保持与compareTo的一致性 // 虽然TreeSet主要依赖compareTo,但其他场景(如HashSet、对象相等判断)会用到这两个方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Edificio edificio = (Edificio) o; return anno == edificio.anno && distanza == edificio.distanza && base == edificio.base && altezza == edificio.altezza && pinodeipalazzi.equals(edificio.pinodeipalazzi) && lato.equals(edificio.lato); } @Override public int hashCode() { return Objects.hash(anno, pinodeipalazzi, lato, distanza, base, altezza); } }
额外建议
你手动维护的dimension变量其实是多余的,TreeSet自带的size()方法可以直接返回集合中的元素数量,完全不需要手动增减,这样能避免因操作失误导致的dimension与实际大小不一致的问题。建议直接移除dimension变量,所有需要用到它的地方替换成alberobello.size()。
内容的提问来源于stack exchange,提问作者Sab Biuzzino
相关产品推荐
相关产品推荐

