Edit element in arraylist, find index? - java

I'm about to create two methods for creating and changing customer profiles. Creating profile is no problem. Everything seems to go well there. But, when I shall then go in and change the profile, I get it not to work.
The indexOf() gives me -1, even though the value I search for available :S
Anyone have a good solution to this?
The problem is in the editProfile-method!
public class Profile{
String name;
long id;
int accNr = 1000;
double balance;
}
ArrayList<Profile> profileList = new ArrayList<Profile>();
public boolean newProfile(long id, String name, int amount){
Profile newProfile = new Profile();
Profile accNr = new Profile();
int ACC = accNr.accNr++;
newProfile.accNr = ACC;
newProfile.id = id;
newProfile.name = name;
newProfile.balance = amount;
profileList.add(newProfile);
return true;
}
public void editProfile(long id, String newName){
int ID = (int)id;
System.out.print(ID);
int index = profileList.indexOf(id);
System.out.print(index);
profileList.get(index);
}

The indexOf method will use the equals method to determine if your Profile exists in the list. You must override the equals method in Profile to return the proper result.
Second, it won't find your Profile, because you are passing a long to indexOf, and neither a long nor a Long will be found in the list. If you must retrieve the Profile by a long, then it makes more sense to have a Map<Long, Profile> instead of an ArrayList<Profile>. Then you can call get(id) to retrieve the Profile. Usually, you should override the hashCode method if you override equals, but because a Profile isn't being used as the key here, it's not necessary.

profileList contains Profile instances and you are trying to get the index of a long.
One solution would be overriding equals method in Profile class.
#Override
public boolean equals(Object obj) {
...
}
Another solution (not very recommended) would be looping over elements of profileList and manually checking for matches, like:
for (Profile element : profileList)
if (element.getID() == id)
...

Probably your Profileneeds to override equals and hashCode methods. Eclipse can generate then, Would be like taking your example:
public class Profile {
String name;
long id;
int accNr = 1000;
double balance;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + accNr;
long temp;
temp = Double.doubleToLongBits(balance);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Profile other = (Profile) obj;
if (accNr != other.accNr)
return false;
if (Double.doubleToLongBits(balance) != Double
.doubleToLongBits(other.balance))
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}

Related

Hashcode/Equals override with number range rather than direct equals?

Let's say I have an object that has a number range as two properties, a start and an end to define a numeric band. I want to load these objects into a HashMap. But when I look up on the hashcode and equals with a key object, I want to match on a given number that falls into the range. So I want the hashcode and equals to take any number in a key, and return the object where it falls between the startRange and endRange. So if an object has a startRange of 7 and endRange of 14, passing 9 in a key would retrieve that object. How do I do this? The equals would be straightforward as I would use >= and <=, but I don't want to break the hashcode... I know I can iterate item by item but I'd like to avoid that for performance reasons.
public class MyClass {
private final int marketID;
private final int startRange;
private final int endRange;
...
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + marketID;
/*I don't want to match on startRange and endRange, I want to fall between it! */
result = prime * result + endRange;
result = prime * result + startRange;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyClass other = (MyClass) obj;
if (endRange!= other.endRange)
return false;
if (marketID != other.marketID)
return false;
if (startRange!= other.startRange)
return false;
return true;
}
}

Compact equals and hashcode

I have a bean with 4 attributes:
user
institutionId
groupId
postingDate
I use Eclipse to generate equals and hashcode but the resulting code is not pretty. Is there a compact way to do the same? Assuming I want equals & hashcode to use all the attributes or a subset of them.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((groupId == null) ? 0 : groupId.hashCode());
result = prime * result + ((institutionId == null) ? 0 : institutionId.hashCode());
result = prime * result + ((postingDate == null) ? 0 : postingDate.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ManGroupKey other = (ManGroupKey) obj;
if (groupId == null) {
if (other.groupId != null)
return false;
} else if (!groupId.equals(other.groupId))
return false;
if (institutionId == null) {
if (other.institutionId != null)
return false;
} else if (!institutionId.equals(other.institutionId))
return false;
if (postingDate == null) {
if (other.postingDate != null)
return false;
} else if (!postingDate.equals(other.postingDate))
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}
In Java 7
public int hashCode() {
return Objects.hash(groupId, institutionId, postingDate, user);
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
// cast to correct class
Target o = (Target)obj;
return Objects.equals(groupId, o.groupId) &&
Objects.equals(institutionId, o.institutionId) &&
Objects.equals(postingDate, o.postingDate) &&
Objects.equals(user, o.user);
}
You could compact the code down, but the odds are far higher that you would introduce bugs than that you would do anything useful. All the parts of the equals and hash code method are there for a reason.
If it's bothering you most IDEs have a folding editor, just click the little yellow box (usually) and all the contents of the method get hidden away.
Instead of using the eclipse generated code, you can use Apache-common-langs(http://commons.apache.org/proper/commons-lang/) class HashCodeBuilder and EqualsBuilder to do this:
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this);
}
hashCode:
Either:
#Override
public int hashCode() {
return Objects.hash(user, institutionId, groupId, postingDate);
}
Or:
#Override
public int hashCode() {
int result = 17;
result = 31 * result + Objects.hashCode(user);
result = 31 * result + Objects.hashCode(institutionId);
result = 31 * result + Objects.hashCode(groupId);
result = 31 * result + Objects.hashCode(postingDate);
return result;
}
Equals:
public boolean equals(Object obj){
if (obj == this){
return true;
}
if (! (obj instanceof ManGroupKey)){
return false;
}
ManGroupKey other = (ManGroupKey) obj;
return Objects.equals(user, other.user)
&& Objects.equals(institutionId, other.institutionId)
&& Objects.equals(groupId, other.groupId)
&& Objects.equals(postingDate, other.postingDate);
}
You can at least remove one level of nesting by removing the other.x != null check.
Comparing a value in this way: x.equals(y) will always return false when y is null.
Aside from that: the .equals() method is a good example where a bit of reflection can be handy, possible extracted out into a generic utility method. All you have to do is run through the different fields and see if they're equal in the two objects, that can be done in a few lines.
Obviously that is only feasible when you actually want to compare each field (or you'll have to add some additions to it which let you choose the fields).
I think the library, that can suite you is apache common. It provides EqualsBuilder and HashCodeBuilder classes, that do exactly what you are looking for.
Consider this question for details: Apache Commons equals/hashCode builder
Here are some code snippets:
public class Bean{
private String name;
private int length;
private List<Bean> children;
#Override
public int hashCode(){
return new HashCodeBuilder()
.append(name)
.append(length)
.append(children)
.toHashCode();
}
#Override
public boolean equals(final Object obj){
if(obj instanceof Bean){
final Bean other = (Bean) obj;
return new EqualsBuilder()
.append(name, other.name)
.append(length, other.length)
.append(children, other.children)
.isEquals();
} else{
return false;
}
}
}

Is the below is correct equals and hashCode implementation in Java?

When an object's value is equal i need to return it is true.
example
#Override
public int hashCode() {
return new HashCodeBuilder().append(value).toHashCode();
}
#Override
public boolean equals(final Object obj) {
if (obj instanceof NumberValTO) {
final NumberValTO other = (NumberVal) obj;
return new EqualsBuilder().append(value, other.getValue()).isEquals();
}
return false;
}
Is the above is fine or wrong?
I saw in few applications where hashcode is being multiple with each and every field of the table and not sure whether it is a correct approach.
Assume an entity has 4 columns
Assume an entity has 2 columns
Which is the best approach to generate the same?
Also, do we need to implement hashcode() and equals() for a hibernate entity class?
Thanks.
Yes it's fine, assuming those are the Apache Commons helper classes you're using. #Vino is correct to point out that adding if (obj == this) return true; to the start of your equals method can be a worthwhile optimisation, but your methods look correct as is.
Your example is fine as it provides a fair implementation of equals and hashcode methods. I am using this way in my project.
To answer you 1 question You can read through http://www.ideyatech.com/2011/04/effective-java-equals-and-hashcode/
To answer you 2 question follow link : Hibernate: When is it necessary to implement equals() and hashCode(), and if so, how?
Your equals and hashCode methods are both using the EqualsBuilder and HashCodeBuilder from Apache's commons-lang correctly, though you should add a reference check - if (obj == this) return true - to the equals method.
An argument I've recently been given against using EqualsBuilder and HashCodeBuilder was that it was less performant, so I tested it.
I created a HashMap, added 10K entries and then compared the look-up times for the same key object, once using a traditional equals and hashCode, then again with the EqualsBuilder and HashCodeBuilder. The idea is that getting the values by their key will hammer the both the equals and hashCode methods and give a good comparison of their performance.
While the EqualsBuilder and HashCodeBuilder implementations where slower, the difference was in the region of 60ns with an average look-up time of about 320ns for the commons-lang implementation and 260ns for the traditional approach (I've shown the code I used below).
IMHO this performance penalty should only be a concern where the equals and hashCode are called repeatedly over a large set of objects and even then, only where the small performance gain is worth sacrificing that clarity of you code.
Anyway, here's the class I used to test the performance difference:
public class Example
{
private Type operationType;
private long identity;
private String name;
private BigDecimal value;
public Example(Type operationType, long identity, String name, BigDecimal value)
{
this.operationType = operationType;
this.identity = identity;
this.name = name;
this.value = value;
}
public Example(Example example)
{
this.operationType = example.operationType;
this.identity = example.identity;
this.name = example.name;
this.value = example.value;
}
public long getIdentity()
{
return identity;
}
public String getName()
{
return name;
}
public BigDecimal getValue()
{
return value;
}
#Override
public boolean equals(Object obj)
{
if (Type.TRADITIONAL.equals(operationType))
{
if (this == obj)
{
return true;
}
if (obj == null || getClass() != obj.getClass())
{
return false;
}
Example example = (Example)obj;
return getIdentity() == example.getIdentity()
&& ((getName() == null && example.getName() == null) || getName().equals(example.getName ()))
&& ((getValue() == null && example.getValue() == null) || getValue().equals(example.getValue()));
}
else
{
return this == obj || obj instanceof Example &&
new EqualsBuilder()
.append(getIdentity(), ((Example)obj).getIdentity())
.append(getName(), ((Example)obj).getName())
.append(getValue(), ((Example)obj).getValue())
.isEquals();
}
}
#Override
public int hashCode()
{
if (Type.TRADITIONAL.equals(operationType))
{
int result = (int)(getIdentity() ^ (getIdentity() >>> 32));
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
else
{
return new HashCodeBuilder().append(getIdentity()).append(getName()).append(getValue()).toHashCode();
}
}
public static enum Type
{
TRADITIONAL,
COMMONS
}
}
And here's the test:
public class ExampleTest
{
#Test
public void testMapLookupWithTraditional() throws Exception
{
double total = 0;
for (int i = 0; i < 10; i++)
{
total += testMapLookup(Example.Type.TRADITIONAL);
}
System.out.println("Overall Average: " + (total / 10));
}
#Test
public void testMapLookupWithCommons() throws Exception
{
double total = 0;
for (int i = 0; i < 10; i++)
{
total += testMapLookup(Example.Type.COMMONS);
}
System.out.println("Overall Average: " + (total / 10));
}
private double testMapLookup(Example.Type operationType) throws Exception
{
Map<Example, String> examples = new HashMap<Example, String>();
while (examples.size() < 10000)
{
long now = System.currentTimeMillis();
Example example = new Example(
operationType,
now,
"EXAMPLE_" + now,
new BigDecimal(now)
);
examples.put(example, example.getName());
Thread.sleep(1);
}
int count = 0;
double average = 0;
double max = 0;
double min = Double.MAX_VALUE;
for (Example example : examples.keySet())
{
Example copiedExample = new Example(example);
long start = System.nanoTime();
examples.get(copiedExample);
long duration = System.nanoTime() - start;
average = ((average * count++) + duration) / count;
if (max < duration) max = duration;
if (min > duration) min = duration;
}
System.out.println("Average: " + average);
System.out.println("Max: " + max);
System.out.println("Min: " + min);
return average;
}
}

HashMap in java cannot hash MyObject

I have defined a simple private class named SetOb which contains an int and a Set data structure. I have a HashMap in the 'main' method with SetOb as Key and Integer as value. Now as you can see in the main method, when I feed the HashMap with a SetOb instance and then look for an instance with exactly the same value, it returns 'null'. This has happened with me quite a few times before when I use my own defined data structures like SetOb as Key in HashMap. Can someone please point me what am I missing ?
Please note that in the constructor of SetOb class, I copy the Set passed as argument.
public class Solution {
public static Solution sample = new Solution();
private class SetOb {
public int last;
public Set<Integer> st;
public SetOb(int l , Set<Integer> si ){
last = l;
st = new HashSet<Integer>(si);
}
}
public static void main(String[] args) {
Map<SetOb, Integer> m = new HashMap< SetOb, Integer>();
Set<Integer> a = new HashSet<Integer>();
for(int i =0; i<10; i++){
a.add(i);
}
SetOb x = sample.new SetOb(100, a);
SetOb y = sample.new SetOb(100, a);
m.put(x,500);
Integer val = m.get(y);
if(val!= null) System.out.println("Success: " + val);
else System.out.println("Failure");
}
}
Your x and y are not the same object instances hence contains is not able to match y against x, which ends up not finding the matching key/value in the Map.
If you want the match to succeed, please implement(override) hasCode & equals method in SetOb which will compare the field values.
Sample methods(Eclipse generated) as below:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + last;
result = prime * result + ((st == null) ? 0 : st.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SetOb other = (SetOb) obj;
if (last != other.last)
return false;
if (st == null) {
if (other.st != null)
return false;
} else if (!st.equals(other.st))
return false;
return true;
}
The default implementation of hashCode uses object identity to determine the hash code. You will need to implement hashCode (and equals) in your private class if you want value identity. For instance:
private class SetOb {
public int last;
public Set<Integer> st;
public SetOb(int l , Set<Integer> si ){
last = l;
st = new HashSet<Integer>(si);
}
#Override
public boolean equals(Object other) {
if (other.class == SetOb.class) {
SetOb otherSetOb = (SetOb) other;
return otherSetOb.last == last && otherSetOb.st.equals(st);
}
return false;
}
#Override
public int hashCode() {
return 37 * last + st.hashCode();
}
}
SetOb needs to override the hashCode() and thus the equals() methods.
Hash-based collections use these methods to store (hashCode()) and retrieve (hashCode()) and equals()) your objects.

Regarding Object Comparison

I am having a java class Rec. I have two instance of it Rec1 and Rec2. I want to check whether the values of Rec1 and Rec2 are equal. If i do Rec1.equals(Rec2) is it correct way of doing it?
class Rec {
private BigDecimal RecordId = null;
private BigDecimal recSubNum = null;
private BigDecimal FileId = null;
private String Category = null;
private BigDecimal status = null;
private BigDecimal errorCode = null;
}
You need to implement the equals() and hashCode() methods to implement object equality in Java:
class Rec {
private BigDecimal recordId = null;
private BigDecimal recSubNum = null;
private BigDecimal FileId = null;
private String category = null;
private BigDecimal status = null;
private BigDecimal errorCode = null;
#Override
public int hashCode() {
int ret = 41;
ret = hc(ret, recordId);
ret = hc(ret, recSubNum);
ret = hc(ret, fieldId);
ret = hc(ret, category);
ret = hc(ret, status);
ret = hc(ret, errorCode);
return ret;
}
#Override
public boolean equals(Object ob) {
if (ob == null) return false;
if (ob.getClass() != Rec.class) return false;
Rec r = (Rec)ob;
if (!eq(r.recordId, record)) return false;
if (!eq(r.recSubNum, recSubNum)) return false;
if (!eq(r.fileId, fileId)) return false;
if (!eq(r.category, category)) return false;
if (!eq(r.status, status)) return false;
if (!eq(r.errorCode, errorCode)) return false;
return true;
}
private static boolean eq(Object ob1, Object ob2) {
return ob1 == null ? ob2 == null : ob1.equals(ob2);
}
private static int hc(int hc, Object field) {
return field == null ? hc : 43 + hc * field.hashCode();
}
}
Note: the equals/hashCode contract for Java means that for any two objects a and b:
a.equals(b) == b.equals(a)
and if two objects are equal then a.hashCode() must equal b.hashCode().
Edit: there are two ways of checking if the types match. Either:
if (ob == null) return false;
if (ob.getClass() != Rec.class) return false;
or
if (!(ob instanceof Rec)) return false;
These two do different things and you should select the correct one depending on what you want to do. I generally prefer the first one unless you know you need the second. What's the difference?
class A {
public int i;
public boolean equals(Object ob) {
if (!(ob instanceof A)) return false;
return i == ((A)ob).i;
}
}
Looks reasonable right? What if the class gets extended:
class B extends A {
public int j;
public boolean equals(Object ob) {
if (!(ob instanceof B)) return false;
if (!super.equals(ob)) return false;
return j == ((B)ob).j;
}
}
Still looks reasonable? It's broken.
A a = new A();
a.i = 10;
B b = new B();
b.i = 10;
b.j = 20;
System.out.println(a.equals(b)); // true! Is this really what you want?
System.out.println(b.equals(a)); // false! Different to previous = problem.
That's why I favour getClass() over instanceof unless I really want subclass equality.
if Rec is a user defined class then you really should override the equals method otherwise it will just call the equals method in the Object class;
something like :
public boolean equals(Rec x){
//check here to see if the references are the same, if so return true
if(this == x) return true;
//if they aren't the same object then check all the fields for equality
if (category.equals(x.category) && etc etc) return true;
else return false;
}

Categories

Resources