• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Devaka Cooray
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Jeanne Boyarsky
  • Tim Cooke
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Tim Moores
  • Mikalai Zaikin
  • Carey Brown
Bartenders:

Do you write equals() and hashCode() on your business objects?

 
Ranch Hand
Posts: 65
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

I'm not new to programming, but fairly new to Java. I've got a bunch of business objects - Agent, Client, Job. Some of the objects nest other objects.

I'm writing my test cases and asserting that an object assembled from the database matches and expected one and I find that writing a lot of comparisons for the attributes and wondering if I should go to the trouble of writing equals() and hashCode() for the business objects - then my tests will become shorter.

I understand hashCode() is a requiremnt if using HashMap, etc.

I'm just curious how many Java developers reading this go to the trouble of overriding and maintaining these methods?

Thanks,

Ed
 
Bartender
Posts: 2700
IntelliJ IDE Opera
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The equals method is to compare two objects if they are meaningful equal. This is just internal-state comparison.
Testsmethods there to test functionality (with different contexts and parameters). The two exist for two completely
different purposes.

Objects stored in a database are most of the time entities and these should imho always implement the hashCode
and equals methods. Because the programmer that writes the entitycode can't predict how another programmer will
use it and therefore should write code that follows contracts.

In your case I'm assuming that the methods where not implemented. In that case I would write the hashcode/equals
methods because then you can use them in your tests and other programmers can use the entities in hashmap etc.
 
Rancher
Posts: 4803
7
Mac OS X VI Editor Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Edward Winchester wrote:I understand hashCode() is a requiremnt if using HashMap, etc.



Its actually more subtle than you suggest. And, there are default equals() and hashCode() funcitons inherited from Object, so you don't have to do anything to use a HashSet/HashMap.

The question is really, when are business objects equal?

For example, if I have a Person class, and an instance that has the name of "Edward Winchester" and somewhere else, there is another Person with a name of "Edward Winchester" are they equal? Perhaps, perhaps the other Person is your great grandfather, or a guy over in England. So only you, the Business Object developer can decide what "equals()" really means you your application.

The default implementation of equals() is the same as the == operator, meaning that the objects are the same. Most business objects really want to mean "has the same value for all member variables" So when you want that, you have to implement equals() and then you have to implement hashCode().

Note: when the objects can have their member variables change, such as when the "Mary Winchester" object gets married can changes its name to "Mary Farrell" then the impact on hashCode() can be a big deal, and any objects already in a HashSet/HashMap may be lost.
 
Master Rancher
Posts: 4660
63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Edward wrote:I'm just curious how many Java developers reading this go to the trouble of overriding and maintaining these methods?


Well, I usually do. Pretty much any time I'm creating a class where I expect to one day use the equals() method, or to put it in a HashSet or HashMap. If I wanted to use equals(), but was fairly sure I didn't need to put the class in a HashMap or -Set, I would consider implementing hashCode thus:

That way, if the class ever does need a hash code, I'll get a nice clear error message, rather than mysterious and perplexing failures. But much more often, I'll simply implement both, as per the original specification.

These days, I will often simply use Pojomatic to provide simple implementations of equals(), hashCode(), and toString(). It's pretty simple to use, and requires minimal maintenance if you change the fields in a class. It's a little slower than a hand-made method would be, but in all applications I've worked on since finding Pojomatic, the performance difference is utterly negligible compared to other things in the system (e.g. network and database access). The ease of use is well worth a little extra slowness.

Since you're posting in Beginning, I would strongly encourage you to master how to write your own equals() and hashCode() methods (without Pojomatic) if you haven't already. Such fundamentals are important. But in terms of what to do as a working programmer - I encourage you to check out Pojomatic.

 
Ranch Hand
Posts: 449
Scala IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Edward Winchester wrote:writing a lot of comparisons for the attributes and wondering if I should go to the trouble of writing equals() and hashCode() for the business objectsEd


I use HashCodeBuilder and EqualsBuilder from Apache which really help me in this complex process.
 
Marshal
Posts: 78666
374
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Look in Effective Java by Joshua Bloch. Google for Angelika Langer Java equals; both those sources give no end of valuable information about the equals() method.

I shall take Mike Simmons' hint about "beginning"; I think this thread would sit better in "Java in General".
 
Wouter Oet
Bartender
Posts: 2700
IntelliJ IDE Opera
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Pat Farrell wrote:
Its actually more subtle than you suggest. And, there are default equals() and hashCode() funcitons inherited from Object, so you don't have to do anything to use a HashSet/HashMap.



It will compile and even run. But it will not run as expected. Because objects equals just returns if it's the same object instead of if it's meaningful equal.
 
Campbell Ritchie
Marshal
Posts: 78666
374
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That is the whole idea of Object#equals(). It takes the strictest definition of equality, viz whether the two references refer to the same object, as the link tells you. If you decide that two other objects are going to be equal, then you have to override the equals method (and hashCode()).
 
Edward Winchester
Ranch Hand
Posts: 65
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks to everyone for their responses! I've read through them all and have picked up some really useful information. Sorry I've not responded to you individually.

I now believe the equals()/hashCode() is very useful for business objects and worth implementing.

I'm really glad I following the link to Pojomatic. I figured it would just be some standalone process to generate these methods and if new members were introduced then it'd need to be invoked again. I was wrong. It's an annotation against the class and one-liners of equals(), hashCode(), and toString(). Any new members introduced will be considered and super classes are considered (by default). Fantastic!. My logging statements will be simpler now too

There's a final wrinkle about equals() and my test cases which I'm not sure how to handle elegantly. I know it's a little off-topic - hope that's ok this once:

Pretend I have a Person class with a personId which can be null if the database hasn't seen it yet:



My PersonDAO has this signature:



In the test case, I create a Person (null personId), save to DAO which gives me the Person object with the database id populated. Now I would like to easily assert the objects are equal. Trouble is I also think the personId is essential to the equality test, so the equals() will always return false:



Most of the time I will want to be doing the equality test on all attributes. For the test case I don't. I can't help feeling that I'm missing an elegant trick. The solution I've considered (a PersonWithId class that contains a Person class) seems clunky and will not work on more complicated cases (for instance, where a Person has an Address and a Person has a personId and the Address has an addressId).

Edward
 
Mike Simmons
Master Rancher
Posts: 4660
63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:I shall take Mike Simmons' hint about "beginning"; I think this thread would sit better in "Java in General".


Eh, I think you're probably right. I only included that line because I wasn't sure how much the poster already understood.

Edward Winchester wrote:I'm really glad I following the link to Pojomatic. [...] Fantastic!.


Excellent, glad to hear it.
 
Mike Simmons
Master Rancher
Posts: 4660
63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Edward Winchester wrote:Most of the time I will want to be doing the equality test on all attributes. For the test case I don't. I can't help feeling that I'm missing an elegant trick.


I don't know if it's really elegant, but what I've done in the past in this situation is something like:

This can get tedious if there are many fields you want to ignore, but for just one or two, it's fine. It's can also be a bit destructive of the data - you need to be sure that you don't need the value of personO.getId() for anything else before you reset it. In this case, I'm pretty sure you don't (it's just null after all) but in some cases you might.
 
Edward Winchester
Ranch Hand
Posts: 65
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike Simmons wrote:I don't know if it's really elegant, but what I've done in the past in this situation is something like:

This can get tedious if there are many fields you want to ignore, but for just one or two, it's fine. It's can also be a bit destructive of the data - you need to be sure that you don't need the value of personO.getId() for anything else before you reset it. In this case, I'm pretty sure you don't (it's just null after all) but in some cases you might.



I was hoping to avoid doing this (have nested objects which have lists of objects, etc.), but it does seem the far better than changing the hierarchy of the business objects.

Thanks for you view on it,

Ed
 
Mike Simmons
Master Rancher
Posts: 4660
63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Another technique you can use here is to write custom assertEquals() methods for your classes. If a Foo object has a complex hierarchy attached to it that you want to navigate, you can create

You still may have to write a bunch of tedious stuff, and it might require updating whenever the Foo class or its associated hierarchy changes - but at least you can write that stuff once, and reuse it in your tests whenever you want to test if two Foos are equal. This can often make your tests a lot more readable too.
 
Edward Winchester
Ranch Hand
Posts: 65
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike Simmons wrote:Another technique you can use here is to write custom assertEquals() methods for your classes. If a Foo object has a complex hierarchy attached to it that you want to navigate, you can create

You still may have to write a bunch of tedious stuff, and it might require updating whenever the Foo class or its associated hierarchy changes - but at least you can write that stuff once, and reuse it in your tests whenever you want to test if two Foos are equal. This can often make your tests a lot more readable too.



I had this before. It worked well but I've now changed it to walk through the objects and fix the identifiers from the database. The latter solution is definitely better for my situation as I can envisage the business objects changing quite a lot over the next stage of development.

Thanks again,

Ed
 
Something must be done about this. Let's start by reading this tiny ad:
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic