Compare two objects with .equals() and == operator
==
compares object references, it checks to see if the two operands point to the same object (not equivalent objects, the same object).
If you want to compare strings (to see if they contain the same characters), you need to compare the strings using equals
.
In your case, if two instances of MyClass
really are considered equal if the strings match, then:
public boolean equals(Object object2) {
return object2 instanceof MyClass && a.equals(((MyClass)object2).a);
}
...but usually if you are defining a class, there's more to equivalency than the equivalency of a single field (a
in this case).
Side note: If you override equals
, you almost always need to override hashCode
. As it says in the equals
JavaDoc:
Note that it is generally necessary to override the
hashCode
method whenever this method is overridden, so as to maintain the general contract for thehashCode
method, which states that equal objects must have equal hash codes.
How to use compareTo() to compare two objects?
Your class needs to implement Comparable interface, and inside your class you need to override compareTo method (which is in Comparable interface). In this method you will define how your object will be compared to another, on what 'criteria' the comparison will be done.
It's a good practice to implement compareTo method such that, when its return value is 0, it's like two objects are equals (e.g. firstK.compareTo(secondK) == firstK.equals(secondK)
).
You can also read Java documentation compareTo documentation.
public class K implements Comparable<K> {
//Attributes, constructor etc
@Override
public int compareTo(final K otherK) {
/*
Do what you want to compare them, for example, if your
K class has a integer field 'value', and you want to compare
K's instances based on 'value' field, you can do as follow:
*/
return Integer.compare(this.value, otherK.getValue());
}
}
Comparing the content of two objects in Java
You can structure your equals method similarly to an if statement. You just need to cast the other argument first before your can compare their fields.
@Override
public boolean equals(Object o) {
// Check if the other object is also a Student
if (o instanceof Student) {
// Now that we know o is a student, we can safely cast it
Student other = (Student) o;
// Similarly to how you would write an if statement you can compare each individual field.
// Thanks to inheritance, we defer the equality check of each field to its own implementation
return this.firstName.equals(other.firstName)
&& this.lastName.equals(other.lastName)
&& this.birthDate.equals(other.birthDate);
}
// Other object was not a student
return false;
}
You then need to go write something similar in Date
so that when you compare birthDate
, it will know what to do.
You can also take this one step farther by using Objects.equals(a, b)
instead of a.equals(b)
. This will ensure you do not get a nullPointerException if a
happens to be null when comparing them. However, since this looks to be a school project I imagine you may be expected to either check manually or assume the values will not be null instead of using the standard library.
Compare two objects excluding some fields - Java
The quickest way without writing any code is Lombok
Lombok is one of the most used libraries in java and it takes a lot of Boilerplate code off your projects. If you need to read more on what it can and does, go here.
The way to implement what you need is pretty straightforward:
// Generate the equals and HashCode functions and Include only the fields that I annotate with Include
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public class Class1
{
@EqualsAndHashCode.Include // Include this field
private Long identity;
private String testStr1; // This field is not annotated with Include so it will not be included in the functions.
// ... any other fields
}
Lombok can do a lot more than this. For more information on @EqualsAndHashCode
refer to this.
You can always use @EqualsAndHashCode.Exclude
for a quicker solution to your use case:
@EqualsAndHashCode
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public final class Class1 {
private String a;
private String b;
private String c;
:
:
:
private String z;
@EqualsAndHashCode.Exclude
private Date createdAt;
@EqualsAndHashCode.Exclude
private Date updatedAt;
}
How to compare two Sets of objects Not overriding equals/hashCode with Comparator and Streams
A Fix for Comparator
In order to create a Comparator
in this case you need to provide generic type information explicitly, like that: <Book, String>comparing()
, where Book
and String
are the parameter type and return type of the Function
that Comparator.comparing()
expects as a parameter.
Without an explicit declaration, the compiler has not enough data to determine the type of the variable book
, and inside both comparing()
and thenComparing()
its type will be inferred as Object
.
Comparator<Book> comparingBooks =
Comparator.<Book, String>comparing(book -> book.getName())
.thenComparing(book -> book.getType());
If the case if only one of the static methods was used, the type of the book
variable will be correctly inferred by the compiler as Book
based on the type of the locale variable Comparator<Book> comparingBooks
.
Both method lambda expressions could be replaced with method references:
Comparator<Book> comparingBooks =
Comparator.<Book, String>comparing(Book::getName)
.thenComparing(Book::getType);
for information on the syntax of generic methods, take a look at this tutorial
for more information on how to build comparators with Java 8 methods take a look at this tutorial
Stream
should validate any difference of Name and Type by returning true, if both Sets have exactly the same objects, it should return false.
Stream s1.stream().anyMatch(a -> s2.stream().anyMatch(b -> ...))
is currently checking whether there's an element in the first set s1
that is different from ANY of the elements in s2. I.e. the nested anyMatch()
will return true
for the first element encountered in s1 that has not matching element in s2. After the comparison of Book("book 1", BookType.ONE)
(s1) with Book("book 2", BookType.TWO)
(s2) anyMatch()
terminates by returning true
. And enclosing anyMatch()
operation propagates this result.
Precisely the same will happen with the second example. The same pair of elements differ, although you've changed a type, names are not equal. Result is true
.
Note:
- that by convention classes are usually named with singular nouns, i.e.
Book
(not Books),Event
,Person
, etc. - as a rule of thumb, if your objects are intended to be used with collection they must implement
equals/hashCode
contract, your requirement is very unusual.
Comparing two objects for varying set of properties
anyMatch
You can solve this with the Stream API, using anyMatch
, with your rules basically being defined as Predicate
s.
For example checking if there is any person who is 20
years old:
List<Person> persons = ...
boolean doesAnyMatch = persons.stream()
.anyMatch(p -> p.getAge() == 20);
You can of course also setup the rule in a way that it compares with an existing item, mimicking equals
a bit more:
p -> p.getAge() == otherPerson.getAge()
Predicate
You can setup all your rules somewhere else, as Predicate
s and then use them. For example:
List<Predicate<Person>> rules = List.of(
p -> p.getAge() == 20,
p -> p.getName().equals("John"),
p -> p.getAge() > 18,
p -> p.getName().length() > 10 && p.getAge() < 50
);
And then maybe use them in some sort of loop, whatever you need:
for (Predicate rule : rules) {
boolean doesAnyMatch = persons.stream()
.anyMatch(rule);
...
}
findAny
You can substitute anyMatch
by a combination of filter
and findAny
to receive an actual match, i.e. a Person
, instead of just a boolean
:
Person matchingPerson = persons.stream()
.filter(rule)
.findAny();
How to compare two java objects
You need to provide your own implementation of equals()
in MyClass
.
@Override
public boolean equals(Object other) {
if (!(other instanceof MyClass)) {
return false;
}
MyClass that = (MyClass) other;
// Custom equality check here.
return this.field1.equals(that.field1)
&& this.field2.equals(that.field2);
}
You should also override hashCode()
if there's any chance of your objects being used in a hash table. A reasonable implementation would be to combine the hash codes of the object's fields with something like:
@Override
public int hashCode() {
int hashCode = 1;
hashCode = hashCode * 37 + this.field1.hashCode();
hashCode = hashCode * 37 + this.field2.hashCode();
return hashCode;
}
See this question for more details on implementing a hash function.
How to compare two objects without knowing their type
The problem you're reporting is that
return (String)ob;
should be
return ob.toString();
if ob
is never null; or
return Objects.toString(ob);
if it might be.
But note that wrapping an object in an object to compare its toString()
isn't necessary. You can simply use a Comparator<Object>
, like Guava's Ordering.usingToString()
:
int order = Ordering.usingToString().compare(someObject, someOtherObject);
or whatever the Java 8 equivalent is. I guess it would be something like:
Comparator<Object> usingToString = (a, b) -> a.toString().compareTo(b.toString());
int order = usingToString(someObject, someOtherObject);
Related Topics
How to Re-Attach Detached Objects in Hibernate
Warning - Build Path Specifies Execution Environment J2Se-1.4
Spring Boot Adding Http Request Interceptors
How to Access Owl Documents Using Xpath in Java
Spring Security Configuration - Httpsecurity VS Websecurity
Purpose of Default or Defender Methods in Java 8
Converting Roman Numerals to Decimal
How to Set Java_Home Environment Variable on MAC Os X 10.9
I Get Exception When Using Thread.Sleep(X) or Wait()
Is It Bad to Explicitly Compare Against Boolean Constants E.G. If (B == False) in Java
Why Not to Start a Thread in the Constructor? How to Terminate
Subclassing a Java Builder Class
How to Handle Very Large Numbers in Java Without Using Java.Math.Biginteger