How can I get an equals method with many constrants - java

I'm working on an equals method that will check to see if two points are equal. A single point consists of quantity and price where quantity is an integer and price is a double. I want the price to stop at the second decimal place which is why I have the TOLERANCE (it is set as 0.01). I am not sure how to get these constraints in the equals(). This is what I have right now:
public boolean equals (Point Other)
{
if((this.quantity == Other.quantity) && (Math.abs(this.price - Other.price)<TOLERANCE)) return true;
return false;
}
Say you have (q1,p1) and (q2,p2). I want to be able to use the equals() to see if:
If q1=q2 while p1=p2 or
If q1!=q2 while p1=p2 or
If q1=q2 while p1!=p2 or
If q1!=q2 while p1!=p2
Also in my TestPoint class when in test to see if the points are equal I want it to print out if:
The points are equal
The quantities are not equal, prices are equal
The quantities are equal, the prices are not equal
The points are not equal
Here is what I have now in my tester:
if (p1.equals(p2)) {
System.out.println("Points are equal");
} else {
System.out.println("Points are not equal");
}

One of the maxims that Joshua Bloch (Effective Java, 2nd Ed.) offers for overriding equals() in Java is the following (paraphrasing):
You shouldn't try to hard to demonstrate equivalence. For example,
for the File class, equals() should not take symbolic links into
account for demonstrating equivalence. Thankfully, it doesn't.
As was pointed out in the comments, your purpose is not to look for equality (rather, to look for nearness). You should not override the equals() method for this purpose and I just wanted to take a moment to point out the hazard of doing so in this case (because the signature of your method differs, I note that you aren't overriding equals, you're overloading it ... but still).
The contract for equals() from the Object class (the parent class for all objects in Java):
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
While the developer is free to refine this contract, he may not change it. The Collections framework, in particular, relies on this contract for correctness. If you define an equals() method that violates this contract, the Collections classes may fail in ways that can be difficult to debug.
Creating an equivalence test based on tolerances can violate the equals() contract because of loss of transitivity (the 3rd point in the contract).
To illustrate:
Say you wish to say that objects are equal if an integer field is within +/- 10 of another object's same field
myObject a = new myObject(1);
myObject b = new myObject(6);
myObject c = new myObject(11);
For these objects:
a.equals(b) evaluates to true
b.equals(c) evaluates to true
a.equals(c) evaluates to false
Transitivity is violated and thus the equals contract is broken. Defining an equals() method in this way will cause unpredictable behavior for any class that depends on the equals contract for its correctness. The Collections classes, in particular, will not function properly.

public boolean quantityEqualWith (Point other) {
if(this.quantity == other.quantity) return true;
return false;
}
public boolean priceEqualWith (Point other) {
if (Math.abs(this.price - other.price)<TOLERANCE) return true;
return false;
}
public boolean isEqual(Point other) {
if(this.priceEqualWith(other)&&this.quantityEqualWith(other)) return true;
return false;
}
public boolean isQuantityEqual (Point other) {
if((!this.priceEqualWith(other))&&(this.quantityEqualWith(other))) return true;
return false;
}
public boolean isPriceEqual (Point other) {
if((this.priceEqualWith(other))&&(!this.quantityEqualWith(other))) return true;
return false;
}
public boolean isNotEqual(Point other) {
if((!this.priceEqualWith(other))&&(!this.quantityEqualWith(other))) return true;
return false;
}
I don't recommend overriding equals(). However, if you insist, you should override hashcode() as well.

public int comparePriceQuantity(Point Other)
{
if((this.quantity == Other.quantity)){
if(Math.abs(this.price - Other.price)<TOLERANCE){
return 0; // return PQ_EQUAL;
else
return 2; // return Q_EQUAL_P_NOT_EQUAL
}
}
else{
if(Math.abs(this.price - Other.price)<TOLERANCE)
return 1; // return Q_NOT_EQUAL_P_EQUAL
else
return 3; //PQ_NOT_EQUAL
}
}
If q1=q2 while p1=p2 => 0
If q1!=q2 while p1=p2 =>1
If q1=q2 while p1!=p2 =>2
If q1!=q2 while p1!=p2 =>3
Note: Instead of using int, enum should be used for better readability and manageability of code.
enum declaration:
public enum PointTestValues{
QP_EQUAL,
Q_NOT_EQUAL_P_EQUAL,
Q_EQUAL_P_NOT_EQUAL,
PQ_NOT_EQUAL
}
Message Print:
public void messagePrint(PointTestValues testResult){
switch(testResult){
case QP_EQUAL:
// print message
break;
case Q_NOT_EQUAL_P_EQUAL:
// print message
break;
case Q_EQUAL_P_NOT_EQUAL:
// print message
break;
case PQ_NOT_EQUAL:
// print message
break;
}
}
Note: return corresponding enum value instead of int in the method "comparePriceQuantity". I have provided it in comment
Main function:
messagePrint(point1.comparePriceQuantity(point2))

Related

ArrayList's contains() method always returns false with custom object

I'm having some troubles with getting on with my code, I'll give you an simple example (though it's going to be a little more complex, this simple code doesn't work properly either).
class Sign {
private String char;
private Integer freq;
public Sign(String c) {
this.char = c;
}
#Override
public boolean equals(Object o) {
String check = (String)o;
return check.equals(this.char);
}
#Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + this.char.hashCode();
return hash;
}
}
I assume that there's always will be a String in equals method for simplicity reasons. There's some hashCode() also to make sure that the contains() method will work and here's the test itself:
ArrayList<Sign> queueOfSigns = new ArrayList<>();
Sign test = new Sign("C");
String c = "C";
queueOfSigns.add(test);
if(queueOfSigns.contains("C"))
System.out.println("I am here!");
No matter what, this simple test-code always returns false in that case - so "I'm here" message never appears. I've been trying some different ways of approach my code but it was because the idea of this is to get single characters from String text and check whether the single character is already present in the ArrayList. Nevertheless - without getting this simple test working properly I can't move on, so I would like to ask you - what am I missing. It's my first time actually with using equals() and hashCode() methods to get my own object working properly with contains() method.
Your equals implementation is incorrect. equals has a specific contract; that code attempts to violate that contract. From the documentation:
The equals method implements an equivalence relation on non-null object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
There's no way to make an instance of your Sign class equals to a string.
Your equals method is implemented incorrectly. It violates the general contract of Object.equals:
It is not reflexive - since it throws an exception when the argument is not a string, x.equals(x) where x is a Sign will crash with an exception.
It is not symmetric - x.equals(y) does not return the same value as y.equals(x), if y is a string and x is a Sign
It is not consistent - since it can possibly throw exceptions when the argument is not a string, not just return true or false.
On a low level of abstraction, the cause of this problem is the implementation of contains. As per the docs:
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
ArrayList actually calls o.equals(e) with o being the string you passed in. So it actually calls the equals method in String.
If contains called e.equals(o), then your program would have printed "I'm here", but your equals still violates the contract.
A better equals implementation is something like this:
#Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o.getClass() == this.getClass()) {
Sign other = (Sign)o;
return other.$char.equals($char); // I have renamed 'char' to '$char' since the former is not a valid identifier
} else {
return false;
}
}
And your client code:
ArrayList<Sign> queueOfSigns = new ArrayList<>();
Sign test = new Sign("C");
Sign c = new Sign("C");
queueOfSigns.add(test);
if(queueOfSigns.contains(c))
System.out.println("I am here!");
EDIT:
I think this is what you are looking for:
arrayList.stream()
.filter(x -> x.getChar().equals("C"))
.findFirst().isPresent() // this returns true if a sign with C is found in the array list

How to check if two arraylist are the same (Unit test with JUnit)

Before you mark my question as duplicate, i have tried solutions in other post but didnt work. This what i have
Clientes Cliente1 = new Clientes(1,PinturasCliente1,ColoresCliente1);
Clientes Cli= new Clientes(1,PinturasCliente1,ColoresCliente1);
ArrayList<Clientes> ListaClientes = new ArrayList<Clientes>();
ArrayList<Clientes> ClientesMetodo = new ArrayList<Clientes>();
ListaClientes.add(Cliente1);
ClientesMetodo.add(Cli);
Assert.assertEquals(ListaClientes, ClientesMetodo);
This return error, and by the way PinturasCliente1 and ColoresCliente1 are ArrayList too.
So, how can I test both ListaClientes and ClientesMetodo have not the same Objects, but the Objectes they have added, have the same information.
You should overwrite the equals method on the classes of the objects you are adding to your list.
from the javadoc:
public boolean equals(Object obj)
Indicates whether some other object is "equal to" this one.
The equals method implements an equivalence relation on non-null
object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns
true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then
x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or
consistently return false, provided no information used in equals
comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
Note that it is generally necessary to override the hashCode method
whenever this method is overridden, so as to maintain the general
contract for the hashCode method, which states that equal objects must
have equal hash codes.
Parameters:
obj - the reference object with which to compare. Returns:
true if this object is the same as the obj argument; false otherwise.
note: If you override the equals method in a given class its also recommended to overwrite the hashCode method.
AbstractList.equals() is defined:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
so it use o1.equals(o2) to compare each element. In your case, it's Clientes. But Clientes.equals() by default is Object.equals(), it's defined:
public boolean equals(Object obj) {
return (this == obj);
}
Apparently, Cliente1 != Cli.
So you should override Object.equlas() in Clientes. You can check this by add
public boolean equals(Object o) { return true; }
in Clientes. Then focus on the implementation. And for PinturasCliente1 and ColoresCliente1, you'd better also implement own equals() for each of the class in case of they are not the same object.
You can override your equals method that's all objects gets from Object,
If you using maven / gradle you can import Lombok project
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven</artifactId>
<version>1.16.20.0</version>
<type>pom</type>
</dependency>
And use it to generate equals and hashcode methods auto.
#EqualsAndHashCode
public class Clientes {
}
If you implement equals() and hashCode() methods and use the equals() methods from AbstractList your program will work if only both lists contains the same elements in the same order.
If both lists contain the same elements but in different order, then it would return false even if the two lists are same in content. I do not know whether it is your requirement, but if that is, then you'll need to write your own logic to compare the lists.

creating a polymorphic equals expression

my question concerns altering an expression in java to make it polymorphic. The class is called csHash and is used to create hash-tables from a given datatype DT, and a given keytype KT. now, in several methods within the class (delete, search, insert, etc.) the method uses an equals function that, in the non-polymorphic version, simply uses String ( as the key in the non-polymorphic version is of the type String). what i was thinking is to create an equals method written as something along the lines of the following code. my question is... is it a valid means of testing equality?
public boolean equals(Object x) {
String i;
i = new String[1];
String y;
y = new String[1];
i == i + this; // use the + operator to add 'this' object
y == y + (findkey(other))x; // do the same for other object. findkey methods returns KT for a given object, i use this return to typecast the Object x.
int j = i.compareTo(y); // use built in String compare method
if(j = 0) {return true;} // use if else to determine if they are equal
else {return false;}
}
I would start by reading the spec:
Indicates whether some other object is "equal to" this one.
The equals method implements an equivalence relation on non-null
object references:
It is reflexive: for any non-null reference value x, x.equals(x)
should return true. It is symmetric: for any non-null reference values
x and y, x.equals(y) should return true if and only if y.equals(x)
returns true. It is transitive: for any non-null reference values x,
y, and z, if x.equals(y) returns true and y.equals(z) returns true,
then x.equals(z) should return true. It is consistent: for any
non-null reference values x and y, multiple invocations of x.equals(y)
consistently return true or consistently return false, provided no
information used in equals comparisons on the objects is modified. For
any non-null reference value x, x.equals(null) should return false.
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
Note that it is generally necessary to override the hashCode method
whenever this method is overridden, so as to maintain the general
contract for the hashCode method, which states that equal objects must
have equal hash codes.
In other words, as long as given three objects x, y, and z the following will hold:
x.equals(y) implies y.equals(x)
!x.equals(y) implies !y.equals(x)
x == y implies x.equals(y)
x.equals(y) && y.equals(z) implies x.equals(z)
If your equals method follows this contract, then it is a valid Java Object.equals implementation. You can create lots and lots of unit tests for this quite easily to ensure all corner cases are covered.
Note that you will also have to override hashCode with the related behavior.
Your equals method is problematic as it doesn't compare the two hash tables with all items in the buckets. Also it doesn't exclude some cases. An example override of equals method in your CSHash class looks like the following to satisfy the general guideline of equals method:
#Override
public boolean equals(Object o) {
if (o == null)
return false;
if (this == o)
return true;
if (!(o instanceof CSHash))
return false;
CSHash other = (CSHash) o;
return this.entrySet().equals(other.entrySet());
}
Here it assumes that you have defined entrySet() method in your CSHash class to return the set of your hash table. You can define your own entrySet() method similar to the one in Java's HashMap class.

Java hashcode based on identity

The default behavior of Object.hashCode() is to return essentially the "address" of the object so that a.hashCode() == b.hashCode() if and only if a == b. How can I get this behavior in a user-defined class if a superclass already defines hashCode()? For instance:
class A {
public int hashCode() {
return 0;
}
}
class B extends A {
public int hashCode() {
// Now I want to return a unique hashcode for each object.
// In pythonic terms, it'd look something like:
return Object.hashCode(this);
}
}
Ideas?
System.identityHashCode(Object) provides this behaviour.
You would write this:
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
}
Please check the equals-method, that it only returns true, if the two objects are the same. Otherwise it would break behaviour described for equals and hashCode. (To be correct, the equals-method has to return false, if you get different hashcodes for two objects.) To provide an implementation of equals() that comply with the given hashCode()-method:
public boolean equals(Object other){
return this == other;
}
Use System.identityHashCode(). This is what IdentityHashMap uses.
You should be extremely wary of overriding an existing hashCode() with this though because you might break the hashCode contract, being that two objects that:
if a.equals(b) then a.hashCode() must equal b.hashCode()
You might break this by overriding the existing behaviour or you might need to override equals() too.
As Mnementh said it all, I'd just like to point out that hashCode() returning 0 (or any constant value) is valid (while lame). hashCode() can (and should) return different values for a and b only if !a.equals(b).
So for example you have
class A {
public int hashCode() {
return 0;
}
public boolean equals(Object o) {
return o instanceof A; // all objects are equal
}
}
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return this.hashCode().equals(o.hashCode());
}
}
Now you create two objects:
A a = new A();
A b = new B();
And suddenly a.equals(b), but !b.equals(a). Of course in more real life the equals() in A will be more sophisticated, but the problem still persist. To get rid of this problem you want to always call
if (super.equals(o)) return true;
at the beginning of new equals().
And since overriding hashCode() is strictly tied to overriding equals(), you want to make sure that everywhere super.equals() returned true for any two given objects, new hashCode() will return super.hashCode().

equals() method of java

I've the following test program. I create 3 Integer references. I create 2 Integer objects and make references i1 and i2 refer them respectively. I make reference i3 equal to i1. Now i1 equals() i3 should be obviously true as they both refer to same object on heap. But why should i1 be equal() to i2 ? They are refering to two different objects. What am I missing.
The documentation says:
public boolean equals(Object obj)
Indicates whether some other object is "equal to" this one.
public class Test{
public static void main(String [] args)
{
Integer i1 = new Integer(10);
Integer i2 = new Integer(10);
Integer i3 = i1;
if(i1.equals(i3)) // UNDERSTANDABLE
System.out.println("equal");
if(i1.equals(i2)) // prints equal. WHY !!!!!
System.out.println("equal");
}
}
The equals() methods for the wrapper types test for value equality, if you want to test reference equality, use == instead, e.g.
System.out.println(new Integer(1) == new Integer(1));
equals is the value version of equality. Classes override this method to define what value equality means. For example, to see if two strings contain the same sequence of characters, you use the .equals() method. If creating your own class, and, for example, you want to add it to a HashMap, you would have to define both a hashCode() and an equals() method for it to work properly.
To see if two references point to the same memory location, use ==.
Because i1 and i2 have the same value. Integer.equals() is implemented like this:
public boolean equals(Object obj) {
return (obj instanceof Integer
&& intValue() == ((Integer) obj).intValue());
}
So i1 and i2 are Integers and they have the same value, so it will return true.
The equals method of the Integer class compares the int values that Integer wraps. As 10 is equal to 10, i1 and i2 are considered equal.
By looking at the Integer class you may get a better idea why. Here is the code is below
/**
* Compares this object to the specified object. The result is
* <code>true</code> if and only if the argument is not
* <code>null</code> and is an <code>Integer</code> object that
* contains the same <code>int</code> value as this object.
*
* #param obj the object to compare with.
* #return <code>true</code> if the objects are the same;
* <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
This is the implementation of equals() in Integer:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
with that in mind, if the value of i1 is 10, and the value of i2 is also 10, then 10 == 10 would return true.
If you read further in the JavaDoc, it provides more details, specifically:
Indicates whether some other object is
"equal to" this one. The equals
method implements an equivalence
relation on non-null object
references:
It is reflexive: for any non-null reference value x, x.equals(x) should
return true.
It is symmetric: for any non-null reference values x and y, x.equals(y)
should return true if and only if
y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if
x.equals(y) returns true and
y.equals(z) returns true, then
x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple
invocations of x.equals(y)
consistently return true or
consistently return false, provided no
information used in equals comparisons
on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
Specifically, it is up to the implementor of "equals(Object)" to decide if two objects are "equal." For reference comparison, us the == operator as others have pointed out.
I also encourage you to read Effective Java if you're interested in this (and other similar) topics.
The answer to your question has been already said but I have one note. Be careful because your own objects are extended from Object and there is method equal() implemented like operator == so if you want to compare values you have to override it.
Also note that "Using new Integer(int) is guaranteed to always result in a new object, whereas Integer.valueOf(int) allows caching of values to be done by the compiler, class library, or JVM. Using of cached values avoids object allocation and the code will be faster." --FindBugs
Compare these statements:
System.out.println("new == " + (new Integer(1) == new Integer(1)));
System.out.println("new equals() " + new Integer(1).equals(new Integer(1)));
System.out.println("valueOf() == "
+ (Integer.valueOf(1) == Integer.valueOf(1)));
System.out.println("valueOf() equals() "
+ Integer.valueOf(1).equals(Integer.valueOf(1)));
which produce this output:
new == false
new equals() true
valueOf() == true
valueOf() equals() true
They have same value, that's why it is true. Generally equals method does not test if the references are equal although that is the default behavior.

Categories