How to maintain only non-equal object in HashSet - java

How can i remove objects having the same state.
class Student{
private int age;
private String name;
Student(int age, String name){
this.age=age;
this.name=name;
} }
public class SetTest {
public static void main(String[] args) {
Student s1= new Student(15,"abc");
Student s2= new Student(15,"abc");
Student s3= new Student(16,"adfc");
Student s4= new Student(14,"ayuc");
Set<Student> ss= new HashSet<Student>();
ss.add(s1); ss.add(s2); ss.add(s3); ss.add(s4);}}
here s1 and s2 are having equal state and as i am using Set and I want to keep only one instance. What should i do to take only object with non-equal instance.

You need to override the equals() and hashCode() methods in the Student class. In this method you define what it means for 2 students to be equal.
#Override
public boolean equals(Object other){
//code to determine if this student is equal to other
}
#Override
public int hashCode() {
//code to generate a hashCode for the student
}
Pay attention to the advice in this question.

You need to override the equals() and hashCode() methods in your Student class.
class Student {
...
#Override
public boolean equals(Object obj) {
// Your own logic
// return super.equals(obj); // default
}
#Override
public int hashCode() {
// Your own logic
// return super.hashCode(); // default
}
}

Related

How can I use an object outside of it's declared scope?

For example, if I have a class Student and an student object inside of it with the value of 5, also some getters and setters
public class Student {
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void run() {
Student stud = new Student();
stud.setAge(5);
}
}
And I have another class called getStudent
public class GetStudent {
int studAge = stud.getAge;
}
Now this, obviously, gives me an error. Is there any way to access the stud object and it's methods outside of it's class?
If you always want to access the Student object only through the public static void run() method, check out Singleton design pattern.

Comparing two class objects with a method

I have a multitude of objects that are created with multiple instance variables (a string a multiple integers)
I have to create a method that will check for equality between the object that executes the method and another object. By that I mean that I would want to see whether all the instance variables are the same for two objects by calling a method. I'm thinking of something like the equals method (string1.equals(string2)), but can I do the same for an object with multiple instance variables which are not all strings?
example:
//object1
String name1= keyb.nextLine();
int age1= keyb.nextInt();
int monthborn1;
//object2
String name2=keyb.nextLine();
int age2 = keyb.nextInt();
int monthborn2;
I need to make a method that compare both objects and sees if they are equal or not.
Thank you very much.
Yes, you can create an equals method for your class. For example:
public final class Person {
private final String name;
private final int age;
private final int birthMonth;
public Person(String name, int age, int birthMonth) {
this.name = Objects.requireNonNull(name);
this.age = age;
this.birthMonth = birthMonth;
}
#Override
public boolean equals(Object o) {
if (o instanceof Person) {
Person rhs = (Person) o;
return name.equals(rhs.name)
&& age == rhs.age
&& birthMonth == rhs.birthMonth;
}
return false;
}
// Any time you override `equals`, you must make a matching `hashCode`.
// This implementation of `hashCode` is low-quality, but demonstrates
// the idea.
#Override
public int hashCode() {
return name.hashCode() ^ age ^ birthMonth;
}
}
In Java you usually have to manually check every field like this:
class MyObject {
String name;
int age, monthborn;
public boolean isEqual(MyObject other) {
return Objects.equals(name, other.name) &&
age == other.age && monthborn == other.monthborn;
}
}
Objects.equals is used here which is null-safe equivalent of name.equals(other.name). When you add new fields you will have to add new checks in your method as well. The alternative would be to utilize reflection, but it looks ugly and has significant performance drawback. Here's a draft example how to do this (do not take into account possible inheritance):
import java.lang.reflect.Field;
import java.util.Objects;
public class ObjectUtil {
public static <T> boolean allFieldsEqual(T o1, T o2) throws IllegalAccessException {
if(o1 == o2) return true;
if(o1.getClass() != o2.getClass()) return false;
for(Field field : o1.getClass().getDeclaredFields()) {
field.setAccessible(true);
if(!Objects.equals(field.get(o1), field.get(o2))) {
return false;
}
}
return true;
}
}
class MyObject {
String name;
int age, monthborn;
public boolean isEqual(MyObject other) {
try {
return ObjectUtil.allFieldsEqual(this, other);
} catch (IllegalAccessException e) {
return false;
}
}
}
This way upon adding the new field the isEqual method will take it into account as well. However I would not recommend such solution.
Please see this answer . Also, since you are overriding the equals method you should also override the hashcode method (also covered in the linked post)
Once you compare two objects you have to consider about all the members of the class.
We will assume that we have a class named B and with two member variables age and name.
class B :
public class B {
String name;
int age;
public B(String name, int age) {
this.age = age;
this.name = name;
}
}
Then lets compare the two different objects of same class using equals and hashcode methods which are inherited to our class B from Object class.
class A to compare :
public class A {
public static void main(String args[]){
B b1 = new B("a", 22);
B b2 = new B("a",22);
System.out.println(b1.equals(b2));
System.out.println(b1.hashCode());
System.out.println(b2.hashCode());
}
}
As soon as we compile and run class A we will get following out-puts.
false
705927765//returns int value
366712642//returns int value
But here in the class A we have passed same parameters to both objects of the B. Which means we are getting what we did not expect because of equals and hashcode methods which are in Object class not doing what we need.
So in this case we have to override these methods in our class B to make it success.
Class B after override done:
public class B {
String name;
int age;
public B(String name, int age) {
this.age = age;
this.name = name;
}
#Override
public boolean equals(Object obj) {
boolean flag = false;
if (obj instanceof B) {
B b = (B) obj;
if (this.age == b.age) {
if (this.name.charAt(0)==b.name.charAt(0))) {
flag = true;
} else {
flag = false;
}
} else {
flag = false;
}
} else {
flag = false;
}
return flag;
}
#Override
public int hashCode() {
return this.age+this.name.charAt(0);
}
}
If we run our class A again we could get follwing result :
true
119
119
Which means our work is done.

Hashmap element cannot be override even through hashCode() and equals()?

Here is my code in make sure to add student information with name ,age and their address. In order to make sure the student is unique. I use the hashCode() and equals() to make sure data integrity. The same name of student will be considered as override.
Problem is: The same information is never be cleaned out, Anybody know why? It seems the hashCode() and equals() never work.
class Student implements Comparable<Student>{
private String name;
private int age;
Student(String name, int age){
this.name = name;
this.age = age;
}
public int hashcode(){
return name.hashCode() + age *34;
}
//override equals method
public boolean equals(Object obj){
if(!(obj instanceof Student))
throw new ClassCastException("The data type is not match!");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
public int compareTo(Student s) {
int num = new Integer(this.age).compareTo(new Integer(s.age));
if (num == 0)
return this.name.compareTo(s.name);
return num;
}
}
public class HashMapDemo1 {
public static void main (String[] agrs){
HashMap<Student,String> hs = new HashMap<Student,String>();
hs.put(new Student("James",27),"Texas");
hs.put(new Student("James",27), "California");
hs.put(new Student("James",27), "New mexico");
hs.put(new Student("Jack",22),"New York");
hs.put(new Student("John",25),"Chicago");
hs.put(new Student("Francis",26),"Florida");
Set<Student> Keyset = hs.keySet();
Iterator<Student> it = Keyset.iterator();
while(it.hasNext()){
Student stu = it.next();
String addr = hs.get(stu);
System.out.print(stu.getName()+stu.getAge()+"..." +addr+"\n");
}
}
hashcode != hashCode
Be sure to use the #Override annotation whenever you think that you are overriding a super-class's method, as this will allow the compiler to notify you if/when you are wrong. As you're finding out, it's much easier to fix errors at the compilation stage rather than the run-time stage.
Myself, I'd not use the age field as part of equals or hashCode since age can change for a student with time. I'd use Date birthDate or some other invariant instead.
And also I agree with Radiodef: the equals(...) method should not throw an exception. If the parameter object is not Student type, simply return false.
The method you have implemented is public int hashcode().
It should be public int hashCode().

how to remove duplicate objects with same id's in a set

HashSet contains objects,I want to remove duplicates whose objects are having same id's
the following is the code..
Set<Employee> empSet=new HashSet<Employee>();
empSet.add(new Employee(1,"naresh"));
empSet.add(new Employee(2,"raj"));
empSet.add(new Employee(1,"nesh"));
empSet.add(new Employee(2,"rajes"));
//i saw in some blog that we can use hashCode equals method, but i don't how to use that in this context, please help me out
import groovy.transform.EqualsAndHashCode
#EqualsAndHashCode(includes='id')
class Employee {
int id
String name
}
You can remove constructors as well if #Canonical AST is used. Canonical also provides #EqualsAndHashCode, but to add the includes it has to be used separately again.
UPDATE
If the class is not modifiable and you have a list/hasSet then you can use unique with a closure to perform the uniqueness. Assuming the SolrDocument mentioned in comment is referred as Employee and you have the above HashSet with duplicate ids, then below should work:
empSet.unique { it.id } //this mutates the original list
empSet.unique( false ) { it.id } //this does not mutate the original list
Write equals and hashCode as shown below
public class Employee {
private int id;
private String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (id != employee.id) return false;
return true;
}
#Override
public int hashCode() {
return id;
}
}
You need to override equals() method in your Employee class and it will be taken care of. Set uses the equals method to compare the objects inserted in the Set.
public class Employee
{
public boolean equals(Employee e)
{
/// logic to compare 2 employee objects
}
}

Overriding hashcode and equals method in java?

I have the classes below:
public class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
//This POJO does not override equals() and hashCode()
}
public class B{
private Sample sample;
//here i need override hashcode and equals() based on **sample** property.
}
When i tried overriding equals() and hashCode() in the B class I got the error below in Eclipse.
The field type com.mypackage.Sample does not implement hashCode() and equals() - The resulting code may not work correctly.
Now how can I compare two B instances whether equals or not based on the Sample property?
I cannot modify Sample class.
are you looking something like following? Just try it, as from your question i think you want to compare contents of your Sample class also.
class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//This POJO does not override equals() and hashCode()
}
public class Beta implements Comparable{
private Sample sample;
public Sample getSample() {
return sample;
}
public void setSample(Sample sample) {
this.sample = sample;
}
#Override
public int compareTo(Object o) {
if(!(o instanceof Beta)){
return -1;
}
}if(((Beta)o).getSample().getName().equals(this.sample.getName())){
return 0; // return true if names are equal
}
if(((Beta)o).getSample().getId().equals(this.sample.getId())){
//if name are notequal and IDs are equal, do what you need to do
}
return -1;
}
public static void main(String[] args) {
Beta b = new Beta();
Sample s = new Sample();
s.setId(10);
s.setName("Name1");
b.setSample(s);
Beta b2 = new Beta();
Sample s2 = new Sample();
s2.setId(20);
s2.setName("Name2");
b2.setSample(s2);
System.out.println(b2.compareTo(b));
Beta b3 = new Beta();
Sample s3 = new Sample();
s3.setId(10);
s3.setName("Name1");
b3.setSample(s3);
System.out.println(b3.compareTo(b));
}
}
Overriding approach
class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//This POJO does not override equals() and hashCode()
}
public class Beta /*implements Comparable*/{
private Sample sample;
public Sample getSample() {
return sample;
}
public void setSample(Sample sample) {
this.sample = sample;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Beta other = (Beta) obj;
if ((this.getSample() == null) && (other.getSample() == null)){
return true;
}
if ((this.getSample().getId().equals(other.getSample().getId())) && (this.getSample().getName().equals(other.getSample().getName()))) {
return true;
}
return false;
}
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.getSample().getName() != null ? this.getSample().getName().hashCode() : 0);
hash = 53 * hash + (this.getSample().getId() != null ? this.getSample().getId().hashCode() : 0);
return hash;
}
/* #Override
public int compareTo(Object o) {
if(!(o instanceof Beta)){
return -1;
}
if(((Beta)o).getSample().getId().equals(this.sample.getId()) && ((Beta)o).getSample().getName().equals(this.sample.getName())){
return 0;
}
return -1;
}*/
public static void main(String[] args) {
Beta b = new Beta();
Sample s = new Sample();
s.setId(10);
s.setName("Name1");
b.setSample(s);
Beta b2 = new Beta();
Sample s2 = new Sample();
s2.setId(20);
s2.setName("Name2");
b2.setSample(s2);
System.out.println(b2.equals(b));
Beta b3 = new Beta();
Sample s3 = new Sample();
s3.setId(10);
s3.setName("Name1");
b3.setSample(s3);
System.out.println(b3.equals(b));
}
If you don't explicitly override .equals(), they will be compared based solely off of their references (despite not having a equals(), every object inherits one from Object). If you only want B to be compared based off of Sample, then simply do the following:
#Override
public boolean equals(Object o)
{
if (o istanceof B)
{
return sample.equals(o.sample)
}
return false;
}
Additionally, you should then override hashCode() (and compareTo()) to maintain the contract between equals() and hashCode(). Hence, you should also have the following:
#Override
public int hashCode()
{
return sample.hashCode();
}
EDIT (in response to comment):
My requirement is first i need to check equals property against "name"
property of Sample. IF names are equals then both objects are equal.
If names are not equals then i need to check for equality against "ID"
property of Sample. How can i do that? Thanks!
Determining whether Samples are equivalent should be handled in Sample, by overriding equals(). If equals() for Sample bases off of name and id, then you're fine. If you want to compare Samples in B differently than they are normally compared, then you're not going to be able to maintain the contract between equals() and hashCode() for B if you use hashCode() or equals() from Sample, which means that your hashCode() and equals() for B should be cannot call equals() or hashCode() from Sample. See this tutorial for how to override based on specific fields.

Categories