Метод сравнения (compareTo) возвращает разные результаты в разных JVM - PullRequest
0 голосов
/ 08 января 2019

Я озадачен: я написал компаратор, который сравнивает даты. Однако, когда я запускаю тест junit, он возвращает разные результаты в зависимости от того, запускаю ли я его в своей IDE или в maven ?! В моей IDE это работает, а в Maven это не удается. Использование одного и того же 1.8 jvm в обеих средах, однако в maven с режимом совместимости 1.6. (Обратите внимание, что это устаревший проект и использование java.util.date плохо ... (но сейчас это не главное)

Вот вывод из IDE (правильный): Birthday [id=four, time=Thu Sep 23 20:54:24 CEST 2010] Birthday [id=six, time=Wed Feb 01 01:01:01 CET 2012] Birthday [id=five, time=Wed Feb 01 01:01:02 CET 2012] Birthday [id=three, time=Tue Jan 08 17:30:43 CET 2019] Birthday [id=one, ] Birthday [id=two, ]

А вот вывод из maven (не правильно): Birthday [id=four, time=Thu Sep 23 20:54:24 CEST 2010] Birthday [id=three, time=Tue Jan 08 17:26:25 CET 2019] Birthday [id=five, time=Wed Feb 01 01:01:02 CET 2012] Birthday [id=six, time=Wed Feb 01 01:01:01 CET 2012] Birthday [id=one, ] Birthday [id=two, ]

Вот код (запустите его в 1.8 для успеха, 1.6 для отказа):

import java.util.Date;

public class Birthday implements Comparable<Birthday>{

    private String id;
    private Date time;

    public String getId() {
        return this.id;
    }
    public Birthday(String id, Date time) {
        this.id=id;
        this.time=time;
    }
    public Date getTime() {
        return this.time;
    }
    public void setTime(Date time) {
        this.time = time;
    }
    @Override
    public int compareTo(Birthday o) {   
        //if both are null return 0 for equals
        if(this.time==null && o.getTime()==null) {
            return 0;
        }

        //null birthdays should always be last
        if(this.time==null) {
            return 1;
        }
        if(o.getTime() == null) {
            return -1;            
        }
        return this.time.before(o.getTime()) ? 0 : 1;
    }

    @Override
    public String toString() {
        return this.id+" "+this.time;
    }
}

@Test
public void testTime() {
    Birthday info1 = new Birthday("one",null);
    Birthday info2 = new Birthday("two", null);
    Birthday info3 = new Birthday("three",new Date());
    Birthday info4 = new Birthday("four",new Date(110,8,23,20,54,24));
    Birthday info5 = new Birthday("five",new Date(112,1,1,1,1,2));
    Birthday info6 = new Birthday("six",new Date(112,1,1,1,1,1));

    ArrayList<Birthday> dates = new ArrayList<Birthday>();
    dates.add(info1);
    dates.add(info2);
    dates.add(info4);
    dates.add(info3);
    dates.add(info5);
    dates.add(info6);

    Collections.sort(dates);

    for(Birthday bs: dates) {
        System.out.println(bs);
    }

    Assert.assertEquals(info4, dates.get(0));
    Assert.assertEquals(info6, dates.get(1));
    Assert.assertEquals(info7, dates.get(2));
    Assert.assertEquals(info5, dates.get(3));
    Assert.assertEquals(info3, dates.get(4));
    Assert.assertEquals(info1, dates.get(5));
    Assert.assertEquals(info2, dates.get(6));
}

Что происходит ??

Ответы [ 4 ]

0 голосов
/ 08 января 2019

Как уже отмечали другие, проблема в последней строке метода compareTo.

Поскольку Date реализует Comparable, самое простое исправление:

return this.time.compareTo(o.getTime());
0 голосов
/ 08 января 2019

Ваш compareTo() метод некорректен. В случае, если время ни одного объекта не равно null, оно сводится к

        return this.time.before(o.getTime()) ? 0 : 1;

а что если o.time.before(this.getTime())? Ваш compareTo() должен надежно возвращать -1 в этом случае, но вместо этого он возвращает 0. java.util.Date имеет естественный порядок, который вы могли бы также использовать, если в первую очередь полагаетесь на этот класс:

        return this.time.compareTo(o.getTime());
0 голосов
/ 08 января 2019

Я думаю, что нашел проблему: Компаратор вернул 0 (указывает на равенство), что неверно:

Должно быть return this.time.before(o.getTime()) ? -1 : 1;

вместо return this.time.before(o.getTime()) ? 0 : 1;

И, как указал Джон, еще лучше:

return this.time.compareTo(o.getTime());

И java изменил алгоритм сортировки в JDK 1.7, который, вероятно, по-разному обрабатывает одинаковые значения. Так что все собрались вместе в этом интересном загадочном деле ...

0 голосов
/ 08 января 2019

Проблема в этой строке:

return this.time.before(o.getTime()) ? 0 : 1;

если время этих предметов раньше времени других, они равны. Это не рефлексивно, поэтому вы нарушаете требования для сравнения.

В разных реализациях JVM могут использоваться разные алгоритмы сортировки, где одна будет демонстрировать эту ошибку, а другая нет

...