2014-10-10 76 views
1

参见下面的2类,DTODTOWithOrderingTreeSet中比较器执行不一致

public class DTO { 
    private final String key; 
    private final long recordVersionNumber; 

    public DTO(String key) { 
     this.key = key; 
     this.recordVersionNumber = 0; 
    } 

    public DTO(String key, long recordVersionNumber) { 
     this.key = key; 
     this.recordVersionNumber = recordVersionNumber; 
    } 

    public String getKey() { 
     return key; 
    } 

    public long getRecordVersionNumber() { 
     return recordVersionNumber; 
    } 

    @Override 
    public String toString() { 
     return "Key: " + this.key + " Record Version Number: " + this.recordVersionNumber; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     DTO that = (DTO) o; 

     return Objects.equal(this.key, that.key) && 
       Objects.equal(this.recordVersionNumber, that.recordVersionNumber); 
    } 

    @Override 
    public int hashCode() { 
     return Objects.hashCode(key, recordVersionNumber); 
    } 

public class DTOWithOrdering extends DTO implements Comparable<DTOWithOrdering> { 

    public DTOWithOrdering(String key, long recordVersionNumber) { 
     super(key, recordVersionNumber); 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     DTOWithOrdering other = (DTOWithOrdering) o; 

     if(this.getKey().equals(other.getKey())) { 
      if(this.getRecordVersionNumber() == other.getRecordVersionNumber()) { 
       return true; 
      } else if(this.getRecordVersionNumber() <= other.getRecordVersionNumber()) { 
       return true; 
      } else { 
       return false; 
      } 
     } { 
      return false; 
     } 
    } 

    @Override 
    public int compareTo(DTOWithOrdering other) { 
     if(this.getKey().equals(other.getKey())) { 
      if(this.getRecordVersionNumber() == other.getRecordVersionNumber()) { 
       return 0; 
      } else if(this.getRecordVersionNumber() <= other.getRecordVersionNumber()) { 
       return 0; 
      } else { 
       return -1; 
      } 
     } { 
      return -1; 
     } 
    } 
} 

DTOWIthOrderingDTO延伸并覆盖equalscompareTo方法。

问题与下面的代码片段出现时,我创建了一个TreeSet<DTOWIthOrdering>并调用包含此

TreeSet<DTOWithOrdering> treeSet = new TreeSet<DTOWithOrdering>(keyAndVersionList); 
    List<DTO> results = new ArrayList<DTO>(); 
    for (DTO diff : diffs) { 
     if (treeSet.contains(new DTOWithOrdering(diff.getKey(), diff.getRecordVersionNumber())) == false) { 
      results.add(diff); 
     } 
    } 

当我运行此我的程序中,我可以看到TreeSet中包含2700+实体,其中之一有的0b3ae620-bbcf-347d-a9b4-87e6fd765cd7和4

然而recordVersionNumber一个键时,DIFF实体之一包含具有0

一个recordVersionNumber相同的密钥。当代码调用CONT ains方法,该集合返回false值。

奇怪的是,对于其他例子来说,在键集相同且记录版本号在TreeSet中更大的情况下,它将返回true!

我的逻辑在这里有什么问题吗?

+3

您在'DTOWithOrdering'方法中的'compareTo'看起来很奇怪,因为它永远不会返回'1'。你确定它确实是你想要的吗? – kraskevich 2014-10-10 19:24:32

+0

作为一个方面说明,这是一个很好的例子,其中'compareTo'的单元测试可能会识别和诊断错误。 – chrylis 2014-10-10 19:25:28

+0

它必须返回1吗?我承认这是一个效率低下的比较器,因为它实际上是一个列表,但这是否解释了为什么contains()返回false? – DJ180 2014-10-10 19:26:22

回答

3

下面是从一个的JavaDoc报价Comparable接口:

INT的compareTo(T O)

比较与指定对象此对象为顺序。返回 负整数,零或正整数,因为此对象比指定对象小 ,等于或大于此指定对象。实现者 必须为所有x和 确保sgn(x.compareTo(y))== -sgn(y.compareTo(x))。 (这意味着则x.compareTo(Y)如果 y.compareTo(X)抛出异常必须抛出异常。)

如果返回-1但从未返回1,物业
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))不能抱真。所以你实现这个方法不符合规范,TreeSet可能工作不正常。