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

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
}
}

Related

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().

Android ArrayList: check an element exists of another ArrayList

I have two ArrayList.
private ArrayList<Friend> friendsList = new ArrayList<Friend>();
private ArrayList<Friend> myFriendsList = new ArrayList<Friend>();
First one contains all Friend of database. Second one contains only user Friend. In my search option(SearchManager) i've a ListView contains searched friends of friendsList. When i select a Friend of ListView, i want to check if the Friend exists in myFriendsList. I used following code
friendListView
.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
handelListItemClick(adapter.getItem(position));
}
});
private void handelListItemClick(Friend friend) {
for(Friend fr: myFriendsList){
Log.v("Check User Name:", fr.getName());
}
if (myFriendsList.contains(friend)) {works with matched friend}
But it can't check the selected Friend in myFriendsList. In LogCat it show myFriendsList information. Thanks in advance.
Update
Here is my Friend class
public class Friend {
private String id, name, thumbnailUrl;
public Friend() {
}
public Friend(String name, String thumbnailUrl) {
this.name = name;
this.thumbnailUrl = thumbnailUrl;
}
public Friend(String name, String thumbnailUrl, String id) {
this.name = name;
this.thumbnailUrl = thumbnailUrl;
this.id = id;
}
public String getID(){
return id;
}
public void setID(String id){
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
}
To be able to use methods to find and search like contains your custom class MUST implement correctly the hasCode and equals methods.
Here is the link about the implementing hasCode and here about implementing equals. It is Java Best Practises website that I like very much and from where I've learned about it.
equals() is used in most collections to determine if a collection contains a given element
hashCode() of this object is calculated and used to determine where to search for the object in the hash tables.
For more information on either of these topics visit oracle webiste or take a look here
If You could decide that two Friend objects are equal to each other if just their id's are equal.
So , In your Friend Class include
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Friend)) return false;
Friend friend = (Friend) o;
if (!id.equals(friend.id)) return false;
return true;
}
#Override
public int hashCode() {
return id.hashCode();
}
Now just do,
private void handelListItemClick(Friend friend) {
if (myFriendsList.contains(friend)) {works with matched friend}
}
Edit
You can take a look at this tutorial to learn more about the topic

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.

Is validating fields in both constructor and setter considered bad redundant code?

I have the following class :
public class Project {
private int id;
private String name;
public Project(int id, String name) {
if(name == null ){
throw new NullPointerException("Name can't be null");
}
if(id == 0 ){
throw new IllegalArgumentException("id can't be zero");
}
this.name = name;
this.id = id;
}
private Project(){}
public int getId() {
return id;
}
public void setId(int id) {
if(id == 0 ){
throw new IllegalArgumentException("id can't be zero");
}
this.id = id;
}
public String getName()
return name;
}
public void setName(String name) {
if(name == null ){
throw new NullPointerException("Name can't be null");
}
this.name = name;
}
}
If you noticed that setName and setId share the same validation for its fields with the constructor. Is this redundant code that could cause issues in the future ( for example if somebody edit the the setter to allow 0 for the id and prevent -1 instead but didn't change the constructor) ? . Should I use a private method to do the check and share it between the constructor and the setter which seems too much if there's a lot of fields.
Note: This is why im not using the setters in the constructor. https://stackoverflow.com/a/4893604/302707
Here is the revised code:
public class Project {
private int id;
private String name;
public Project(int id, String name, Date creationDate, int fps, List<String> frames) {
checkId(id);
checkName(name);
//Insted of lines above you can call setters too.
this.name = name;
this.id = id;
}
private Project(){}
public int getId() {
return id;
}
public void setId(int id) {
checkId(id);
this.id = id;
}
public String getName()
return name;
}
public void setName(String name) {
checkName(name);
this.name = name;
}
private void checkId(int id){
if(id == 0 ){
throw new IllegalArgumentException("id can't be zero");
}
}
private void checkName(String name){
if(name == null ){
throw new NullPointerException("Name can't be null");
}
}
}
I recommend that you should define one method per field as isValid() and then call the same method in you setter as well as Constructor.
I would say yes. Rather than that, just call the setters from your constructor:
public Project(int id, String name, Date creationDate, int fps, List<String> frames) {
setName(name);
setId(id);
// other stuff with creationDate, fps and frames?
}
Also, you shouldn't check for a null name in getName -- do it in setName. Otherwise, bugs are going to be hard to track down -- you want to catch the invalid name as soon as it comes in, not when it's used (which may be much later).
if you make Project immutable, it will eliminate the redundant code. but for now, i think explicitly throwing exceptions in both the constructor and mutator methods is fine.
and i would not call the mutator methods within the constructor for many reasons, including this. also, i would remove the validation code in the accessor method...it's not necessary.

Categories