Comparator (int) in inner class - java

I have some problem with comparator. I make very simple class with 2 fields and i need make inner classes with comparators for this two fields.
public class KlassA {
private int i;
private String tekst;
public int getI(){
return i;
This comparator works ok.
public static class KomparatorText implements Comparator<KlassA>{
public int compare(KlassA a1, KlassA a2) {
return a1.getTekst().compareTo(a2.getTekst());
}
}
In this comparator i have some issue: "Cannot invoke compareTo(int) on the primitive type int"
public static class KomparatorI implements Comparator<KlassA>{
public int compare(KlassA a1, KlassA a2) {
return a1.getI().compareTo(a2.getI());
}
}
I also try CompareTo but then i need to implements field or method and it's not work
public static class KomparatorI implements Comparable<KlassA>{
private int i = this.i;
public int compareTo(KlassA o) {
if (this.i < o.i)
return -1;
else if (this.getI() == o.getI())
return 0;
else
return 1;
}
}
}
I really don't know how to fix it. I'm already serach the other inquiries but all sollutions don't work for my example. Pls help.

You could force everything to Integers as in the other answers, but, IMO, better to keep your current class structure with ints and to use a built in method, Integer.compare()
public static class KomparatorI implements Comparator<KlassA>{
public int compare(KlassA a1, KlassA a2) {
return Integer.compare(a1.getI(), a2.getI());
}
}
Likewise, if you wish to use Comparable instead, use it to save typing (and avoid mistakes in the logic):
public static class KomparatorI implements Comparable<KlassA>{
public int compareTo(KlassA o) {
return Integer.compare(this.i, o.i);
}
}

In Java, primitive types like int, float, or boolean are not objects like the correspondent Integer, Float, or Boolean.This means you cannot call methods on them.
Try using,
Integer.valueOf(this.i).compareTo(o.i);
Your confusion probably comes from the fact that the compiler tries to covert primitive types to their corresponding object classes automatically. In the sample above this happens for the argument o.i, which is converted automatically to an Integer.
Try searching for "java autoboxing".
Note: You can actually use Integer.compare(this.i, o.i) which is better, for that case.

Lets see what you gout here
a1.getI().compareTo(a2.getI());
it looks like getI() returns int insteed of Integer.
Change mehod definition to return Integer insteed and all wil be fine. So inside your KlaasA
public Integer getI(){ return i};

Related

Use Object class to achieve polymorphism in math operations

I want to make good use of polymorphism in java when implementing math operations between objects of math classes.
I got from the answers in How to add two java.lang.Numbers?
that the general solution when using java.lang.Number is to know or check the real objects class and make the appropriate hardcoded conversion to float, int, etc.
But this approach actually is not very object oriented. The java language designers chose to give the java.lang.Number class and its derivatives a set of methods floatValue(), intValue() and so on.
In light of this, Is my proposed approach, below, not going to work?.
To implement mathematical operations in a seamless way I want to to rewrite the Number class Hierarchy to allow to do something like this:
MyNumber a = b.getValue() + c.getValue();
where the real type of b and c don't matter
The base class would be:
public abstract class MyNumber {
protected Object mValue;
public abstract <N> N getValue();
}
And, for example, my integer class would look like:
public class MyInteger extends MyNumber {
public MyInteger(int value) {
mValue = value;
}
#Override
public Integer getValue() {
return (Integer) mValue;
}
}
and similarly for MyFloat, MyDouble, etc.
It will not work with different types.
public class MyInteger extends MyNumber {
public MyInteger(int value) {
mValue = value;
}
#Override
public Integer getValue() {
return (Integer) mValue;
}
}
public class MyFloat extends MyNumber {
public MyFloat(float value) {
mValue = value;
}
#Override
public Float getValue() { // first issue: types don't match. can't override
return (float) mValue; // second issue: type won't match with other getValue methods, arithmetic will fail
}
}
Your problem is even before the arithmetic. You'll need to use generics, or some kind of type-resolving and/or type-converting mechanis to get past this issue.
Firstly, overriding methods need to have matching signatures, and Types are part of that signature.
Secondly, after having a single type, Java does not have operator overloading. Therefore you will need to implement a method that MyNumber has that can take your two Generic or high level Object's and do that type casting or conversion itself.

Java: Interface

I have been reading about interface in java. Overall I understood the concept except one problem. In http://goo.gl/l5r69 (docs.oracle), in the note it is written that we can type cast an interface and a class implementing it. That is
public interface Relatable {
public int isLargerThan (Relatable other) ;
}
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
// ...
// a method for computing the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect = (RectanglePlus) other;
if (this.getArea() < otherRect.getArea()) {
return -1;
} else if (this.getArea () > otherRect.getArea()) {
return 1;
} else {
return 0;
}
}
}
How can otherRect (which is a interface) be casted to a RectanglePlus. The confusion is, RectanglePlus is a class having variables, which are not present in the otherRect which is an interface
I have to admit that the example in the java doc you showed is simply bad and confusing.
It's bad because it contains an unsafe cast down the hierarchy.
It is always safe to cast up (from implementing class to interface/superclass), but casting down should be avoided when possible.
Ideally, the Relatable interface should also contain getArea() method:
public interface Relatable {
public int isLargerThan(Relatable other);
public int getArea();
}
Now you don't need the ugly cast, simply:
public int isLargerThan(Relatable other) {
if (this.getArea() < other.getArea()) {
return -1;
} else if (this.getArea () > other.getArea()) {
return 1;
} else {
return 0;
}
}
is enough. I also think that isLargerThan(Relatable other) is a bad name (larger in terms of what?). It should probably be something like hasBiggerArea(Relatable other) so that it explains what we are actually comparing (only "larger" is rather vogue).
Your interface is pretty similar to Comparable, (Are you sure Comparable isn't what your looking for?) so maybe you should add a generic to it:
public interface Relatable<T extends Relatable> {
public int isLargerThan(T t);
}
And then your class will start as:
public class RectanglePlus implements Relatable<RectanglePlus> {...
So your RectanglePlus instance will be compared with other RectanglesPlus elements only.
If this does not suit what you need, then you have to choose what will happen when you are comparing two different classes:
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
public int getArea() {
return width * height;
}
public int isLargerThan(Relatable other) {
if (!(other instanceof RectanglePlus)) {
return 1; // I'm bigger than any other class!
}
RectanglePlus otherRect =(RectanglePlus)other;
return this.getArea() - otherRect.getArea();
}
}
Or, a third option, you can add another method to your interface to obtain the measureable, realatable value of an object. Then you could add a default implementation to isLargerThan, if you are using Java 8:
public interface Relatable<T extends Relatable> {
public default int isLargerThan(T t) {
return this.getRelatableValue - t.getRelatableValue();
}
public int getRelatableValue();
}
In the method declaration public int isLargerThan(Relatable other){...} the parameter other is declared to be a reference to an object whose class implements the interface Relatable.
In the method body, the expression (RectanglePlus)other means to check that the object is of class RectanglePlus or a subclass of that (and throw a ClassCastException if it isn't). Now, a RectanglePlus is Relatable, but the inverse isn't necessarily true; the cast here ensures that other will either be RectanglePlus; if it's not further instructions will not be executed because an exception will have been thrown.
We can type cast any object(of class C) stored in a variable of type T1 (interface or class) into a variable of type T2 if T2 is a super class or super interface of class C or T2==C otherwise a ClassCastException will be thrown.
So in your case if an object obj of class Foo implements Relatable is passed to isLargerThan method then it will throw ClassCastException, because obj's class Foo is not a super class of RectanglePlus.
One aspect that hasn't been touched on in other answers is the fact that the example in the Oracle docs has a clear problem: if Relatable is only meant to be analogous to Comparable, then there needs to be a specialization for shapes in order to avoid the cast in the isLargerThan method. Perhaps, for example, an interface called RelatableShape, which itself extends Relatable, and provides for the getArea() method. Then, you could have Circle, Hexagon, Rectangle, etc. classes that implement RelatableShape (the interface with isLargerThan and getArea), and the isLargerThan() method would not need to cast its argument to a particular concrete class (since the parameter could be guaranteed to implement RelatableShape, and getArea() would always be available).
Thus, though the Oracle documentation is showing something that is valid Java, it's also showing something that's necessary because of a bad design. Keep that in mind. Casting is almost never necessary in real code.
It's rather simple your mehtod
public int isLargerThan(Relatable other)
just asks for an argument that implements Relatable. It could be an object of any class that implements Relatable. As long as there is something like
public class SomeName implements Relatable { /* Implementation */ }
in the class, you can treat objects of that class as Relatable.
But that does not mean that these objects are not of their own type. If you have the following classes
public class Square implements Relatable {
public int isLargerThan(Relatable other) {
// Implementation
}
// Square specific implementation
}
and
public class Rectangle implements Relatable {
public int isLargerThan(Relatable other) {
// implmentation
}
// Rectangle specific implemenation
}
you can call the interface methods like this:
/* ... */
public static int check(Relatable a, Relatable b) {
return a.isLargerThan(b);
}
/* ... */
Square s = new Square();
Rectangle r = new Rectangle();
System.out.println("Check: " + check(s, r));
ATTENTION:
Because several different classes can implement Relatable you have to check the type of the argument to isLargerThan, otherwise you run into type cast exceptions.
Maybe you can specify something like this in Relatable
public int getSize();
Than you could write your isLargeThan method like this:
public int isLargerThan(Relatable other) {
if (this.getSize() < other.getSize())
return -1;
else if (this.getSize() > other.getSize())
return 1;
else
return 0;
}
Then there would be no need for a type cast.

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.

Correct it so that it will compile and properly implement Comparable

Why won't the following program compile? Correct it so that it will compile and properly implement Comparable.
class Int implements Comparable
{
private int x;
public Int(int x)
{
this.x = x;
}
public int compareTo(Int other)
{
return x - other.x;
}
}
----//// im assuming that the compareTo method is wrong.. but i dont know why or how to fix it.
The interface Comparable is defined with a type parameter of <T>.
If one does not provide a generic type parameter to a class or interface that requires it, then the default type parameter is assumed to be Object.
So, in effect, your class declaration reads like this:
public class Int implements Comparable<Object>
Now, this is where things get interesting. compareTo(T other) takes the generic type parameter as its type argument. If you don't explicitly declare the type to be something, then the method signature reads compareTo(Object other).
Suffice to say, but Object and Int aren't the same object. When you attempt to declare your method as #Override, the compiler will inform you that your method doesn't inherit or implement anything.
Ultimately, what this boils down to: you have to fix your type parameter. If you want to compare against Int, explicitly declare it so:
public class Int implements Comparable<Int>
Now, your code will compile.
Replace:
class Int implements Comparable
With:
class Int implements Comparable<Int>
You need to specify what you're comparing to. If it's blank, then you need to compare Objects in compareTo().
Try This
public class Int implements Comparable<Int> {
private int x;
public Int(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
#Override
public int compareTo(Int other) {
return x-other.getX();
}
}

NullObjectPattern and the Comparable interface

The problem I'm having has already been asked before: How to implement an interface with an enum, where the interface extends Comparable?
However, none of the solutions solve my exact problem, which is this:
I have a value object, similar to BigDecimal. Sometimes this value will not be set with a real object, because that value is not yet known. So I want to use the Null Object Pattern to represent the times this object is not defined. This is all not a problem, until I try to make my Null Object implement the Comparable interface. Here's an SSCCE to illustrate:
public class ComparableEnumHarness {
public static interface Foo extends Comparable<Foo> {
int getValue();
}
public static class VerySimpleFoo implements Foo {
private final int value;
public VerySimpleFoo(int value) {
this.value = value;
}
#Override
public int compareTo(Foo f) {
return Integer.valueOf(value).compareTo(f.getValue());
}
#Override
public int getValue() {
return value;
}
}
// Error is in the following line:
// The interface Comparable cannot be implemented more than once with different arguments:
// Comparable<ComparableEnumHarness.NullFoo> and Comparable<ComparableEnumHarness.Foo>
public static enum NullFoo implements Foo {
INSTANCE;
#Override
public int compareTo(Foo f) {
return f == this ? 0 : -1; // NullFoo is less than everything except itself
}
#Override
public int getValue() {
return Integer.MIN_VALUE;
}
}
}
Other concerns:
In the real example, there are multiple subclasses of what I'm calling Foo here.
I could probably work around this by having NullFoo not be an enum, but then I can't guarantee there is ever only exactly one instance of it, i.e. Effective Java Item 3, pg. 17-18
I don't recommend the NullObject pattern because I always find myself in one of these 2 situations:
it does not make sense to use NullObject like an object, and it should stay null
NullObject has too much meaning to be just a NullObject, and should be a true object itself (for instance, when it acts like a fully functional default value)
According to our discussion in the comments, it seems to me that your NullObject behaves very much like the 0 value of your normal objects.
What I would do is actually use 0 (or whatever default value makes more sense), and put a flag if you really need to know whether it has been initialized. This way, you will have 2 things to consider:
all uninitialized values won't share the same instance with my solution
for the very same reason, you are now able to initialize your object later without having to create a new instance
Here is the kind of code I think of:
public static class VerySimpleFoo implements Foo {
private int value;
private boolean initialized;
public VerySimpleFoo() {
this.value = 0; // whatever default value makes more sense
this.initialized = false;
}
public VerySimpleFoo(int value) {
this.value = value;
this.initialized = true;
}
#Override
public int compareTo(Foo f) {
// possibly need some distinction here, depending on your default value
// and the behavior you expect
return Integer.valueOf(value).compareTo(f.getValue());
}
#Override
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
this.initialized = true;
}
public boolean isInitialized() {
return initialized;
}
}
As you suggested, I believe one solution would be to use a class instead of an enum:
public class NullFoo implements Foo {
private NullFoo() {
}
public static final Foo INSTANCE = new NullFoo();
#Override
public int compareTo(Foo f) {
return f == this ? 0 : -1;
}
#Override
public int getValue() {
return 0;
}
}
This mimics an enum behavior, but it allows you to implement your Foo interface. The class is not instantiable because of the private constructor, so the only instance available is the one accessible via NullFoo.INSTANCE, which is thread-safe (thanks to the final modifier).
The thing is that Enum already implements Comparable natively, and since the generics are just a sugar code, and lost after compilation, effectively you want to implement the same method twice for the same interface.
I would drop enum, for NullFoo, converting it to class (like you suggested), and make final public static INSTANCE reference with private constructor, (This is not as good as using an enum, but acceptable, in most cases).

Categories