Can equals() and hashCode() be lambdas? - java

I am new to Java. Can someone explain to me what is the difference between using lambda and method here?
Method equals()
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Book)) {
return false;
}
Book book = (Book) o;
if (!author.equals(book.author)) {
return false;
}
return title.equals(book.title);
}
Lambda equals()
public Function<Object, Boolean> equals = (Object o) -> {
if (this == o) {
return true;
}
if (!(o instanceof Book)) {
return false;
}
Book book = (Book) o;
if (!author.equals(book.author)) {
return false;
}
return title.equals(book.title);
};
Method hashCode()
#Override
public int hashCode() {
return 31 * author.hashCode() + title.hashCode();
}
Lamba hashCode()
public Supplier<Integer> hashCode = () -> 31 * author.hashCode() + title.hashCode();
I wanted to use Lambda instead of method for equals and hashCode.
Is it OK?

No, it is not OK. Java defines the methods boolean equals(Object) and int hashCode(). This is a specific signature and your suggested solution doesn't meet that signature and doesn't override the default implementation from Object (in fact, they are not even methods).
You could use a lambda in your equals and hashCode, but that would just add a needless level of indirection, and make your code harder to read.

Related

Abstract Class Java

I need to write abstract class, which looks like this.
public abstract class Value {
public abstract String toString();
public abstract Value add(Value v);
public abstract Value sub(Value v);
public abstract boolean eq(Value v);
public abstract boolean lte(Value v);
public abstract boolean gte(Value v);
public abstract boolean neq(Value v);
public abstract boolean equals(Object other);
public abstract int hashCode();
public abstract Value create(String s);
}
Now I need to make few classe, which inherit from that one. I started from Int class and implemented it like this:
public class Int extends Value {
int val;
public String toString() {
String toStr = Integer.toString(val);
return toStr;
}
public Int add(Value v) {
Int result = new Int();
if(v instanceof Int) {
Int temp = (Int) v;
result.val = val + temp.val;
}
return result;
}
public Int sub(Value v) {
Int result = new Int();
if(v instanceof Int) {
Int temp = (Int) v;
result.val = val - temp.val;
}
return result;
}
public boolean eq(Value o) {
if(this == o) return true;
if(this == null) return false;
if(getClass() != o.getClass()) return false;
Int other = (Int) o;
return toString() == other.toString();
}
public boolean lte(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return this.val < temp.val;
}
return false;
}
public boolean gte(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return this.val > temp.val;
}
return false;
}
public boolean neq(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return !eq(temp);
}
return true;
}
public boolean equals(Object o) {
if(this == o) return true;
if(this == null) return false;
if(getClass() != o.getClass()) return false;
Int other = (Int) o;
return toString() == other.toString();
}
public int hashCode() {
Integer hash = val;
return hash.hashCode();
}
public Int create(String s) {
val = Integer.parseInt(s);
return this;
}
}
Everything is compiling and working, but I have no clue if my hashcode() function and equals() are good. Furthermore i want to use create() to make objects like this:
getInstance().create("1234");
Is my method also sufficient?
Everything is compiling and working, but I have no clue if my hashcode() function and equals() are good.
Your equals() should compare int val and not result of toString() of compared objects (this.val == other.val).
Your hashCode() looks good, though I would add #Override to it (same with equals()).
Furthermore i want to use create() to make objects like this: getInstance().create("1234");
Looking at its implementation, it looks fine (i.e. would work according to your needs):
public Int create(String s) {
val = Integer.parseInt(s);
return this;
}
though I don't think you really want to use it with getInstance(). Simply Int.create() would be enough:
public static Int create(String s) {
val = Integer.parseInt(s);
return new Int(val);
}
Note that you would need a private constructor.
Also, as someone noted in the comments, consider using generics instead of inheritance.
The hashCode() method is fine (although I'd add an #Override annotation, just to make the code easier to maintain and avoid mistakes), but the equals(Object) definitely isn't.
Following the logic you have in place, == isn't the right way to compare strings. You should use equals instead (see, e.g., How do I compare strings in Java?). In addition, as Joakim Danielson noted in the comments, this can never be null - you should check if o is null instead:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if(getClass() != o.getClass()) {
return false;
}
Int other = (Int) o;
return toString().equals(other.toString()); // Here!
}
But in all fairness, there's no reason to use toString - you could just compare the internal val:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if(getClass() != o.getClass()) {
return false;
}
Int other = (Int) o;
return val == other.val; // Here!
}
First when you override Methods please do it with #Override Annotation. Then i would implement your equals method in another way. Just do return this.val == other.val instead of doing this.toString() == other.toString(). Your toString() method implementation is ok. Your hashCode is good as well. But please remove that create method. Use a constructor instead.
Can I implement equals() method using eq() like this ?
public boolean equals(Object o) {
Value compare = (Value) o;
return eq(compare);
}

How is Java compiler without type casting calling a correct equals() function in subclass?

I have ScheduledSessionViewModel class which extends AbstractSessionViewModel. Both this functions have implementation of equals() function.
class AbstractSessionViewModel {
#Override public boolean equals(Object o) {
return /* some logic */
}
}
class ScheduledSessionViewModel extends AbstractSessionViewModel {
#Override public boolean equals(Object o) {
if (!super.equals(o)) return false;
return /* some logic */;
}
}
Since I'm using Androids new ListAdapter I am implementing DiffUtil.ItemCallback<T> and I have next method:
#Override public boolean areContentsTheSame(AbstractSessionViewModel oldItem, AbstractSessionViewModel newItem) {
if (oldItem instanceof ScheduledSessionViewModel && !(newItem instanceof ScheduledSessionViewModel)){
return false;
} else if (!(oldItem instanceof ScheduledSessionViewModel) && newItem instanceof ScheduledSessionViewModel){
return false;
} else if (oldItem instanceof ScheduledSessionViewModel){
return ((ScheduledSessionViewModel)oldItem).equals((ScheduledSessionViewModel)newItem);
} else {
return oldItem.equals(newItem);
}
}
What's weird here is that compiler is showing me warning that in the next statement
((ScheduledSessionViewModel)oldItem).equals((ScheduledSessionViewModel)newItem);
type cast is unnecessary.
How is this possible? How's Java compiler able to detect that oldItem is of type ScheduledSessionViewModel?
How's Java compiler able to detect that oldItem is of type ScheduledSessionViewModel?
No it is not; the compiler only knows that oldItem is of type AbstractSessionViewModel.
But it doesn't matter. The compiler knows that the AbstractSessionViewModel has the equals(Object) method, so the actual object type has it too. In this way the compiler guarantees that the equals(Object) method is available at runtime.
How it is implemented is only known at runtime. The runtime searches the appropriate method based on a set of rules defined by the JLS.
Side note: After the clarification above, I came up with the conclusion that with properly implemented equals() method, a method bellow
#Override public boolean areContentsTheSame(AbstractSessionViewModel oldItem, AbstractSessionViewModel newItem) {
if (oldItem instanceof ScheduledSessionViewModel && !(newItem instanceof ScheduledSessionViewModel)){
return false;
} else if (!(oldItem instanceof ScheduledSessionViewModel) && newItem instanceof ScheduledSessionViewModel){
return false;
} else if (oldItem instanceof ScheduledSessionViewModel){
return ((ScheduledSessionViewModel)oldItem).equals((ScheduledSessionViewModel)newItem);
} else {
return oldItem.equals(newItem);
}
}
can be refactored and that if statements are unnecessary. Implementation of equals() method should take care of everything.
End result:
#Override public boolean areContentsTheSame(AbstractSessionViewModel oldItem, AbstractSessionViewModel newItem) {
return oldItem.equals(newItem);
}

Set of object contains by object with value (not reference) (java 7)

I have my object with some feilds.
public class MyObject{
private String a;
private String b;
}
I have a Set contains objects like this :
Set<MyObject> thirdSet = new HashSet<MyObject>();
Set<MyObject> firstSet=getFirstSet();
Set<MyObject> secondSet = getSecondeSet();
for (MyObjectobj : firstSet) {
if (!secondSet.contains(obj)) {
thirdSet.add(obj);
}
}
I need to select all obj that not contains in my secondSet into thridSet (obj with value not by reference)
Is it possible or using collection is more better?
You'll need to override both equals and hashcode methods in your object. I'd recommend using the java 7 Objects utility methods if you can to prevent NullPointerExceptions.
#Override
public boolean equals(Object other) {
if (!(other instanceof MyObject)) {
return false;
}
MyObject that = (MyObject) other;
return Objects.equals(a, that.a) && Objects.equals(b, that.b);
}
#Override
public int hashcode() {
Objects.hash(a, b);
}
I'd also recommend taking a look at the third party library Guava if possible which would simplify your code.
Set<MyObject> thirdSet = new HashSet<>(Sets.difference(firstSet, secondSet));
Note wrapping it in a new HashSet so it can be modified (if you don't need to modify it you can remove that)
You should override Object#equals and Object#hashCode in MyObject.java.
#Override
public boolean equals(Object o) {
if (!(o instanceof MyObject)) {
return false;
}
MyObject m = (MyObject) o;
return a.equals(m.a) && b.equals(m.b);
}
#Override
public int hashCode() {
return Objects.hash(a, b);
}
Also if you're allowed to use external libraries, you should check out Guava's Sets#difference.

equals(Object obj)" should be overridden along with the "compareTo(T obj)" method

I am writing a comparable class. I have overridden compareTo method to sort my objects based on date in descending order.
public class Employee implements Comparable
{
private Timestamp joinDate;
public Timestamp getJoinDate()
{
return joinDate;
}
public void setJoinDate(Timestamp joinDate)
{
this.joinDate = joinDate;
}
#Override
public int compareTo(Employee a)
{
//sort employess based on join date desc
return a.getJoinDate().compareTo(this.getJoinDate());
}
}
My Sonar is complaing to override equals method.
How do I override equals method here.
If you want to override the method compareTo, you have to use the same signature. The actual signature uses an Object parameter:
#Override
public int compareTo(Object o)
{
return ((Employee) o).getJoinDate().compareTo(joinDate);
}
Note that you have to explicitly cast the object obj to Employee, otherwise you won't be able to call its method getJoinDate().
Edit: If you want to override the equals() method you can return the result of comparing the attributes joinDate:
#Override
public boolean equals(Object obj)
{
return joinDate.equals(((Employee) obj).getJoinDate());
}
Note: It's not necessary to call getJoinDate() inside the Employee class, so you can just do:
return ((Employee) o).joinDate.compareTo(joinDate);
or
return joinDate.equals(((Employee) obj).joinDate);
Include this on your class (when you override equals, you have to also override hashCode):
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((joinDate == null) ? 0 : joinDate.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Snippet other = (Snippet) obj;
if (joinDate == null) {
if (other.joinDate != null)
return false;
} else if (!joinDate.equals(other.joinDate))
return false;
return true;
}
There is a difference between what what is indicated by .equals() == true and .compareTo(...) == 0. equals() method is intended to check whether two objects are equal, while compareTo is intended to set a relation order between elements, whether one is greater then the other, other is greater then the first one, or none of this is applicable which is typically means that objects are equal.
Unless you have a very good reason, you should override both equals and compareTo. An example of very good reason is BigDecimal class where equals compares both value of the object and its scale, while compareTo compares only values.
For your case, I'd override equals() like this:
#Override
public int hashCode() {
return this.getJoinDate().hashCode();
}
#Override
public boolean equals(Object obj) {
//correct argument check
if (!(obj instanceof Employee)) {
return false;
}
//check nulls
if (obj == null) {
return false;
}
Employee other = (Employee) obj;
if (this.getJoinDate() == null) {
return other.getJoinDate() == null;
}
return this.getJoinDate().equals(other.getJoinDate());
}

How to implement hashCode and equals method

How should I implement hashCode() and equals() for the following class in Java?
class Emp
{
int empid ; // unique across all the departments
String name;
String dept_name ;
String code ; // unique for the department
}
in Eclipse right mouse click-> source -> generate hashCode() and equals() gives this:
/* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (code == null ? 0 : code.hashCode());
return result;
}
/* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Emp))
return false;
Emp other = (Emp) obj;
return code == null ? other.code == null : code.equals(other.code);
}
I've selected code as a unique field
try this code, use org.apache.commons.lang3.builder
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
append(empid).
append(name).
append(dept_name ).
append(code ).
toHashCode();
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
Emp rhs = (Emp) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
isEquals();
}
Guava has helper methods for creating them. You tell it which fields to take in consideration and it will handle nulls for you and do the prime number calculation for hashcode.
IDEs can also generate them based on the fields you choose.
The advantage of delegating it to a tool like that is you get a standard solution and will worry less about bugs and maintenance of varied implementations spread all over your project.
Here's an example of using Guava and generated by an IntelliJ plugin: https://plugins.jetbrains.com/plugin/7244?pr=
If code is unique (i.e. your business key), it's best to only use the code for equals and hashCode - it's good practice to seperate business key (code) from object id (id).
Here's a nice read: Hibernate Documentation: Equals and HashCode (valid not only for Hibernate itself)
what ever values you use in equals to determine if two objects are the same, are the the values that you need to use to create a hash code.
public boolean equals(Object o) {
boolean result = false;
if(o instanceof CategoryEnum) {
CategoryEnum ce = (CategoryEnum) o;
result = ce.toString().equals(name);
}
return result;
}
public int hashCode()
{
int hash = 6;
hash += 32 * name.hashCode();
return hash;
}
equals()and hashcode(),They have a lot of different places.
equals(),if we don't Override it from Object,it represent that whether two variables are pointing to the same object heap?
public Class Student(){
private int id;
private name;
public Student(int id,String name){
this.name=name;
this.id=id;
}
public void main(String[] args){
Student A=new Student(20,'Lily');
Student B=new Student(20,'Lily');
boolean flag=A.equals(B)//flag=flase;
/*
*Although they attribute the same, but they are two different objects, they point to different memory
*/
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (this.getClass() != obj.getClass()) {
return false;
}
Student s=(Student)obj;
return new Integer(this.id).equals(new Integer(s.id))&&this.name.equals(s.name);
}
/**
*Sometimes even though we Override the equals, but we still can not determine whether the *two objects the same,
*In the collection object, such as HashSet, this time we have to Override the hashoCode ()
*/
public int hashCode(){
return id + name.hashCode() ;
}

Categories