Skip to main content

apache commons equals/hashcode builder



I'm curious to know, what people here think about using org.apache.commons.lang.builder EqualsBuilder/HashCodeBuilder for implementing the equals/hashcode? Would it be a better practice than writing your own? Does it play well with Hibernate? What's your opinion?




Comments

  1. The commons/lang builders are great and I have been using them for years without noticeable performance overhead (with and without hibernate). But as Alain writes, the Guava way is even nicer:

    Here's a sample Bean:

    public class Bean{

    private String name;
    private int length;
    private List<Bean> children;

    }


    Here's equals() and hashCode() implemented with Commons/Lang:

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


    and here with Guava:

    @Override
    public int hashCode(){
    return Objects.hashCode(name, length, children);
    }

    @Override
    public boolean equals(final Object obj){
    if(obj instanceof Bean){
    final Bean other = (Bean) obj;
    return Objects.equal(name, other.name)
    && Objects.equal(length, other.length)
    && Objects.equal(children, other.children);
    } else{
    return false;
    }
    }


    As you can see the Guava version is shorter and avoids superfluous helper objects. In case of equals, it even allows for short-circuiting the evaluation if an earlier Object.equal() call returns false (to be fair: commons / lang has an ObjectUtils.equals(obj1, obj2) method with identical semantics which could be used instead of EqualsBuilder to allow short-circuiting as above).

    So: yes, the commons lang builders are very preferable over manually constructed equals() and hashCode() methods (or those awful monsters Eclipse will generate for you), but the Guava versions are even better.

    And a note about Hibernate:

    be careful about using lazy collections in your equals(), hashCode() and toString() implementations. That will fail miserably if you don't have an open Session.



    Note (about equals()):

    a) in both versions of equals() above, you might want to use one or both of these shortcuts also:

    @Override
    public boolean equals(final Object obj){
    if(obj == this) return true; // test for reference equality
    if(obj == null) return false; // test for null
    // continue as above


    b) depending on your interpretation of the equals() contract, you might also change the line(s)

    if(obj instanceof Bean){


    to

    // make sure you run a null check before this
    if(obj.getClass() == getClass()){


    If you use the second version, you probably also want to call super(equals()) inside your equals() method. Opinions differ here, the topic is discussed in this question:


    right way to incorporate superclass into a Guava Objects.hashcode() implementation?


    (although it's about hashCode(), the same applies to equals())

    ReplyDelete
  2. If you don't to write your own, there is also the possibility to use google guava (formerly google collections)

    ReplyDelete
  3. The EqualsBuilder and HashCodeBuilder have two main aspects that are different from manually written code:


    null handling
    instance creation


    The EqualsBuilder and HashCodeBuilder make it easier to compare fields that could be null. With manually writen code this creates a lot of boilerplate.

    The EqualsBuilder will on the other hand create an instance per equals method call. If your equals methods are call often this will create a lot of instances.

    For Hibernate the equals and hashCode implementation make no difference. They are just an implementation detail. For almost all domain objects loaded with hibernate the runtime overhead (even without escape analysis) of the Builder can be ignored. Database and communication overhead will be significant.

    As skaffman mentioned the reflection version cannot be used in production code. Reflection will be to slow and the "implementation" will not be correct for all but the simplest classes. Taking all members into account is also dangerous as newly introduced members change the equals method behaviour. The reflection version can be useful in test code.

    ReplyDelete
  4. If you do not want to depend on a 3rd party library (maybe you are running an a device with limited resources) and you even do not want to type your own methods, you can also let the IDE do the job, e.g. in eclipse use

    Source -> Generate hashCode() and equals()...


    You will get 'native' code which you can configure as you like and which you have to support on changes.

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex