Using HashSet with a user class Employee - java

I know this will sound a very dumb question, but I got confused after what I have known about HashSet and what I see when I execute below code.
I have an Employee class as follows (keeping only relevant piece of code):
public class Employee {
//assume it has 3 variable name(String),salary(double) and id(int)
//assume the constructor, getter-setters are there
//following is my equals and hashCode implementation
public boolean equals(Employee e){
return name.equals(e.name);
}
public int hashCode(){
return id;
}
}
Now I have following code which uses HashSet :
Employee e1 = new Employee("Abc", 2.0, 1);
Employee e2 = new Employee("abc", 3.0, 4);
Employee e3 = new Employee("XYZ", 4.0, 3);
Employee e4 = new Employee("Mno", 5.0, 2);
Employee e5 = new Employee("Abc", 77.0, 1);
Set<Employee> sEmp = new HashSet<Employee>();
sEmp.add(e1);
sEmp.add(e2);
sEmp.add(e3);
sEmp.add(e4);
sEmp.add(e5);
for(Employee e : sEmp){
System.out.println(e);
}
So I get all the objects data being printed on my console as :
Abc 77.0 1
Abc 2.0 1
Mno 5.0 2
XYZ 4.0 3
abc 3.0 4
AFAIK, the set does not allow duplicates and this duplicay will be check on equals (correct me if I am wrong).
Also, HashSet uses the hashCode, so in above case, it should not add the object e5. But it successfully adds that element to the set. This confused me.
(Please ignore if I have missed standards and all that stuff, I am trying to understand the concept/implementation).
EDITED : This may sound a dumb question, but I am preparing for certification ans was trying to see how stuff works.

You're overloading equals rather than overriding it. Its parameter should be of type Object.
But also your hashCode is checking the id while equals is checking the name. They should probably be constructed from the same properties.

This is standard example of why we should be using #Override annotation wherever possible.
If you would use this annotation with your equals method, you would be informed by compiler that you are not overriding equals method, because there is no equals(Employe) method in superclass, but equals(Object). So you are overloading this method (you are creating additional method with different arguments).
Because of this HashSet is not using code of your equals method, but code from equals(Object) method inherited from Object class which just checks references equality:
public boolean equals(Object obj) {
return (this == obj);
}

I have added some more code in equals methods. This will allow you to update the latest value for the employee id.
package com.test.day16;
import java.util.HashSet;
import java.util.Set;
/**
*
* #author PradeepPadmarajaiah
*
*/
public class Employee {
private int empId;
private String empName;
public Employee(int empId, String empName) {
super();
this.empId = empId;
this.empName = empName;
}
/**
* #return the empId
*/
public final int getEmpId() {
return empId;
}
/**
* #param empId
* the empId to set
*/
public final void setEmpId(int empId) {
this.empId = empId;
}
/**
* #return the empName
*/
public final String getEmpName() {
return empName;
}
/**
* #param empName
* the empName to set
*/
public final void setEmpName(String empName) {
this.empName = empName;
}
/*
* (non-Javadoc)
*
* #see java.lang.Object#toString()
*/
#Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + "]";
}
#Override
public int hashCode() {
return this.empId;
}
#Override
public boolean equals(Object obj) {
Employee employee = (Employee) obj;
if (employee.empId == this.empId) {
employee.setEmpName(this.empName);
return true;
} else {
return false;
}
}
public static void main(String[] args) {
Set<Employee> employees = new HashSet<>();
employees.add(new Employee(1, "Raj"));
employees.add(new Employee(1, "Pradeep"));
employees.add(new Employee(1, "Kumar"));
employees.add(new Employee(2, "Chandan"));
employees.add(new Employee(2, "Amitava"));
System.out.println(employees);
}
}
Check the line "employee.setEmpName(this.empName);" This will override the value of id. This means, empId 1 will have latest empName value as Kumar
Else, empId 1 will have empName value as Raj which was first assigned and it will not ovverride the value to Kumar after checking
This work similar to the HashMap mechanism now.
Code Result will be
[Employee [empId=1, empName=Kumar], Employee [empId=2, empName=Amitava]]

Related

Filter duplicated objects in a Objects List

I have a problem with a list of object in my Java code.
This object is populated with the following fields :
-name
-lastname
-birthdate
-car accident date
Now, this list could countain some object with same values (name,lastname,birthdate)
For example :
Luke skywalker 09/10/1970 10/10/2008
Luke skywalker 09/10/1970 10/10/2009
my goal is to remove the duplicated user and add in a new list only the one with the latest car accident for each user.
In the previous example :
Luke skywalker 09/10/1970 10/10/2009
Do you guys have any idea?
If you let your user class implement Comparable then you could use a SortedSet:
class User implements Comparable<User> {
// fields, constructor, methods etc...
#Override
public void compareTo(User other) {
// assuming carAccidentDate is comparable
return carAccidentDate.compareTo(other.carAccidentDate);
}
#Override
public boolean equals(Object other) {
return /* true if name, lastname and birthdate are equal */
}
#Override
public int hashCode() {
return /* hash code of name, lastname and birthdate */
}
}
I omitted the equals and hashCode implementation for simplicity, but they are also required for this to work.
Then simply create your SortedSet from the existing List, I use TreeSet:
Set<User> latestAccidentsUser = new TreeSet<>(users);
For this question, we have 2 requirements.
Remove duplications.
Keep the lastest car accident.
For requirement 1:
We have HashSet to remove duplication. In order to do that, we have to override equals() and hashcode(), since the default ones are based on the object memory location, while this problem is based on values(name, Lastname, birthdate).
For requirement 2:
First, sort the Users in descending order based on the accident date. And we will have the lastest car accident in the front among the duplicates. And for duplicates will not be added into HashSet since the user has already existed.
The code is as follows:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
class User {
String name;
String lastname;
String birthdate;
String carAccidentDate;
public User(String name,
String lastname,
String birthdate,
String carAccidentDate){
this.name = name;
this.lastname = lastname;
this.birthdate = birthdate;
this.carAccidentDate = carAccidentDate;
}
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
User o = (User) other;
return o.name.equals(name) && o.lastname.equals(lastname)
&& o.birthdate.equals(birthdate);
}
#Override
public int hashCode() {
return Objects.hash(name, lastname, birthdate);
}
#Override
public String toString(){
return String.join(",", name,lastname,birthdate,carAccidentDate);
}
public static void main(String input[]) {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
User[] users = new User[]{
new User("Luke", "skywalker", "09/10/1970", "10/10/2008"),
new User("Luke", "skywalker", "09/10/1970", "10/10/2009")
};
Arrays.sort(users, (B, A) -> {
try {
return dateFormat.parse(A.carAccidentDate).compareTo(dateFormat.parse(B.carAccidentDate));
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
});
Set<User> userSet = new HashSet(Arrays.asList(users));
for(User u: userSet){
System.out.println(u.toString());
}
}
}

How to sort an ArrayList of type Student? [duplicate]

I have simple class
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
and List<ActiveAlarm> con. How to sort in ascending order by timeStarted, then by timeEnded? Can anybody help? I know in C++ with generic algorithm and overload operator <, but I am new to Java.
Using Comparator
For Example:
class Score {
private String name;
private List<Integer> scores;
// +accessor methods
}
Collections.sort(scores, new Comparator<Score>() {
public int compare(Score o1, Score o2) {
// compare two instance of `Score` and return `int` as result.
return o2.getScores().get(0).compareTo(o1.getScores().get(0));
}
});
With Java 8 onwards, you can simply use lambda expression to represent Comparator instance.
Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });
Either make ActiveAlarm implement Comparable<ActiveAlarm> or implement Comparator<ActiveAlarm> in a separate class. Then call:
Collections.sort(list);
or
Collections.sort(list, comparator);
In general, it's a good idea to implement Comparable<T> if there's a single "natural" sort order... otherwise (if you happen to want to sort in a particular order, but might equally easily want a different one) it's better to implement Comparator<T>. This particular situation could go either way, to be honest... but I'd probably stick with the more flexible Comparator<T> option.
EDIT: Sample implementation:
public class AlarmByTimesComparer implements Comparator<ActiveAlarm> {
#Override
public int compare(ActiveAlarm x, ActiveAlarm y) {
// TODO: Handle null x or y values
int startComparison = compare(x.timeStarted, y.timeStarted);
return startComparison != 0 ? startComparison
: compare(x.timeEnded, y.timeEnded);
}
// I don't know why this isn't in Long...
private static int compare(long a, long b) {
return a < b ? -1
: a > b ? 1
: 0;
}
}
JAVA 8 and Above Answer (Using Lambda Expressions)
In Java 8, Lambda expressions were introduced to make this even easier! Instead of creating a Comparator() object with all of it's scaffolding, you can simplify it as follows: (Using your object as an example)
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);
or even shorter:
Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));
That one statement is equivalent to the following:
Collections.sort(list, new Comparator<ActiveAlarm>() {
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return a1.timeStarted - a2.timeStarted;
}
});
Think of Lambda expressions as only requiring you to put in the relevant parts of the code: the method signature and what gets returned.
Another part of your question was how to compare against multiple fields. To do that with Lambda expressions, you can use the .thenComparing() function to effectively combine two comparisons into one:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted
.thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);
The above code will sort the list first by timeStarted, and then by timeEnded (for those records that have the same timeStarted).
One last note: It is easy to compare 'long' or 'int' primitives, you can just subtract one from the other. If you are comparing objects ('Long' or 'String'), I suggest you use their built-in comparison. Example:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );
EDIT: Thanks to Lukas Eder for pointing me to .thenComparing() function.
We can sort the list in one of two ways:
1. Using Comparator : When required to use the sort logic in multiple places
If you want to use the sorting logic in a single place, then you can write an anonymous inner class as follows, or else extract the comparator and use it in multiple places
Collections.sort(arrayList, new Comparator<ActiveAlarm>() {
public int compare(ActiveAlarm o1, ActiveAlarm o2) {
//Sorts by 'TimeStarted' property
return o1.getTimeStarted()<o2.getTimeStarted()?-1:o1.getTimeStarted()>o2.getTimeStarted()?1:doSecodaryOrderSort(o1,o2);
}
//If 'TimeStarted' property is equal sorts by 'TimeEnded' property
public int doSecodaryOrderSort(ActiveAlarm o1,ActiveAlarm o2) {
return o1.getTimeEnded()<o2.getTimeEnded()?-1:o1.getTimeEnded()>o2.getTimeEnded()?1:0;
}
});
We can have null check for the properties, if we could have used 'Long' instead of 'long'.
2. Using Comparable(natural ordering): If sort algorithm always stick to one property:
write a class that implements 'Comparable' and override 'compareTo' method as defined below
class ActiveAlarm implements Comparable<ActiveAlarm>{
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(long timeStarted,long timeEnded) {
this.timeStarted=timeStarted;
this.timeEnded=timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
public int compareTo(ActiveAlarm o) {
return timeStarted<o.getTimeStarted()?-1:timeStarted>o.getTimeStarted()?1:doSecodaryOrderSort(o);
}
public int doSecodaryOrderSort(ActiveAlarm o) {
return timeEnded<o.getTimeEnded()?-1:timeEnded>o.getTimeEnded()?1:0;
}
}
call sort method to sort based on natural ordering
Collections.sort(list);
In java8+ this can be written in single line as follows:
collectionObjec.sort(comparator_lamda) or comparator.comparing(CollectionType::getterOfProperty)
code:
ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
or
ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
public class ActiveAlarm implements Comparable<ActiveAlarm> {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public int compareTo(ActiveAlarm a) {
if ( this.timeStarted > a.timeStarted )
return 1;
else if ( this.timeStarted < a.timeStarted )
return -1;
else {
if ( this.timeEnded > a.timeEnded )
return 1;
else
return -1;
}
}
That should give you a rough idea. Once that's done, you can call Collections.sort() on the list.
Since Java8 this can be done even cleaner using a combination of Comparator and Lambda expressions
For Example:
class Student{
private String name;
private List<Score> scores;
// +accessor methods
}
class Score {
private int grade;
// +accessor methods
}
Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);
Java-8 solution using Stream API:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded))
.collect(Collectors.toList());
B. When timeStarted and timeEnded have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded))
.collect(Collectors.toList());
If you want to sort the original list itself:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
list.sort(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded));
B. When timeStarted and timeEnded have public getter methods:
list.sort(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded));
Guava's ComparisonChain:
Collections.sort(list, new Comparator<ActiveAlarm>(){
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return ComparisonChain.start()
.compare(a1.timestarted, a2.timestarted)
//...
.compare(a1.timeEnded, a1.timeEnded).result();
}});
We can use the Comparator.comparing() method to sort a list based on an object's property.
class SortTest{
public static void main(String[] args) {
ArrayList<ActiveAlarm> activeAlarms = new ArrayList<>(){{
add(new ActiveAlarm("Alarm 1", 5, 10));
add(new ActiveAlarm("Alarm 2", 2, 12));
add(new ActiveAlarm("Alarm 3", 0, 8));
}};
/* I sort the arraylist here using the getter methods */
activeAlarms.sort(Comparator.comparing(ActiveAlarm::getTimeStarted)
.thenComparing(ActiveAlarm::getTimeEnded));
System.out.println(activeAlarms);
}
}
Note that before doing it, you'll have to define at least the getter methods of the properties you want to base your sort on.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(String name, long timeStarted, long timeEnded) {
this.name = name;
this.timeStarted = timeStarted;
this.timeEnded = timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
#Override
public String toString() {
return name;
}
}
Output:
[Alarm 3, Alarm 2, Alarm 1]
Employee POJO Class
package in.ac.adit.oop.sort;
public class Employee {
private int id;
private String name;
private String department;
public int getId() {
return id;
}
public Employee() {
super();
}
public Employee(int id, String name, String department) {
super();
this.id = id;
this.name = name;
this.department = department;
}
#Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", department=" + department + "]";
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
Employee Class To Manage Employee
package in.ac.adit.oop.sort;
import java.util.ArrayList;
import java.util.List;
public class Example {
public static void main(String[] args) {
/*
* Create 10 Employee Object
*/
Employee emp1 = new Employee(1, "Nayan", "IT");
Employee emp2 = new Employee(2, "Siddarth", "CP");
Employee emp3 = new Employee(3, "Samarth", "AE");
Employee emp4 = new Employee(4, "Bhavesh", "CV");
Employee emp5 = new Employee(5, "Sam", "FT");
Employee emp6 = new Employee(6, "Keyur", "IT");
Employee emp7 = new Employee(7, "Bala", "ME");
Employee emp8 = new Employee(8, "Mitul", "ME");
Employee emp9 = new Employee(9, "Kamlesh", "EE");
Employee emp10 = new Employee(10, "Piyush", "EE");
/*
* List of Employee Object
*/
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);
employeeList.add(emp4);
employeeList.add(emp5);
employeeList.add(emp6);
employeeList.add(emp7);
employeeList.add(emp8);
employeeList.add(emp9);
employeeList.add(emp10);
CustomObjectSort customObjectSort = new CustomObjectSort();
List<Employee> sortByDepartment = customObjectSort.sortByDepartment(employeeList);
/*
* Sorted By Department
*/
for (Employee employee : sortByDepartment) {
System.out.println(employee);
}
/*
* Sorted By Name
*/
List<Employee> sortByName = customObjectSort.sortByName(employeeList);
for (Employee employee : sortByName) {
System.out.println(employee);
}
/*
* Sorted By Id
*/
List<Employee> sortById = customObjectSort.sortById(employeeList);
for (Employee employee : sortById) {
System.out.println(employee);
}
}
}
Custom Sorting
package in.ac.adit.oop.sort;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CustomObjectSort {
public List<Employee> sortByName(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getName().compareTo(employee2.getName());
}
});
return employeeList;
}
public List<Employee> sortByDepartment(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getDepartment().compareTo(employee2.getDepartment());
}
});
return employeeList;
}
public List<Employee> sortById(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getId() - employee2.getId();
}
});
return employeeList;
}
}
You can use Collections.sort and pass your own Comparator<ActiveAlarm>
In java you need to use the static Collections.sort method. Here is an example for a list of CompanyRole objects, sorted first by begin and then by end. You can easily adapt for your own object.
private static void order(List<TextComponent> roles) {
Collections.sort(roles, new Comparator() {
#Override
public int compare(Object o1, Object o2) {
int x1 = ((CompanyRole) o1).getBegin();
int x2 = ((CompanyRole) o2).getBegin();
if (x1 != x2) {
return x1 - x2;
} else {
int y1 = ((CompanyRole) o1).getEnd();
int y2 = ((CompanyRole) o2).getEnd();
return y2 - y1;
}
}
});
}
You can call Collections.sort() and pass in a Comparator which you need to write to compare different properties of the object.
As mentioned you can sort by:
Making your object implement Comparable
Or pass a Comparator to Collections.sort
If you do both, the Comparable will be ignored and Comparator will be used. This helps that the value objects has their own logical Comparable which is most reasonable sort for your value object, while each individual use case has its own implementation.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
List<ActiveAlarm> con = new ArrayList<ActiveAlarm>();
Collections.sort(con , (a1, a2) -> a1.timeStarted.compareTo(a2.timeStarted));
Collections.sort(con , (a1, a2) -> a1.timeEnded.compareTo(a2.timeEnded));
Here's what did the trick for me.
Was much shorter and easier than everything else I found:
Collections.sort(listName, Comparator.comparing(Object::getProperty).reversed());
The ".reversed()" part at the end was a requirement for my specific project but I'm sharing it too, as it took a while to find it
The best and the easiest way to sort any list of objects in Java (Java 8 and above).
Lets sort a basket of fruits based on the property "fruitName"
Fruit POJO:
class Fruit
{
int price;
String fruitName;
public Fruit(int price, String fruitName) {
super();
this.price = price;
this.fruitName = fruitName;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
#Override
public String toString() {
return "Fruits [price=" + price + ", fruitName=" + fruitName + "]";
}
}
Now lets add fruits into a list and then sort it
List<Fruit> basketOfFruits = new ArrayList<>();
basketOfFruits.add(new Fruit(123, "oranges"));
basketOfFruits.add(new Fruit(45, "nectarine"));
basketOfFruits.add(new Fruit(369, "blueberries"));
basketOfFruits.add(new Fruit(248, "apple"));
basketOfFruits.add(new Fruit(968, "peaches"));
basketOfFruits.add(new Fruit(436, "grapes"));
basketOfFruits.add(new Fruit(596, "figs"));
//sorting by the property fruitName
Collections.sort(basketOfFruits, (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());});
You can now print the list (i.e basketOfFruits) and the fruits in the list would be sorted in ASCENDING order (lexicographically).
The output would look like this:
[Fruits [price=248, fruitName=apple], Fruits [price=369, fruitName=blueberries], Fruits [price=596, fruitName=figs], Fruits [price=436, fruitName=grapes], Fruits [price=45, fruitName=nectarine], Fruits [price=123, fruitName=oranges], Fruits [price=968, fruitName=peaches]]
Instead of Collections.sort(), Java streams can also be used (Java 8 and above). The following is the code using Java streams
List<Fruit> sortedFruits = basketOfFruits.stream().sorted( (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());}).collect(Collectors.toList());
here the list is sorted in the same manner as Collections.sort(), but the sorted items would be stored/collected in another list "sortedFruits". So, if we want to print the sorted items of the list, we need to print "sortedFruits" instead of "basketOfFruits" in this case

Set working incorrectly in JAVA

I just want to remove duplicate elements from list. To do this I have written a POJO class Student as :
class Student{
private String roll;
private String name;
public Student(String roll, String name) {
this.roll = roll;
this.name = name;
}
#Override
public boolean equals(Object obj) {
Student st = (Student) obj;
return st.getRoll().equals(roll);
}
public String getRoll() {
return roll;
}
public void setRoll(String roll) {
this.roll = roll;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return roll ;
}
}
And a test class as below :
public class TestMain {
public static void main(String[] args) {
List<Student> list = Arrays.asList(
new Student("19", "goutam kumar singh"),
new Student("20", "goutam kumar singh"),
new Student("11", "goutam kumar singh"),
new Student("19", "goutam kumar singh")
);
List<Student> arrayList = new CopyOnWriteArrayList<>(list);
Set<Student> set = new HashSet<>();
for(Student st : arrayList)
set.add(st);
System.out.println(set);
}
}
but in the output all the four elements in the set but i am expecting only three element as fourth element is duplicate and must be removed.
Where I am going wrong?
You have to override the hashCode() method too. Override hashCode() methods for those property for which you override equals() method.
While working with Collection it's useful to remember the contract between hashCode() and equals() method -
1. If two objects are equal, then they must have the same hash code.
2. If two objects have the same hashcode, they may or may not be equal.
For more information you may visit this link
A HashSet stores elements internally as keys in a HashMap. Because of this, it will use your Student object as the keys for that map, using the hash code for each object. Since you don't provide an implementation for this method hashCode(), the default one from Object is used and each of your students will have a different hash code.
You must extend this method in your class, being aware of the equals-hashCode contract. If two objects are equal, they must have the same hashCode (the reverse isn't allways true). For further details see this Object.hashCode()

Java HashMap return value not confirming with my understanding of equals and hashcode

The output of the following code sample is:
{1--e=e2, 2--e1=e1}
package com.sid.practice;
import java.util.HashMap;
import java.util.Map;
public class InputOutputPractice
{
public InputOutputPractice()
{
}
public static void main(String[] args)
{
Employee e = new InputOutputPractice().new Employee(1, "e");
Employee e1 = new InputOutputPractice().new Employee(2, "e1");
Employee e2 = new InputOutputPractice().new Employee(1, "e2");
Map m = new HashMap();
m.put(e, "e");
m.put(e1, "e1");
m.put(e2, "e2");
System.out.println(m);
}
class Employee
{
public Employee(int id, String name)
{
this.id=id;
this.name = name;
}
private int id;
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
#Override
public boolean equals(Object obj)
{
return ((Employee)obj).getId()==(this.getId());
}
#Override
public int hashCode()
{
return Integer.valueOf(getId()).hashCode();
}
#Override
public String toString()
{
return this.id + "--" + this.name;
}
}
}
I do not understand how the Object e2 was able to overwrite the key in Object e, but not the value. In my understanding the output should have been:
{1--e2=e2, 2--e1=e1}
Actually, you got it backwards. The value was overridden. The key wasn't replaced since as far as HashMap is concerned, e and e2 are identical.
Your output is {1--e=e2, 2--e1=e1}:
key = e, value = "e2" (which overrode the old value "e")
key = e1, value = "e1"
The Javadocs for HashMap state for the put method:
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
Hence, the key is not overwritten, only the value.
The java.util.HashMap implementation does not replace the existing key when it is equal to the key supplied in the put() call. So, your third put() checks the existing contents of the map, finds an existing equal key and just updates the associated value.
This illustrates why equals() and hashCode() should generally take all properties into account as objects which are considered equal are considered interchangeable by many of the util classes.
The reason behind the output {1--e=e2, 2--e1=e1} is :
Map do not replaces key it only does so for value when there is match (present on the basis of key) in the existing Map.
So applies in this case:
Here e is equal to e2 for Map. When Map search for location to put m.put(e2, "e2"); it goes to location where e--"e1" is present and replaces "e1" by "e2" and leaves the key i.e e in this case intact

How to customize java hashset for checking duplication on the basis of set object instance variable value

By default set can not have a duplicate records, but suppose I have class
class Employee {
Integer emp_id;
String name;
// other fields and their getter
Employee(String name) {
emp_id++;
this.name=name;
}
}
Now I declare a set in my other class
set<Employee> empSet = new HashSet<Employee>();
Employee e1 = new Employee ("abc");
Employee e2 = new Employee ("abc");
so while insert it to the set
empSet.add(e1);
empSet.add(e2);
Then first e1 add to set but second e2 returns false.
Now what I want that there is no duplication of their name. So I want to check while insert into set.
You should override the hashcode and the equals method of Employee class.
Where you can ensure the policy of duplication on equals method by populating different hashcode for different the Objects.
Find a example of same implementation.
You can use COMPARATOR class to remove duplicates... You have to override compare method... For example code refer this page:http://java2novice.com/java-collections-and-util/treeset/duplicate-objects/
As other users mentioned, you need to override hashCode() and equals() methods of Employee class that determines if any two Employee objects are equal/same.
Below is sample implementation for your quick understanding. This would not allow you to add two Employee objects with same name into the Set.
public class Employee {
static int emp_id;
String name;
// other fields and their getter
Employee(String name) {
emp_id++;
this.name=name;
}
#Override
public int hashCode() {
int code = name.hashCode();
return code;
}
#Override
public boolean equals(Object obj) {
Employee empObj = (Employee) obj;
if(empObj.name.equalsIgnoreCase(this.name)) {
return true;
}
return false;
}
}
Hope this would be helpful.

Categories

Resources