-1

I have an array of Appointment objects that I would like to sort based on a few field.

Appointment class with overridden compareTo

public class Appointment implements Comparable<Appointment>{
    
    String month;
    String day;
    int hour;
    int minute;
    String description;

    // constructor, getters and setters omitted to emphasize Comparable implementation

    @Override
    public int compareTo(Appointment other){
        
        if (this.month.compareTo(other.month) == 0){
            return 0;
        } else if (this.month.compareTo(other.month) > 0){
            return 1;
        } else if (this.month.compareTo(other.month) < 0){
            return -1;
        }
        
        
        if (this.day.compareTo(other.day) == 0){
            return 0;
        } else if (this.day.compareTo(other.day) > 0){
            return 1;
        } else if (this.day.compareTo(other.day) < 0){
            return -1;
        }
        
        
        if (this.hour == other.hour){
            return 0;
        } else if (this.hour > other.hour){
            return 1;
        } else if (this.hour < other.hour){
            return -1;
        }
        
        
        if (this.minute == other.minute){
            return 0;
        } else if (this.minute > other.minute){
            return 1;
        } else if (this.minute < other.minute){
            return -1;
        }
        
        return 0;
    }
}

Issue

In my main class, named Calendar, I create and save a number of Appointment objects to the array bookings.

However I cannot sort the list with the compareTo method I defined.

Collections.sort(bookings, new Appointment());

This gives me the error:

No suitable method found for sort(object[],Appointment)

Any idea how I could solve this?

hc_dev
  • 5,553
  • 20
  • 27
  • 1
    Remove the `new Appointment()` argument, just `Collections.sort(bookings);` – Progman May 29 '22 at 18:32
  • 4
    Why is `bookings` an array of objects? By the way, you need to pass a `List`, nothing else, since `Appointment` is a `Comparable`. – Federico klez Culloca May 29 '22 at 18:36
  • 3
    Look at the Javadoc for [`Collections`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Collections.html#sort(java.util.List)) - notice how `sort(...)` requires a `List` of the relevant type (`T`), not an array of objects. – andrewJames May 29 '22 at 18:39
  • It may also help to take a look at [When should a class be Comparable and/or Comparator?](https://stackoverflow.com/q/1440134/12567365) – andrewJames May 29 '22 at 18:47
  • 2
    Your comparer logic is wrong. Your execution path will never get past that first if-else block. – Robert Harvey May 29 '22 at 18:49
  • Also take a look at [java.time.MonthDay](https://docs.oracle.com/javase/8/docs/api/java/time/MonthDay.html) and [java.time.LocalTime](https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html) or better yet at [java.time.LocalDateTime](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html). Your `compareTo` method would just call the `compareTo` of the corresponding `LocalDateTime`s – Valerij Dobler May 29 '22 at 19:01
  • 1
    We don't know what bookings is, but we do know it is not a List. You could try, `Collections.sort( Arrays.asList( bookings) )` if bookings is an array of Appointment's. More likely, you should store your appointments in a list to begin with. – matt May 29 '22 at 19:24
  • 1
    For sorting an array you may alternatively use `Arrays.sort(bookings);` – Ole V.V. May 30 '22 at 04:04

1 Answers1

0

Read also this intro on DZone Java: Java Comparable Interface in Five Minutes

Using the Collections.sort method

To use a class implementing Comparable in Collections.sort(List<T> comparables) method like:

// class Appointment implements Comparable 
Appointment[] arrayOfAppointments = createAppointments(); // sample of appointments
// we need a list for Collections.sort
List<Appointment> appointments = Arrays.asList(arrayOfAppointments); 

// sort them based on Comparable implementation 
Collections.sort(appointments); // no second argument (specific Comparator) needed

You have correctly implemented the interface Comparable with its method compareTo in your class.

At least you need a list or array of Appointment objects which implement Comparable.

Use the Arrays.asList method as matt suggested as bridge:

This method acts as bridge between array-based and collection-based APIs, in combination with Collection.toArray().

There are two things to notice when applying the method sort on a List:

  1. The list must be mutable, because ..

    The specified list must be modifiable, but need not be resizable.

  2. The method has no return (void), it modifies and sorts it in-place.

Sorting objects composed by other comparables

Instead of re-implementing the 3 sort-results like for example on month:

        if (this.month.compareTo(other.month) == 0) {
            return 0;
        } else if (this.month.compareTo(other.month) > 0){
            return 1;
        } else if (this.month.compareTo(other.month) < 0){
            return -1;
        }

you can simply benefit from comparable Integers:

// If typed String: "April" is before "February" alphabetically but not chronologically!
Integer month; // we can compare ordered month-numbers easily

// later
@Override
public int compareTo(Appointment other) {
    // What if other is null, or one of its fields or components ?
    // What if they are equal? Shouldn't we compare on the next (day) then ?!
    return this.month.compareTo(other.month);
    
    // next components are compared in the following

    return 0;  // default result: objects are equal ?!
}

Potential logical bugs in your sorting-logic (also commented in code above):

  1. early returns (e.g. for equal months) if not fully compared to the minor temporals (e.g. differ only in minute)
  2. default return states that objects are equal
  3. no null-check on other or its components (may cause NPE)

Why not using date/time classes?

It gets even easier if the date of an appointment is stored as such, using java.util.Date or any date-class of new Java Date/Time API. So you can compare the dates entirely, without bothering for details of month, day, hour, minute.

hc_dev
  • 5,553
  • 20
  • 27
  • 1
    How is this answer relevant to OP's question? They're passing two arguments to Collections.sort neither of which is a List that needs to be sorted. – matt May 29 '22 at 19:22
  • The [method with second argument](https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator)) is obsolete. To solve it (question) and use the implemented `compareTo` method (question) we don't need a specific `Comparator` - just a `List` of `Comparable`s. – hc_dev May 29 '22 at 19:28
  • No, `Collections.sort` that takes a second argument is not "obsolete". You're right that the OP doesn't need it. The problem is they get an error "No suitable method found for sort(object[],Appointment)" because they are not passing a **List** to Collections.sort. How does your answer help them address that issue? – matt May 29 '22 at 19:42
  • @matt, Agree partly. The method itself is not "obsolete", it has its merits to sort lists which do not implement `Comparable` (see the case of `null` as second argument). What I meant with "obsolete" is: (a) not needed, (b) incorrectly used, (c) not suitable for the given case. Thanks to you comment which I incorporated, I hope my answer addresses most issues now. Otherwise we could reopen the question to have your answer added. – hc_dev May 29 '22 at 20:03