java HashSet 删除重复项但 TreeSet 不删除?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14864488/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 17:40:10  来源:igfitidea点击:

HashSet removes duplicates but TreeSet does not?

javahashsettreeset

提问by blue-sky

Output of below class is : size is 3 size is 1

以下类的输出是:大小为 3 大小为 1

But if I change the TreeSet to a HashSet so line :

但是,如果我将 TreeSet 更改为 HashSet 所以行:

Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();

becomes

变成

Set<SuggestionDetailBean> set = new HashSet<SuggestionDetailBean>();

the output is : size is 3 size is 2

输出为:大小为 3 大小为 2

Shout using HashSet or TreeSet not change the size of Set ? Using HashSet seems to behave as expected because it is removing duplicates but when I use TreeSet the duplicates remain ? I think the hashcode and equals methods in SuggestionDetailBean are overriden correctly ?

大喊使用 HashSet 或 TreeSet 不会改变 Set 的大小?使用 HashSet 似乎表现得如预期,因为它正在删除重复项,但是当我使用 TreeSet 时,重复项仍然存在?我认为 SuggestionDetailBean 中的 hashcode 和 equals 方法被正确覆盖了?

Here is the code :

这是代码:

public class TestSet {

    public static void main(String args[]){

        SuggestionDetailBean s = new SuggestionDetailBean();
        s.setTagList("teddst");
        s.setUrl("testurl");

        SuggestionDetailBean s2 = new SuggestionDetailBean();
        s2.setTagList("teddst");
        s2.setUrl("testurl");

        SuggestionDetailBean s3 = new SuggestionDetailBean();
        s3.setTagList("tessdafat");
        s3.setUrl("fdfaasdfredtestur ldd");

        List<SuggestionDetailBean> list = new ArrayList<SuggestionDetailBean>();
        list.add(s);
        list.add(s2);
        list.add(s3);

        Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
        set.addAll(list);

        System.out.println("size is "+list.size());
        System.out.println("size is "+set.size());

    }

}

public class SuggestionDetailBean implements Comparable<Object> {

    private String url;
    private String tagList;
    private String numberOfRecommendations;
    private String date;
    private String time;
    private String summary;
    private String truncatedUrl;


    public void setTruncatedUrl(String truncatedUrl) {

        if(truncatedUrl.length() > 20){
            truncatedUrl = truncatedUrl.substring(0, 20)+"...";
        }

        this.truncatedUrl = truncatedUrl;
    }

    public String getSummary() {
        if(summary == null){
            return "";
        }
        else {
            return summary;
        }
    }

    public void setSummary(String summary) {
        this.summary = summary;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }


        public String getTime() {
            return time;
        }

        public String getTruncatedUrl() {
            return this.truncatedUrl;
        }

        public void setTime(String time) {
            this.time = time;
        }

        public String getTagList() {
            if(tagList == null){
                return "";
            }
            else {
                return tagList;
            }
        }

        public void setTagList(String tagList) {
            this.tagList = tagList;
        }


        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getNumberOfRecommendations() {
            return numberOfRecommendations;
        }

        public void setNumberOfRecommendations(String numberOfRecommendations) {
            this.numberOfRecommendations = numberOfRecommendations;
        }

        @Override
        public int compareTo(Object o) {

            DateFormat formatter;
            Date date1 = null;
            Date date2 = null;  
            SuggestionDetailBean other = (SuggestionDetailBean) o;

            if(this.date == null || other.date == null){
                return 0;
            }   
            formatter = new SimpleDateFormat(SimpleDateFormatEnum.DATE.getSdfType()+" "+SimpleDateFormatEnum.TIME.getSdfType());
            try {
                date1 = (Date) formatter.parse(this.date + " " + this.time);
                date2 = (Date) formatter.parse(other.date + " " + other.time);
            } catch (ParseException e) {
                System.out.println("Exception thrown in"+this.getClass().getName()+", compareTo method");
                e.printStackTrace();
            }
            catch(NullPointerException npe){
                System.out.println("Exception thrown "+npe.getMessage()+" date1 is "+date1+" date2 is "+date2);
            }

             return date2.compareTo(date1);

        }

        @Override
           public int hashCode() {
                return this.url.hashCode();
            }

        @Override
        public boolean equals(Object obj) {

            SuggestionDetailBean suggestionDetailBean = (SuggestionDetailBean) obj;

            if(StringUtils.isEmpty(this.getTagList())){
                return this.getUrl().equals(suggestionDetailBean.getUrl());
            }
            else {
                return (this.getTagList().equals(suggestionDetailBean.getTagList())) &&
                        (this.getUrl().equals(suggestionDetailBean.getUrl()));
            }

        }

    }

Edit : Note : if I convert the hashset to a treeset using :

编辑:注意:如果我使用以下方法将哈希集转换为树集:

 Set<SuggestionDetailBean> sortedSet = new TreeSet<SuggestionDetailBean>(hashset);

Then correct sorting is maintained, as the removal of duplicates is based on the object hashcode and equals methods not the compareto method.

然后保持正确的排序,因为重复项的删除是基于对象哈希码和等于方法而不是 compareto 方法。

回答by ruakh

According to the Javadoc for TreeSet:

根据Javadoc 对于TreeSet

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equalsif it is to correctly implement the Setinterface. (See Comparableor Comparatorfor a precise definition of consistent with equals.) This is so because the Setinterface is defined in terms of the equalsoperation, but a TreeSetinstance performs all element comparisons using its compareTo(or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set iswell-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Setinterface.

请注意,如果要正确实现接口,则集合维护的排序(无论是否提供显式比较器)必须与 equals 一致Set。(请参阅ComparableComparator以获取与 equals 一致的精确定义。)之所以如此,是因为Set接口是根据equals操作定义的,但TreeSet实例使用其compareTo(or compare) 方法执行所有元素比较,因此被 this 视为相等的两个元素从集合的角度来看,方法是相等的。集合的行为 明确定义的,即使它的顺序与 equals 不一致;它只是不遵守一般合同Set界面。

So, the problem is with your compareTomethod: either it's giving inconsistent results, or else it's giving consistent results that don't obey the rule that a.compareTo(b) == 0if and only if a.equals(b).

所以,问题出在你的compareTo方法上:要么给出不一致的结果,要么给出不遵守规则的一致结果,a.compareTo(b) == 0当且仅当a.equals(b).

For example, this bit:

例如,这一点:

            if(this.date == null || other.date == null){
                return 0;
            }   

means "if either thisor otherhas date == null, then report that thisand otherare equal", which is certainly not what you want.

意思是“如果有this或者otherdate == null,那么报告那个thisother是相等的”,这当然不是你想要的。