Properly implementing comparable and generics - java

I am struggling to understand how to implement generics and comparable into my code. I am tasked with converting the method below to proper generic methods. I also need to switch out the parameters with proper generics.
public static String min(String a, String b) {
if (a < b)
return a;
else
return b;
}
public static String max(String a, String b) {
if (a < b)
return b;
else
return a;
}
And this is my attempt
public static <AnyType> min(<AnyType> a, <AnyType> b) {
if (a < b)
return a;
else
return b;
}
public static <AnyType> max(<AnyType> a, <AnyType> b) {
if (a < b)
return b;
else
return a;
}

You have to ensure that AnyType is comparable.
public static <AnyType extends Comparable<AnyType>> AnyType min(AnyType a, AnyType b) {
return a.compareTo(b) < 0 ? a : b;
}
public static <AnyType extends Comparable<AnyType>> AnyType max(AnyType a, AnyType b) {
return a.compareTo(b) > 0 ? a : b;
}

You are not going to be able to write a single compareTo method that will work for any type. But, you can write a min and max that will work on any type that properly implements Comparable.
Comparable is a Java interface. It has a method compareTo, which contains no code. Using it requires a compareTo method be implemented for each class that uses it.
Use of the Comparable interface looks something like this:
public class Foo implements Comparable<Foo> {
That requires, somewhere in class Foo, this:
public int compareTo (Foo someFoo) { ... }
Where ... is replaced by code specific to Foo.
Then, a class that needs to compare two variables of type Foo might have code like this:
Foo bar = new Foo();
Foo bin = new Foo();
...
if (bar.compareTo(bin) < 0) { ...
If there were another class that implements Comparable, that class would also need a compareTo method specific to that class.
You could write generic min and max methods that would work on several classes, as long as those classes implement Comparable. The <T extends Comparable<T>> enforces that.
public static <T extends Comparable<T>> T min (T a, T b) {
if (a.compareTo(b) <= 0) return a;
return b;
}
public static <T extends Comparable<T>> T max (T a, T b) {
if (a.compareTo(b) >= 0) return a;
return b;
}
However, generics are not necessary in this case. Java allows the name of an interface to be used as a type:
public static Comparable min (Comparable a, Comparable b) {
if (a.compareTo(b) <= 0) return a;
return b;
}
public static Comparable max (Comparable a, Comparable b) {
if (a.compareTo(b) >= 0) return a;
return b;
}

Related

Are java comparators Type-aware?

I wanted a simple way to create a Comparator object based on any given Comparable class, so I coded the ComparatorCreator object, which I believed would look at the type of its generic and return the proper Comparator object that I could use to compare objects of that type. So I wrote the following code to test my idea. my belief would be that since the BackwardsInt class' compareto method is a reversed Comparator, it should be able to compare any two numbers in reverse order. But as it went through the statements, it completely ignored the reversal when it was comparing two ints, and even threw an error. I want to know why this is happening. The comparator I created seems to be aware of the type of the Number I'm passing in its arguments.
(I also got really into bounded wildcards a while back, so if that caused the problem, then oops).
import java.util.Comparator;
public class what {
public static void main(String[] ignoreme)
{
Comparator comp = new ComparatorCreator<BackwardsInt>().getComparator();
//comp should represent a Comparator<Number> which redirects to BackwardsInt.compareTo
int big=6;
int small=2;
BackwardsInt bbig=new BackwardsInt(6);
BackwardsInt bsmall=new BackwardsInt(2);
System.out.println(comp.compare(bbig, bsmall));//prints -1 good
System.out.println(comp.compare(bbig, small));//prints -1 good
System.out.println(comp.compare(big, small));//prints 1 why?
System.out.println(comp.compare(big, bsmall));//throws error?!?
}
private static class ComparatorCreator<T extends Comparable<? super T>>{
public Comparator<? extends T> getComparator()
{
return T::compareTo;
}
}
private static class BackwardsInt extends Number implements Comparable<Number>{
private int val;
public BackwardsInt(int v)
{
val=v;
}
#Override
public int compareTo(Number o) {
double d = o.doubleValue()-val;
if(d>0)
return 1;
if(d<0)
return -1;
return 0;
}
public int intValue() {
return val;
}
public long longValue() {
return val;
}
public float floatValue() {
return val;
}
public double doubleValue() {
return val;
}
}
}
Lets look at your ComponentCreator
private static class ComparatorCreator<T extends Comparable<? super T>>{
public Comparator<? extends T> getComparator()
{
return T::compareTo;
}
}
If have slightly changed it to make your mistake more clear
private static class ComparatorCreator<T extends Comparable<? super T>>{
public Comparator<? extends T> getComparator()
{
return (o1, o2) -> {
return o1.compareTo(o2);
};
}
}
The method reference you used is the same as the lambda I have but it makes the mistake more obvious. If we check your samples one by one we can see the following:
comp.compare(bbig, bsmall); // calls bbig.compareTo(bsmall)
comp.compare(bbig, small); // calls bbig.compareTo(small)
comp.compare(big, small); // calls big.compareTo(small)
comp.compare(big, bsmall); // calls big.compareTo(bsmal)
The output you received makes sense because big.compareTo() will call the compareTo() function of the Integer class.

Combining varargs and generics for chained comparisons in Java

Here's a tough nut to crack. I have a clash between using varargs and generics together. Following given code:
public class MyObject implements Comparable<MyObject>
{
private String name;
private int index;
#Override
public int compareTo(MyObject o)
{
if (name.compareTo(o.name) != 0)
return name.compareTo(o.name);
return ((Integer) index).compareTo(o.index);
}
}
I want the compareTo method to use more than one compare condition. If the strings are the same then use the ints instead. Usual situation I would say.
I would love to create a static method to handle this in general. And I want the new method chainedCompare to be called like this:
public int compareTo(MyObject o)
{
return chainedCompare(this, o, myO -> myO.name, myO -> myO.index);
}
The lambdas are varargs of the Java 8 interface Function. So first I wrote the method like that:
public static <T, C extends Comparable<C>> int chainedCompare(T object1, T object2, Function<T, C>... comparisons)
{
int compareValue = 0;
for (Function<T, C> comparison : comparisons)
{
compareValue = comparison.apply(object1).compareTo(comparison.apply(object2));
if (compareValue != 0)
break;
}
return compareValue;
}
But I didn't consider that in this case the generic type C must be the same type for all Function<T, C> comparisons in the varargs array. As you can see above, I want to use different Comparables (like String and Integer in the example).
Then I modified it to this version:
public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable<?>>... comparisons)
{
int compareValue = 0;
for (Function<T, ? extends Comparable<?>> comparison : comparisons)
{
compareValue = comparison.apply(object1).compareTo(comparison.apply(object2));
if (compareValue != 0)
break;
}
return compareValue;
}
Type C is here replaced with wildcards. While the method call would work now, the method itself does not compile, because of the wildcard typed parameter of compareTo.
So on the one hand I need a fixed generic type (extends Comparable) for the Function interface, but on the other hand I need Function interfaces of different (second) generic types where you usually could set a wildcard. How to resolve this?
My only requirement is that I can call the static method as simple as shown with an undefined number of comparison conditions.
Based on the suggestions of Tunaki I was able to modify the method as follows which can be used like desired:
#SuppressWarnings("raw-types")
public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable>... comparisons)
{
return Arrays.stream(comparisons)
.map(Comparator::comparing)
.reduce(Comparator::thenComparing)
.map(c -> c.compare(object1, object2))
.orElse(0);
}
public int compareTo(MyObject o)
{
return chainedCompare(this, o, myO -> myO.name, myO -> myO.index);
}
Instead of using a Comparable, it would be easier to use a Comparator:
public static <T> int chainedCompare(T object1, T object2, Comparator<T>... comparators) {
int compareValue = 0;
for (Comparator<? super T> comparator : comparators) {
compareValue = comparator.compare(object1, object2);
if (compareValue != 0)
break;
}
return compareValue;
}
You could also chain all the comparator together using thenComparing and have
#SafeVarargs
public static <T> int chainedCompare(T object1, T object2, Comparator<T>... comparators) {
return Arrays.stream(comparators)
.reduce(Comparator::thenComparing)
.map(c -> c.compare(object1, object2))
.orElse(0);
}
Then you can use that by constructing Comparator objects with comparing(keyExtractor) or the primitive specialization comparingInt.
#Override
public int compareTo(MyObject o) {
return chainedCompare(this, o,
Comparator.comparing(obj -> obj.name),
Comparator.comparingInt(obj -> obj.index)
);
}
With this approach, you can even question the existence of such utility and simply have
#Override
public int compareTo(MyObject o) {
return Comparator.<MyObject, String> comparing(obj -> obj.name)
.thenComparingInt(obj -> obj.index)
.compare(this, o);
}

Overriding a method with more parameters in java?

I have a base class with a method called execute :
class A {
public execute(int a){}
}
I also have a class B, which extends A, but the execute method needs more parameters:
Currently, my solution is using optional parameters :
class B extends A {
public execute(int a, Object... parameters){
long b = (long)parameters[0];
boolean c = (boolean)parameters[1];
....
}
}
This would still be ugly because I must cast on parameters. Are there other options for this situation?
you can add an execute(int a, int b) in B, but it won't override the execute(int a) method, it will overload it. Both method will be callable on an instance of B.
This would break the OO paradigm. The L in solid stands for Liskov substitution principle.
The principle applied for you example is that B should behave as A.
A better solution would be to injects those parameters via the constructor and have an execute without any parameters.
class A {
int a;
public A(int a){
this.a = a;
}
public execute(){ // do something with a}
}
class B {
int a;
long b;
boolean c;
public B (int a, long b, boolean c) {
this.a = a;
this.b = b;
this.c = c;
}
public execute(){ // do something with a, b and c}
}

Why is it considered bad practice to define a covariant compareTo method?

Here's an example from my code:
Baseclass:
abstract class AbstractBase implements Comparable<AbstractBase> {
private int a;
private int b;
public int compareTo(AbstractBase other) {
// compare using a and b
}
}
Implementation:
class Impl extends AbstractBase {
private int c;
public int compareTo(Impl other) {
// compare using a, b and c with c having higher impact than b in AbstractBase
}
FindBugs reports this as an issue. But why is that? What could happen?
And how would I correctly implement a solution?
Impl#compareTo(Impl) is not overriding AbstractBase#compareTo(AbstractBase) since they don't have the same signature. In other words, it won't be called when using Collections#sort for example.
EDIT: Added solution without casting
If you don't want to cast you could try the following.
Alter your baseclass to:
abstract class AbstractBase<T extends AbstractBase<?>> implements Comparable<T> {
//...
public int compareTo(T other) {
//...
}
}
And you Impl class to:
class Impl extends AbstractBase<Impl> {
//...
#Override
public int compareTo(Impl other) {
//...
}
}
Solution with casting:
A possible solution would be to override the compareTo(AbstractBase) method in the Impl class and explicitly check if an instance of Impl is passed in:
class Impl extends AbstractBase {
//...
#Override
public int compareTo(AbstractBase other) {
if (other instanceof Impl) {
int compC = Integer.compare(c, ((Impl) other).c);
if (compC == 0) {
return super.compareTo(other);
}
return compC;
}
return super.compareTo(other);
}
}
The following is something that I tried. Not exactly sure this is the reason why findbugs gives the error.
See the following code with a hypothetical implementation of the compareTo method.
Comparing the same objects results in different outputs.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints -2
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return (a + b) - (other.a + other.b);
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
public int compareTo(Impl other)
{
return super.compareTo(other) + (c - other.c);
}
}
Building on my hypothetical compareTo, following seems to be a good solution. You can try to have a method similar to getSum which gives the object instance a value.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints 0
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return getSum() - other.getSum();
}
public int getSum()
{
return a + b;
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
#Override
public int getSum()
{
return super.getSum() + c;
}
}
As sp00m said, your Impl#compareTo(Impl) has a different signature than AbstractBase#compareTo(AbstractBase), so it's not overloading it.
The key point is in understanding why it doesn't work, even when you try to sort() comparing with another Impl, where the more specific signature do matches.
As you defined Comparable<AbstractBase>, you need to define how your
instances compareTo AbstractBase instances. And so you need to implement compareTo(AbstractBase).
You can think that, being Impl a subtype of AbstractBase, the more specific method would be used when a comparison between two Impls takes place. The problem is Java has static binding, and so the compiler defines at compile time which method would use for solving each method call. If what you were doing was sorting AbstractBases, then the compiler would use the compareTo(AbstractBase), that is the one AbstractBase's interface define when it implements the Comparable(AbstractBase) interface.
You can make Impl implement the Comparable<Impl> interface for using the compareTo(Impl) method, but that would only work if you explicitly sort things that are known to be Impls at compile time (ie, an Impl object or Collection<Impl>).
If you really want to apply a different comparison whenever your two objects are Impls, you should fall to some kind of double-dispatch in your Impl#compareTo(AbstractBase) like:
Impl >>>
int compareTo(AbstractBase other) {
return other.compareToImpl(this);
}
int compareToImpl(Impl other) {
// perform custom comparison between Impl's
}
AbstractBase >>>
int compareTo(AbstractBase other) {
// generic comparison
}
int compareToImpl(Impl other) {
// comparison between an AbstractBase and an Impl.
//Probably could just "return this.compareTo(other);", but check for loops :)
}
This requires you add some Impl information in your AbstractBase, which is not pretty, though, but solves the problem the more elegant way it could - using reflection for this is not elegant at all.
The Liskov substitution principle (http://en.wikipedia.org/wiki/Liskov_substitution_principle) states: if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.)
In your case, you are overriding the compareTo method from the Base class in a way that breaks the behaviour of the original method. This is probably why FindBugs has an issue with it.
If you want to be proper about it:
abstract class AbstractBase {
}
class Impl1 extends AbstractBase implements Comparable<Impl1> ...
class Impl2 extends AbstractBase implements Comparable<Impl2> ...
OR
even better, do not use the Comparable interface at all - use a Comparator at sort time instead.
However, in real life there are situations where you need to get around it (maybe you don't have access to the source of AbstractBase, or maybe your new class is just a POC). In these special cases, I would go with the "ugly" cast solution proposed by John.

Generic type extending Number, calculations

I've made an interface of math operation with one method, calculate, taking various number of arguments
public interface MathOperation {
public <T extends Number> T calculate(T... args);
}
There's also simple implementation of this class, which does not work:
private class Sum implements MathOperation {
#Override
public <T extends Number> T calculate(T... args) {
return args[0] + args[1];
}
}
The problem is:
bad operand types for binary operator '+'
first type: T
second type: T
where T is a type-variable:
T extends Number declared in method <T>calculate(T...)
What I'm trying to achieve is a simple class, taking for example two Doubles and returning Double as well.
Is there possibility to achieve this?
+ cannot be applied to types that extend Number. new Integer(5) + new Integer(5) works because of autoboxing. You will have to look at the runtime type of args and do the operation accordingly.
Something on the lines of:
private class Sum implements MathOperation {
#Override
public <T extends Number> T calculate(Class<T> clazz, T... args) {
if (clazz.equals(Integer.class))
{
return Integer.class.cast(args[0]) + Integer.class.cast(args[1]);
} else (....)
}
}
For Addition we can use doubleValue() method of Number class. To return the same type value, the idea is to use a Function or Supplier or a Factory to create instances of the type T.
class MathOperation<T extends Number> {
public double add(T a, T b) {
double d = a.doubleValue() + b.doubleValue();
return d;
}
public T add(T a, T b, Function<Double,T> function) {
double d = a.doubleValue() + b.doubleValue();
return function.apply(d);
}
}
You can test the runtime type as shown in the other answers. Or you can try a different design: Create an abstract class that works as a factory:
interface MathContext<T extends Number> {
...
T valueOf(double d);
T valueOf(int i);
T add (T... args);
}
And concrete classes for the types that you want to use:
DoubleContext implements MathContext<Double> {
...
Double valueOf(int i) {
return i;
}
Double valueOf(double d) {
return d;
}
Double add(Double... args) {
Double res = 0;
for (Double arg: args) {
res += arg;
}
return res;
}
}
Now you could implement your MathOperation using that class. However, it's not really needed any more.

Categories