7

For objects a and b implementing the Comparable interface I want to avoid having code like

if (a.compareTo(b) > 0) {
    ...
}

instead, I am looking for helper methods like

if (a.isGreaterThan(b)) {
    ...
}

This would help me a lot for not always having to look up the definition of the return value of compareTo(T o):

Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

Really helpful would be 5 different methods:

Instead of                  use potential helper method:

a.compareTo(b) < 0          a.isLessThan(b)
a.compareTo(b) <= 0         a.isLessOrEqualTo(b)
a.compareTo(b) == 0         a.isEqualTo(b)
a.compareTo(b) >= 0         a.isGreaterOrEqualTo(b)
a.compareTo(b) > 0          a.isGreaterThan(b)

Are there any helper methods like this in the JDK or other libraries that provide this kind of functionality?

DEX
  • 95
  • 1
  • 7
  • You do realise that the methods you need to write will simply call compareTo ? Something like this `boolean isLessThan(Comparable a, T b){ return a.compareTo(b) < 0; }` (probably not correct, juste write this without check, but a static generic method should do it – AxelH Oct 24 '16 at 11:52
  • 2
    This is more error prone than it looks, you know that `<` always does the same thing as defaulted by the JLS but `isLessThan` in a library could do anything unless you check what is does exactly. Why fill your head with all the oddities of different libraries instead of using plain Java? – Peter Lawrey Oct 24 '16 at 11:54
  • Yes, AxelH, the implementation would be no more than this. But these methods would contribute a lot for readability and clean code purposes, because it would hide what < 0, > 0, ... means. – DEX Oct 24 '16 at 11:57
  • 1
    +1 for Plain Java, looks like newbies want to use library for everything, I use almost none in my project (almost ;) ). Java is already heavy, don't add some library just to remove one simple condition. – AxelH Oct 24 '16 at 11:58
  • @DEX, I prefer to see a simple `> 0` instead of isGreaterThan, this is too verbose ;) Plus, you would need to call a static method or define those into a super class, not always possible. So, I don't found that much more readable. – AxelH Oct 24 '16 at 11:59
  • OK, but say I define `Double.NaN > 0` and `-0.0 < 0.0` differently for `Double.compareTo` you won't know that unless you read the code, now you have know more than you did. – Peter Lawrey Oct 24 '16 at 11:59
  • readabilty is only improved if you know that "less than" means the same to you as the person who wrote it. – Peter Lawrey Oct 24 '16 at 12:01
  • Peter Lawrey: if the helper methods work on Comparables they don't do much more than the JavaDoc already says at the moment: "... as this object is less than, equal to, or greater than the specified object". Only the readability for the developer would increase. I don't see errors arising from this. My question is whether there are such methods already available in the plain JDK. – DEX Oct 24 '16 at 12:01
  • Why would you assume it uses `Double.compareTo(a, b) < 0` rather than `a < b` ? The problem is it's not obvious unless you write what you mean in which case you may as well use the plain Java code. For this reason it's generally a bad idea to replace a short piece of Java code with a library method because it's error prone. If such a library does exist I would strong suggest you avoid it. – Peter Lawrey Oct 24 '16 at 12:04
  • 1
    @Peter Lawrey I would assume it uses the compareTo(T o) method because the methods will only operate on Comparables. How e.g. the "isLessThan(T o)" is implemented is still the same as it always was in the compareTo(T o) method. I prefer having code that tells the story directly, rather than having to look up what compareTo() > 0 means. – DEX Oct 24 '16 at 19:36
  • @DEX I agree, having to look up what a method means is a real pain, and having a method which just calls another method means you now have to look up two methods. This is why I suggest sticking with the standard methods where you at least know what they do. Note: `<` and `compareTo < 0` don't do the same thing in all cases so you may need to know which one it is. It also means there is no standard definition of what `is less than` should do. – Peter Lawrey Oct 25 '16 at 10:14
  • @PeterLawrey In my opinion you wouldn't even have to look up one method, because the name of the method says it all. If the `isLessThan` method is defined on a Comparable I don't see any way of misinterpreting or having to look up logic. – DEX Oct 26 '16 at 22:54
  • @PeterLawrey: 2 more questions just for my understanding: 1. Is there any use case for `compareTo(T o)` without immediately checking for <, == or > 0? I think with my methods users would call the compareTo(T o) method very rarely. 2. Have you ever looked up what e.g. `SortedSet.last()` does in code? I mean, it's as self-explanatory as what I suggest. – DEX Oct 26 '16 at 23:03
  • @DEX you are proving my point because it doesn't say it all which is why it's dangerous to imply there is one way to do this which is what having one method suggests. As mentioned before compareTo and <, =, > don't do exactly the same thing. – Peter Lawrey Oct 27 '16 at 08:02
  • 2
    @PeterLawrey No, I am vehemently disagreeing with your point. Of course `<` means something different than `compareTo() < 0`, in the same way as `==` means something different than `equals()` (although `<` doesn't make sense on Objects anyway). In this case it comes down to what you implement in the `compareTo()` method. But as I said: If you operate on Comparables, it is patently obvious what `isLessThan` means. I would without hesitation suggest the default methods below for inclusion in the next JDK. – DEX Nov 16 '16 at 08:00
  • @DEX I can see what you are saying but you are making an assumption and it's assumptions which are often a cause of bugs. I would prefer to assume the JVM implements the JLS and assume my understanding is correct, neither is always true but that's already a lot to assume. Adding more assumptions on top of that just adds more possibilities for bugs and edge cases. – Peter Lawrey Nov 16 '16 at 08:48

2 Answers2

4

You do not need these methods if you'll remember, that it's just enough to have a mental substitution by carrying the compareTo argument to the right side of comparison as following:

a.compareTo(b) < 0    ---->   a[.compareTo(...)] < b

Since it's that simple, noone usually cares about having any better form of comparison in a library. If you still insist on some more readable form of expression, you can use default methods from Java 8 to extend Comparable interface as following:

public interface ComparableDSL<T> extends Comparable<T> {
    default boolean isLessThan(T that) { 
         return compareTo(that) < 0;
    }
}
Ivan Gammel
  • 652
  • 7
  • 17
3

The equals method exists for every object. The rest you would have to create yourself. You could create an interface that has these methods so all the children would have them.

This should work:

public interface IComparable<T> extends Comparable<T> {

    boolean isLessThan(T other);

    boolean isLessOrEqualTo(T other);

    boolean isGreaterOrEqualTo(T other);

    boolean isGreaterThan(T other);

}

You could add default methods for each of the above methods. Like so:

public interface IComparable<T> extends Comparable<T> {

    default boolean isLessThan(T other) {
        return compareTo(other) < 0;
    }

    default boolean isLessOrEqualTo(T other) {
        return compareTo(other) <= 0;
    }

    default boolean isGreaterOrEqualTo(T other) {
        return compareTo(other) >= 0;
    }

    default boolean isGreaterThan(T other) {
        return compareTo(other) > 0;
    }

}
DEX
  • 95
  • 1
  • 7
nick zoum
  • 7,216
  • 7
  • 36
  • 80
  • you could add `default` methods for each of these ;) – Peter Lawrey Oct 24 '16 at 11:56
  • 1
    @PeterLawrey Edited the answer. – nick zoum Oct 24 '16 at 11:59
  • This would be my idea, but this needs heritage, since Java only allows one super class, this could lead to more complexity. PS : default could be in interface since Java 8, removing this problem ;) – AxelH Oct 24 '16 at 12:02
  • @AxelH I know that is why I also added the option of having an Interface instead. – nick zoum Oct 24 '16 at 12:04
  • See this, for Java 8, to use only the interface : https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html You will only need to implements the interface (no implementation of code needed :) ) That's what Java used to help with Diamond heritance (well I guess) – AxelH Oct 24 '16 at 12:05
  • @AxelH Is this better? – nick zoum Oct 24 '16 at 12:10
  • 1
    I believe this was @PeterLawrey 's idea ;) this has the advantage to be more flexible, if a want a class to be an Observable and IComparable, I can with this one :) – AxelH Oct 24 '16 at 12:13
  • Thanks for this very good implementation suggestion, although it doesn't fully answer my question. So obviously there is no helper method available in the JDK and I have to implement something myself. – DEX Oct 24 '16 at 13:35
  • @DEX Why doesn't it answer your question? – nick zoum Oct 24 '16 at 14:56
  • @nick zoum because I was looking for an implementation in the JDK or any other library so I could use it on plain (maybe external) Comparable implementations without implementing an own logic. – DEX Oct 24 '16 at 19:25
  • @DEX So since the implementation doesn't already exist. Is there an answer that you would accept as correct? – nick zoum Oct 24 '16 at 21:09
  • @nick zoum Yes, the answer you just gave: There aren't any implementations already available ;) – DEX Oct 24 '16 at 21:18
  • 1
    The assumption `(x.compareTo(y)==0) == (x.equals(y))` is wrong or must be stated explicitly by the interface. The JavaDoc of Comparable says: "It is strongly recommended, but not strictly required that `(x.compareTo(y)==0) == (x.equals(y))`." – Till Schäfer Feb 13 '18 at 20:12