Nelson Matias
Nelson Matias

Reputation: 473

Comparison method violates its general contract exception using date

I'm using a simple comparator below to sort by start time of a contest, but am getting the error "Comparison method violates its general contract" even though I Covered all the possibilities. Any help on what I'm missing?

    Collections.sort(contests, new Comparator<Contest>() {
        @Override
        public int compare(Contest o1, Contest o2) {
            if (o1.getStartTime() != null && o2.getStartTime() != null) {
                if (o1.getStartTime().getTime() < o2.getStartTime().getTime()) {
                    return -1;
                }
                return 1;
            } 
            return 1;
        }
    });

Upvotes: 1

Views: 276

Answers (2)

Stefan Mondelaers
Stefan Mondelaers

Reputation: 887

I don't see any case where it returns 0. And when looking further I see that the return value when 2 objects are compared wich have the same start times will be 1. And because of that the following rule of the contract is violated:

sgn(compare(x, y)) == -sgn(compare(y, x)) 

If x and y have the same start time. sgn(1) != -sgn(1). In that case the method has to return 0.

Upvotes: 2

Shafiul
Shafiul

Reputation: 1512

If you are running on Java 8, you can use:

List<Contest> sorted = contests.stream()
            .sorted(Comparator.comparing(contest -> contest.getStartTime().getTime(), Comparator.nullsFirst(Comparator.naturalOrder())))
            .collect(Collectors.toList());

Without knowing details about your startTime data type, assuming time mathematically comparable from your code, see below for code completeness. Adjust according to your need.

class Sorting {
    public static void main(String[] args) {
        List<Contest> contests = new ArrayList<>();

        contests.add(new Contest(new TimeHolder(1)));
        contests.add(new Contest(new TimeHolder(3)));
        contests.add(new Contest(new TimeHolder(2)));
        List<Contest> sorted = contests.stream()
            .sorted(Comparator.comparing(contest -> contest.getStartTime().getTime(), Comparator.nullsFirst(Comparator.naturalOrder())))
            .collect(Collectors.toList());

        sorted.forEach(contest -> System.out.println(contest.getStartTime().getTime()));
    }

    static class Contest {
        TimeHolder startTime;

        public Contest(TimeHolder startTime) {
            this.startTime = startTime;
        }

        public TimeHolder getStartTime() {
            return startTime;
        }
    }
    static class TimeHolder{
        int time;

        public TimeHolder(int time) {
            this.time = time;
        }

        public int getTime() {
            return time;
        }
    }
}

Output:

1
2
3

Upvotes: 0

Related Questions