How to use a String in an Entity class hash code? - java

I'm making a web app that queries an SQL db. I'm under the impression that I need to use entity classes and facade classes to allow persistence - across the whole site. The entity class templates have hashcodes and 1.) Im not sure if I need them and 2.) If I do, they want int's but all I have are String so, how to convert them to int and then back to String? Because I need the String value to appear on the site and the hash wants int's.
heres the code (imports have been remove to protect the innocent...):
#Embeddable
public class ComputerOwnersPK implements Serializable {
#Basic(optional=false)
#NotNull
#Column(name="Computer_Name")
private int computerNameId;
#Basic(optional=false)
#NotNull
#Column(name="User_ID")
private int userId;
public ComputerOwnersPK() {
}
public ComputerOwnersPK(int computerNameId,int userId) {
this.computerNameId=computerNameId;
this.userId=userId;
}
public int getComputerNameId() {
return computerNameId;
}
public void setComputerNameId(int computerNameId) {
this.computerNameId=computerNameId;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId=userId;
}
#Override
public int hashCode() {
int hash=0;
hash+=(int) computerNameId;
hash+=(int) userId;
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if(!(object instanceof ComputerOwnersPK)) {
return false;
}
ComputerOwnersPK other=(ComputerOwnersPK) object;
if(this.computerNameId!=other.userId) {
return false;
}
if(this.userId!=other.userId) {
return false;
}
return true;
}
#Override
public String toString() {
return "entity.ComputerOwnersPK[ computerNameId="+computerNameId+", userId="+userId+" ]";
}
}

Based on your comments I'm assuming you want computerNameId and userId to be Strings in your mapping and you have them mapped to ints because you don't know how to do the hashcode stuff.
In your hashCode method you should be able to concatenate the strings and then call hashcode on them. Very similar to what you are already doing.
private String computerNameId;
private String userId;
#Override
public int hashCode() {
// concatenate the interesting string fields
// and take the hashcode of the resulting String
return (computerNameId + userId).hashCode();
}
Make sure in your equals method you also change from != operators to !.equals method call for checking equality. Finally make sure you are keeping the contract between equals and hashCode or you could be in for some nasty surprises. Two objects that are equal must also have the same hashCode. Two objects that have the same hashCode may or may not be equal.

Related

remove duplicates in Set [duplicate]

This question already has answers here:
Why do I need to override the equals and hashCode methods in Java?
(31 answers)
Closed 8 months ago.
How can I avoid inserting duplicate elements in a Set? If I have:
Set<User> user=new HashSet<>();
User user1=new User("11","Mark",null,"1");
User user2=new User("11","Mark",null,"1");
User user3=new User("12","Helen",null,"2");
user.add(user1);
user.add(user2);
Log.d("main_activity_user", "la dimensione è" +String.valueOf(user.size()));
Adn User class is:
public class User {
public String uid;
public String name;
public String pversion;
public String upicture;
public User(String uid,
String name,
String upicture, String pversion ){
this.uid=uid;
this.name=name;
this.upicture=upicture;
this.pversion=pversion;
}
public String get_uid(){
return uid;
}
public String get_name(){
return name;
}
public String get_pversion(){
return pversion;
}
public String get_upicture(){
return upicture;
}
#Override
public boolean equals(Object obj) {
User newObj = (User)obj;
if (this.get_uid().equals( newObj.get_uid()))
return true;
else
return false;
}
}
Now the Set also stores duplicates and prints me 3 elements instead of two. Why?
I have never used the Set class before and I don't understand it. So, every time I use the Set class, do I have to Override the Equals method? Why? Doesn't the class delete duplicates automatically?
As it has been already said in the comments, your User class needs to honor the hashcode and equals contracts by overriding the equals() and hashCode() methods.
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
In your code, you're using a HashSet which is implemented as a HashMap under the hood. Instead, a HashMap is implemented as an array of buckets, where each entry is stored within a bucket based on the key's hashCode(). However, different keys may yield same hashcodes, so multiple entries may be listed within a same bucket. At that point, the HashMap has to resort to the equals() method to find the exact key within a bucket which corresponds to the inputted entry in order to retrieve or replace an element. This brief explanation shows you why it is so crucial to provide a proper definition of the hashCode() and equals() methods, because, as you could see, a HashMap heavily relies on these methods.
https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html
Here is a proper implementation of your User class where two users are said identical if they have same: uid, name, pversion and upicture. Instead, if two users are identical only by some of the mentioned fields, then you need to updated your equals() and hashCode() methods accordingly (they both must be based on the same fields).
public class User {
public String uid;
public String name;
public String pversion;
public String upicture;
public User(String uid, String name, String upicture, String pversion) {
this.uid = uid;
this.name = name;
this.upicture = upicture;
this.pversion = pversion;
}
public String getUid() {
return uid;
}
public String getName() {
return name;
}
public String getPversion() {
return pversion;
}
public String getUpicture() {
return upicture;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(uid, user.uid) && Objects.equals(name, user.name) && Objects.equals(pversion, user.pversion) && Objects.equals(upicture, user.upicture);
}
#Override
public int hashCode() {
return Objects.hash(uid, name, pversion, upicture);
}
}
Test Main
public class Main {
public static void main(String[] args) {
Set<User> user = new HashSet<>();
User user1 = new User("11", "Mark", null, "1");
User user2 = new User("11", "Mark", null, "1");
User user3 = new User("12", "Helen", null, "2");
user.add(user1);
user.add(user2);
System.out.println("la dimensione è: " + user.size());
}
}
Output
la dimensione è: 1

COMPARABLE - How to see if elements from objects are equals?

Im devoloping a program that i put some elements into my object within an ArrayList... this is my code
import java.util.ArrayList;
public class ListaConcepto {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<CompararListas> Lista = new ArrayList<CompararListas>();
CompararListas obj1 = new CompararListas("abc", 12.25, "lala", 2);
CompararListas obj2 = new CompararListas("abc", 13.50, "lala", 3);
CompararListas obj3 = new CompararListas("poc", 12.50, "jaja", 1);
Lista.add(obj1);
Lista.add(obj2);
Lista.add(obj3);
}
}
Then... this is my class with the interface Comparable... and i need a method to implement to see if elements are EQUALS then print the result.
public class CompararListas implements Comparable<CompararListas> {
private String referencia;
private double monto;
private String descripcion;
private double NumeroParte;
public CompararListas(String referencia, double monto, String descripcion, double numeroParte) {
this.referencia = referencia;
this.monto = monto;
this.descripcion = descripcion;
this.NumeroParte = numeroParte;
}
public double getMonto() {
return monto;
}
public void setMonto(double monto) {
this.monto = monto;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
public double getNumeroParte() {
return NumeroParte;
}
public void setNumeroParte(double numeroParte) {
NumeroParte = numeroParte;
}
public String getReferencia() {
return referencia;
}
public void setReferencia(String referencia) {
this.referencia = referencia;
}
#Override
public int compareTo(CompararListas o) {
// TODO Auto-generated method stub
return 0;
}
}
Remember Comparable is meant to be used to decide the relationship between to items for the purposes of ordering; it's not quite for equality. In fact, there's no requirement that any two comparable items must be equal.
In your case, you may want to order by NumeroParte, which means "Part Number" and seems like a sensible choice. Every type of data has a different way to be organized.
Your method may look something like
public int compareTo(ComprarListas o){
return this.NumeroParte - o.getNumeroParte();
}
Which works because both are integer numbers.
Or the appropriate property of your object - you may want to order based on price instead for instance.
If you want to know just if an object is equal to another you have to implemet the equals method (which doesn't requiere you to declare any interface, every class can do it)
#Override
public boolean equals(Object o) {
CompararListas other = (CompararListas) o;
return ...
}
with this method you can return what makes the two objects equals to you, if you just have to look for referencia.equals(other.referencia) or if you have to compare every property like referencia.equals(other.referencia) && monto == other.monto && ...
But if you want to compare elements in order to do something like ordering them there you have to implement the Comparable interface and implement the compareTo method
#Override
public int compareTo(CompararListas o) {
if (NumeroParte < o.NumeroParte)
return -1;
else if (NumeroParte > o.NumeroParte)
return 1;
return 0;
}
This will make the objects able to compare each other and for example know if one is "smaller" than other according to your criteria (in this example I only used NumeroParte and made it explicit to be easy to understand, but the key is that you can use any criteria you want to compare the objects and if you want order them later).
These are solutions to different problems, you have to identify which one is the better in your case.

Get command of a hashmap with a parameter different than the key in the hashmap?

I have a custom class as my key in my hashmap like so
// In the main function
HashMap<Drink, boolean> drinkMap = new HashMap<>();
// What I would like to be able to do:
drinkMap.get("beer");
// My drink Class which is used as the key
public class Drink implements Comparable<String> {
private String name;
private String info;
public String getName() {
return Name;
}
public Drink(String name, String info) {
this.name = name;
this.info = info;
}
}
What I want to do is have the get method for the hashmap compare the string that is passed in to Drink.name and if they are the same then return that hashmap entry, but I cannot figure out how to get this to work.
I tried implementing the equals and hashcode methods in my Drink class like so:
#Override
public int hashCode() {
return Name.hashCode();
}
#Override
public boolean equals(Object o) {
return o instanceof String && o.equals(Name);
}
But when I would do hashMap.get("beer") it kept returning null even though I know there exists a Drink object with the name "beer" in the map.
This is a terrible idea. You should always query a map with the same type (or a subtype thereof) as the intended key. Not doing that only opens you up to problems (as I'm sure you've started to notice).
You should consider either making the key of your map a String type, or querying your map by Drink.
(As to why your specific case isn't working: "beer".equals(drink) != drink.equals("beer").)

Apache Commons Lang3 Hashcode, Equals and ToString including Enums

We have few datatypes defined for our service response and request objects in a model. Recently we found a need of implementing ToString, HashCode and Equals on all such types to make use of these over comparison and assertions. Confirming from few source like What issues should be considered when overriding equals and hashCode in Java?, Right way to implement equals contract etc we followed implementing toString, equals and hashcode using org.apache.commons.lang3.builder.EqualsBuilder, HashCodeBuilder and ToStringBuilder as follows -
Response.java
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class Response {
private Integer value;
private Currency currency;
private Object edited;
public Response() {
}
public Response(Integer value, Currency currency, Object edited) {
this.value = value;
this.currency = currency;
this.edited = edited;
}
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public Object getEdited() {
return edited;
}
public void setEdited(Object edited) {
this.edited = edited;
}
#Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Response Response = (Response) o;
return new EqualsBuilder().append(value, Response.value).append(currency, Response.currency)
.append(edited, Response.edited).isEquals();
}
#Override public int hashCode() {
return new HashCodeBuilder(17, 37).append(value).append(currency).append(edited).toHashCode();
}
#Override public String toString() {
return "Response{" + "value=" + value + ", currency=" + currency + ", edited=" + edited + '}';
}
}
Currency.java
public enum Currency {
INR
}
On implementing these using the default library version, there is a thought around enums that comes to our mind -
Is it correct to use the default hashcode and equals from the library when a datatype might contain parameters including enums as well?
Is there a library(within commons would be great) support to implementing a correct optimized solution to overriding implementation of hashcode and equals?
On a side note does the library implementation needs an improvement here or is it correct to what exists?
Edit: Have added the implementation over an Object field(edited) in the class as well. The concern there being same if I override the hashCode and equals implementation for these as well.
Do I end up using an Object's hashcode which is different for different instances as it is mostly the memory mapped address?
Edit 2: I can also see a concern raised on the inconsistent implementation on HashCode for Enum values on JIRA

Remove duplicate objects from a ArrayList in Android

I know this has be discussed over and over again here, but none of the examples I've tried worked for me.
What I've got
I access the Call log from Android and I get a list of all calls made. Of course, here I get a lot of duplicates.
First I make a List
List<ContactObject> lstContacts = new ArrayList<ContactObject>();
Then I add objects into it
While (get some record in call log)
{
ContactObject contact = new ContactObject();
contact.SetAllProperties(......)
lstContacts.add(contact);
}
Set<ContactObject> unique = new LinkedHashSet<ContactObject>(lstContacts);
lstContacts = new ArrayList<ContactObject>(unique);
The Contact Object class is simple
public class ContactObject {
public ContactObject() {
super();
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof ContactObject))
return false;
return this.lstPhones == ((ContactObject) obj).getLstPhones();
}
#Override
public int hashCode() {
return lstPhones.hashCode();
}
private long Id;
private String name;
private List<String> lstPhones;
private String details;
//... getters and settres
}
What I need
I need to have a Contact only once in the list. As I've read around here there are a couple of things that can be done like Set, HashSet, TreeSet. TreeSet seems the best as it keeps the order just as I receive it from the Call log. I've tried to make my code work with it but no success. Could anyone be so kind to give me a sample code based on my example. Thank you for your time.
The Working Solution. Thank you all for your support, you've made my day.
In ContactObject override the two methods
#Override
public boolean equals(Object obj) {
if (!(obj instanceof ContactObject))
return false;
return lstPhones.equals(((ContactObject) obj).getLstPhones());
}
#Override
public int hashCode() {
return (lstPhones == null) ? 0 : lstPhones.hashCode();
}
//Getters and Setters and COnstructor....
Simply use it as
Set<ContactObject> unique = new LinkedHashSet<ContactObject>(lstContacts);
lstContacts = new ArrayList<ContactObject>(unique);
LinkedHashSet which keeps insertion-order can be used in your case.
HashSet: no order.
TreeSet: sorted set, but not keep insertion order.
EDIT: As Software Monkey commented, hashCode() and equals() should be overwritten in ContactObject to fit the hash-based Set.
Remove duplication of Custom Object
Example of Removing duplicate using Comparator
Lets suppose you have a class "Contact"
public class Contact implements Comparable<Contact> {
public String getName() {
return this.Name;
}
public void setName(String name) {
this.Name = name;
}
public String getNumber() {
return this.Number;
}
public void setNumber(String number) {
this.Number = number;
}
///// this method is very important you must have to implement it.
#Override
public String toString() {
return "\n" +"Name=" + name + " Number=" + Number;
}
Here is how you can remove duplicate entries using Set , just pass your list in the function and it will work for you. New list will be returned which will have no duplicated contacts.
public ArrayList<Contact> removeDuplicates(ArrayList<Contact> list){
Set<Contact> set = new TreeSet(new Comparator<Contact>() {
#Override
public int compare(Contact o1, Contact o2) {
if(o1.getNumber().equalsIgnoreCase(o2.getNumber())){
return 0;
}
return 1;
}
});
set.addAll(list);
final ArrayList newList = new ArrayList(set);
return newList;
}
It worked for me so please try and give me your feedback. Thanks
P.S: Credit goes to Nilanchala at this article
For sure you can use TreeSet to store only once but a common mistake is do not override hashCode() and equal() methods:
This can fit for you:
public boolean equals(Object obj) {
if (!(obj instanceof ContactObject))
return false;
return this.id == ((ContactObject) obj).getId(); // you need to refine this
}
public int hashCode() {
return name.hashCode();
}
List<ContactObject> listContacts = new ArrayList<ContactObject>();
//populate...
//LinkedHashSet preserves the order of the original list
Set<ContactObject> unique = new LinkedHasgSet<ContactObject>(listContacts);
listContacts = new ArrayList<ContactOjbect>(unique);
Use Set's instead.
Set's works as an Mathematical collection, so it doesn't allow duplicated elements.
So it checks the equality and the .equals() methods for each element each time you add an new element to it.

Categories

Resources