0

Is it possible to make a method that uses an object as a parameter, but doesn't specify exactly what type of object will be passed? The method would try to use the compareTo method that most objects have.

Also, is it possible to check if an object has a compareTo method, and throw an exception if it doesn't?

  • use generics with a constraint. – Ousmane D. Jan 26 '18 at 16:43
  • You're looking for interfaces. – SLaks Jan 26 '18 at 16:43
  • 2
    You want a method that takes a `Comparable>` as a parameter. – OH GOD SPIDERS Jan 26 '18 at 16:44
  • there is an interface for Comparable, just use that and you will not have to check – John Kane Jan 26 '18 at 16:45
  • but if you need to pass any `Object` to that method that not necessarily `implements Comparable` check argument with `instanceof`. If it has `compareTo()` but is not `Comparable` reflection can be used to check that. – pirho Jan 26 '18 at 16:49
  • I would be using this for, say, a sorting method where a user would input an array of objects, and it would sort them, but without having to make a new sorting method everytime I use a new array of objects. – Peregrine Lennert Jan 26 '18 at 16:53
  • @PeregrineLennert: So long as all of the objects you want to sort implement `Comparable`, [you don't have to do anything](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#sort-java.util.List-); they all fall into their natural order. – Makoto Jan 26 '18 at 16:54
  • Are all of the objects of the same type? – phflack Jan 26 '18 at 16:57
  • Yes @phflack, all of the objects would be the same type – Peregrine Lennert Jan 26 '18 at 16:58

4 Answers4

1

The only thing you need your objects to do is to implement the Comparable interface. Java will ensure that anything you're passing in would be type-safe at compile time, meaning you don't have to throw any kind of runtime exception.

From there, you may leverage any of the standard sort methods from Java:

(Note that with Arrays.sort, it expects an Object[], but will throw an exception if the contract of Comparable is violated.)

Makoto
  • 104,088
  • 27
  • 192
  • 230
0

From your description, it sounds to me like what you're asking for is to use casting:

/**
 * @param  lhs
 * @param  rhs
 * @return the result of comparing lhs to rhs via compareTo
 * @throws NullPointerException
 *         if lhs or rhs is null
 * @throws ClassCastException
 *         if lhs or rhs does not implement Comparable or
 *         if lhs and rhs are not mutually comparable
 * @see    Comparable#compareTo(Object)
 */
@SuppressWarnings({"rawtypes", "unchecked"})
private static int compareByCasting(Object lhs, Object rhs) {
    Comparable compL = (Comparable) lhs;
    Comparable compR = (Comparable) rhs;
    return compL.compareTo(compR);
}

This is how methods like Arrays.sort work behind the scenes.

That said, it's very rarely necessary to write code like that, unless you're writing very low-level API like in the case of Arrays.sort. Java has static typing, so in general the goal is to program towards pushing type checks to compile-time so we don't have to run the program to verify that it's correct. That's why we use tools like interfaces and generics.

Radiodef
  • 37,180
  • 14
  • 90
  • 125
-1

a generic custom method with a constraint like below should enable you to compare objects that implement the generic Comparable interface, therefore, removing the need to take a parameter of type Object and then ensuring it has a compareTo method somehow.

public <T extends Comparable<T>> int comparer(T thiss, T that){
       // do logic
}
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
-1

sorting method [...] an array of objects

If all of these objects are the same type and implement comparable, you can use generics

Note that if they are not similarly typed, you'll need to write a custom method to compare
(ie Integer and String comparison)

private <A extends Comparable<A>> void bigger(A a, A b)
{
    if(a.compareTo(b) > 0)
        System.out.println("a bigger");
    else
        System.out.println("b bigger");
}

Do note that this will only work for same typed objects

//works
String a = "5";
String b = "6";
bigger(a, b);

//compile error
Integer c = 5;
String d = "6";
bigger(c, d);

This works for things that implement Comparable

On custom objects, it's normally straightforward to implement

class Duck implements Comparable<Duck>
{
    private int height;
    [...]
    public int compareTo(Duck other)
    {
        return height - other.height;
    }
}

The cool thing about this, is most of the sorting bits of the Java API are built to handle Comparable


If you do not know that they are Comparables and stuck keeping everything as Objects, then you are most likely stuck using Reflection

int compare(Object a, Object b) throws NoSuchMethodException, IllegalAccessException, java.lang.reflect.InvocationTargetException
{
    return (Integer)a.getClass().getMethod("compareTo", b.getClass()).invoke(a, b);
}
phflack
  • 2,729
  • 1
  • 9
  • 21
  • Would there be a way to just check if there's a method named `compareTo`? I know that I can just implement `Comparable`, but it would be nice if I could just check for the specific method instead. – Peregrine Lennert Jan 26 '18 at 17:09
  • @PeregrineLennert It won't be pretty, and would most likely require [Reflection](https://stackoverflow.com/q/37628/5475891). It's much more recommended to use interfaces like Comparable – phflack Jan 26 '18 at 17:11
  • Ok, I was just wondering, but I can see that it would be easier to use `Comparable` than it would be to check for the method specifically. – Peregrine Lennert Jan 26 '18 at 17:15
  • But would I be able to create a method that takes an object, without specifying the type of object? – Peregrine Lennert Jan 26 '18 at 17:19
  • @PeregrineLennert What kind of objects do you plan on throwing at it without errors? You need to look for the lowest common thing that they share and use that. If literally the only thing they have in common is they extend Object, it will be much more difficult to do something useful with them – phflack Jan 26 '18 at 17:23
  • I plan on using this for a method that would sort an array of objects, but as I stated before, I want to only make one, and have it be able to sort any objects passed through it with the `compareTo` method. – Peregrine Lennert Jan 26 '18 at 17:26
  • @PeregrineLennert Also note that in your question you say it should only work for objects implementing compareTo _(which also implement Comparable)_. Do you want to shift the compile error to a runtime error? – phflack Jan 26 '18 at 17:27
  • I honestly don't know why I put in that line. Anyways, how would one write a static method if it's going to receive multiple types of objects (but only one at a time)? – Peregrine Lennert Jan 26 '18 at 17:35
  • @PeregrineLennert *"Would there be a way to just check if there's a method named compareTo?"* You're asking about duck typing and we don't have that/don't do that in Java. In Java we put the method in an interface and implement the interface. – Radiodef Jan 26 '18 at 17:45
  • @PeregrineLennert Added a method that will work for any Objects that have a `compareTo` method – phflack Jan 26 '18 at 17:55
  • 1
    I take grave offense at your use of reflection. This is *not* a case in which this even makes remote sense. If your objects aren't comparable, there's no point in trying to sort them since there is no order to base their sorting on. Additionally, your code will just throw `NoSuchMethodException` ***unless*** they implement `Comparable`. This is just plain wrong. – Makoto Jan 26 '18 at 20:51
  • @Makoto I agree that reflection shouldn't be the way to go. But there may be the rare case that the array is of class `A`, with `int A.compareTo(A)` defined without `A` implementing Comparable _(despite following the interface)_. Personally I'd much prefer only taking Comparables, and if need be cast as Comparables, but OP seems rather insistent that it's an array of Objects that are not Comparables – phflack Jan 26 '18 at 20:57
  • 1
    If code managed to make its way into the code base that *kind of* implemented `Comparable` but wasn't really `Comparable`, the two tools I have at my disposal are `git annotate` and where that person's desk is. Having to do a hack like this *completely* undermines the point of generics. – Makoto Jan 26 '18 at 20:59
  • Also note for the Reflection portion, if `a` and `b` are different classes, `b.compareTo(a)` should also be attempted _(OP specified they are of the same type)_ – phflack Jan 26 '18 at 20:59