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

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

Related

finding the commen objects in two arraylist [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Need to find the common objects between to arraylist. Both of them are VarList type which is the simple POJO class. My comparison return all the elements inside the database list , Need to have a common elements (which as you can see they are objects) between two arraylists and add the them into the new list.
VarList class
public class VarList {
private int number;
private int age;
private String name;
public VarList(int number, int age, String name) {
super();
this.number = number;
this.age = age;
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
my solution which has a problem
//database arraylist
ArrayList<VarList> database=new ArrayList<VarList>();
database.add(new VarList(105,19,"b"));
database.add(new VarList(101,18,"c"));
database.add(new VarList(106,54,"database"));
//object array list
ArrayList<VarList> object=new ArrayList<VarList>();
object.add(new VarList(105,19,"b"));
database.add(new VarList(106,54,"database"));
List<VarList> resultList = new ArrayList<VarList>();
for(VarList user1 : database) {
for(VarList user2 : object) {
if(user1.getName().equals(user2.getName())) {
resultList.add(user2);
}
System.out.println(resultList);
}
}
Override equals & hashCode
You need to define overrides of equals and hashcode methods in your VarList class. Your class inherits these methods from Object.
Also, think harder about naming things. The VarList class is not a list, it is an element in your list. Surely it has an actual descriptive name. The second ArrayList you declare is named 'object'?!? Please don't name things object, ever. Call it testList or something.
Finally, your System.out is inside the resultList loop, so its output is likely to confuse you. Or maybe that was intentional. Just realize that it's going to output it once for every element in resultList.
Instead of implementing your own for loop to compare the elements of 2 ArrayList, you could use retainAll(list) method of the Collection class.
Here is the sample Usage:
SimplePojo.java
import java.util.Objects;
public class SimplePojo {
private String name;
private int age;
public SimplePojo(String name, int age) {
this.name = name;
this.age = 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 String toString() {
return "SimplePojo{" + "name='" + name + '\'' + ", age=" + age + '}';
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SimplePojo that = (SimplePojo) o;
return age == that.age && Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(name, age);
}
}
Client.java
import java.util.ArrayList;
import java.util.List;
public class ListCommonElements {
public static void main(String[] args) {
List<SimplePojo> list1 = new ArrayList<>();
list1.add(new SimplePojo("Dave",49));
list1.add(new SimplePojo("Smith",40));
list1.add(new SimplePojo("Johnson",32));
System.out.println("List 1: " +list1.toString());
List<SimplePojo> list2 = new ArrayList<>();
list2.add(new SimplePojo("Dave",49));
list2.add(new SimplePojo("Smith",40));
list2.add(new SimplePojo("Steve",32));
System.out.println("List2: "+list2.toString());
list1.retainAll(list2);
System.out.println("Common ELements: " + list1.toString());
}
}
Notice How I am overriding equals and hashCode method (You can autogenerate it if using IntelliJ ).
The reason to do it is your list is not of primitive type, so you need to tell what does equal mean to you (so you can get common elements ) and in the current implementation, I am saying that if both name and age are the same then only I would call 2 Object equal.

Java Arraylist of classes (custom data types), how to use contains

in a simple ArrayList, I can use contains like this :
ArrayList<String> names = new ArrayList<String>();
names.add("John");
names.add("Peter");
String find = "Peter";
if (names.contains(find))
System.out.println("I FOUND IT");
but how do I use contains (or something similar), if I have an ArraList of classes (custom data type)?
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name= name;
this.age= age;
}
public String getName() {
return this.name;
}
public String getAge() {
return this.age;
}
}
ArrayList<Person> somePerson = new ArrayList<Person>();
somePerson.add(new Person("John","25"));
somePerson.add(new Person("Peter","84"));
How do I find in this ArrayList just the name "Peter", or just the score of "84"?
I'm using loops and
if (somePerson.get(i).getName().contains(find))
but is there a way without loops, like in the simple ArrayList above?
To quote https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html:
Many methods in Collections Framework interfaces are defined in terms
of the equals method. For example, the specification for the
contains(Object o) method says: "returns true if and only if this
collection contains at least one element e such that (o==null ?
e==null : o.equals(e))."
[...]
Implementations are free to implement
optimizations whereby the equals invocation is avoided, for example,
by first comparing the hash codes of the two elements. (The
Object.hashCode() specification guarantees that two objects with
unequal hash codes cannot be equal.)
In other words, your custom classes need to implement the equals() and hashCode() methods according to the contract of those methods, which states that equal objects should have equal hash codes. (But equal hash codes do not necessarily mean that the objects are equal, though it should be avoided to have implementations that easily result in such collisions.)
You have to overide the equals method in the Person class as follows:
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this.name = name;
}
public Person(int age) {
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
#Override
public boolean equals(Object other) {
if (!(other instanceof Person)) {
return false;
}
Person p = (Person) other;
try {
return this.name.equals(p.name) || this.age == p.age;
} catch (Exception e) {
return this.age == p.age;
}
}
#Override
public String toString() {
return name + " " + age;
}
}
Here is the main code
import java.util.ArrayList;
import org.apache.commons.lang3.ArrayUtils;
public class MainDemo {
public static void main(String[] args) {
ArrayList<Person> somePerson = new ArrayList<Person>();
Person person1 = new Person("John", 25);
Person person2 = new Person("Peter", 84);
somePerson.add(person1);
somePerson.add(person2);
System.out.println("Is John there?: "+ somePerson.contains(new Person("John"))); // true
System.out.println("Is Paul there?: "+ somePerson.contains(new Person("Paul"))); // false
System.out.println("Is age 84 (Peter) there?: "+ somePerson.contains(new Person(84))); //true
System.out.println("Is there a person with age 9 ?: "+ somePerson.contains(new Person(9))); //false
searchPersonByName(somePerson, "Peter");
searchPersonByName(somePerson, "John");
searchPersonByName(somePerson, "Paul"); // not found
searchPersonByAge(somePerson, 25); // will print John 25
searchPersonByAge(somePerson, 84); //will print Peter 84
searchPersonByAge(somePerson, 102); // not found
}
public static void searchPersonByName(ArrayList<Person> personsList, String name){
Person[] personArray = personsList.toArray(new Person[personsList.size()]); // converting arrayList to Array
String str = personsList.contains(new Person(name))?personsList.get(ArrayUtils.indexOf(personArray, new Person(name))).toString():"Not found";
System.out.println(str);
}
public static void searchPersonByAge(ArrayList<Person> personsList, int age){
Person[] personArray = personsList.toArray(new Person[personsList.size()]);
String str = personsList.contains(new Person(age))?personsList.get(ArrayUtils.indexOf(personArray, new Person(age))).toString():"Not found";
System.out.println(str);
}
}
Here you have the output:
Is John there?: true
Is Paul there?: false
Is age 84 (Peter) there?: true
Is there a person with age 9 ?: false
Peter 84
John 25
Not found
John 25
Peter 84
Not found

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

Sorting string property using comparable

I have an employee class & a client class. I am able to sort using compareTo() via Employee's id & age as they are of integer type. But how do I sort by employee's name or salary?
compareTo is not accepting any data type other than int, throws a compile time exception.
public class Employee implements Comparable<Employee> {
private int id;
private String name;
private int age;
private long salary;
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public long getSalary() {
return salary;
}
public Employee(int id, String name, int age, int salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
#Override
public int compareTo(Employee emp) {
//let's sort the employee based on id in ascending order
//returns a negative integer, zero, or a positive integer as this employee id
//is less than, equal to, or greater than the specified object.
return (this.age - emp.age);
}
#Override
//this is required to print the user friendly information about the Employee
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]";
}
}
Client class
import java.util.Arrays;
public class Test {
public static void main(String a[]){
//sorting custom object array
Employee[] empArr = new Employee[4];
empArr[0] = new Employee(10, "Mikey", 25, 10000);
empArr[1] = new Employee(20, "Arun", 29, 20000);
empArr[2] = new Employee(5, "Lisa", 35, 5000);
empArr[3] = new Employee(1, "Pankaj", 32, 50000);
//sorting employees array using Comparable interface implementation
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
}
}
I just googled seems like I can also achieve it by implementing comparator
public static Comparator<Employee> SalaryComparator = new Comparator<Employee>() {
#Override
public int compare(Employee e1, Employee e2) {
return (int) (e1.getSalary() - e2.getSalary());
}
};
Which one is advisable using the comparator or
#Override
public int compareTo(Employee emp) {
// compare salaries, using the builtin Long.compare:
return Long.compare (salary, emp.salary);
}
If you want to sort based on name, you can try
#Override
public int compareTo(Employee emp) {
return this.name.compareTO(emp.name);
}
Basically, you want to sort your class based on several properties. The trick here is to decide the order in which they should be evaluated, and treat one as a Comparable on its own right. If the comparison isn't 0 - you found which instance should come before the other, and you can just return the value. If not, you need to evaluate a different property.
E.g., assuming the properties you want to use are id, age, name and salary:
#Override
public int compareTo(Employee emp) {
// compare IDs:
int cmp = Integer.compare(id, emp.id);
if (cmp != 0) {
return cmp;
}
// compare ages:
cmp = Integer.compare(age, emp.age);
if (cmp != 0) {
return cmp;
}
// compare names. Luckily, Strings are comparable:
cmp = name.compareTo(emp.name);
if (cmp != 0) {
return cmp;
}
// compare salaries, using the builtin Long.compare:
return Long.compare (salary, emp.salary);
}
I would implement compareTo this way:
public int compareTo(Employee emp) {
return Integer.compare(this.age, emp.age);
}

How to maintain only non-equal object in HashSet

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

Categories