logo

Java: Custom Address Class to Check for Duplicates

My adventures as a "proper" programmer continue apace. Yesterday I created a custom class in Java that implements the Comparable interface and now feel quite smug about it. Probably undeservedly so.

I was writing a Domino-based reporting Agent in Java which need to loop a set of invoice documents for a given user and report back a sorted list of each unique billing addresses they'd supplied over the years, so that a data audit could take place.

Here's the use case code for the class:

ArrayList addresses = new ArrayList();

Document d = dc.getFirstDocument();
    
while (null!=d){
    BillingAddress address = new BillingAddress();
                        
    address.setAddress("AddressLine1");
    address.setTown(d.getItemValueString("AddressTown"));
    address.setCounty(d.getItemValueString("AddressCounty"));
    address.setPostCode(d.getItemValueString("AddressPostCode"));
              
    //Make sure the address is isn't in the array.          
    if(!addresses.contains(address)){
        addresses.add(address);
    }
                        
    d = dc.getNextDocument(d);
}

//Sort our addresses before output
Collections.sort(addresses);

//For each address convert to HTML string.
for (int i=0; i<addresses.size(); i++){
    _html+=("<p>"+((BillingAddress)addresses.get(i)).toString().replace("\\n", "<br/>")+"</p>");
}

As you can see I'm able to check whether a BillingAddress is already in the ArrayList and I'm able to sort them. The former is due to the existence of the equals() method in the class and the latter because of the compareTo() method.

Here's the class itself:

public class BillingAddress implements Comparable {

    private String _address;
    private String _town;
    private String _county;
    private String _postCode;
    
    
    public int compareTo(Object address) throws ClassCastException {
        if (!(address instanceof BillingAddress))
              throw new ClassCastException("A BillingAddress object expected.");
            
        return (_address.compareTo(
                ((BillingAddress)address).getAddress()
            ));
    }
    
    public boolean equals(BillingAddress address){
        return (
            address!=null &&
            address.getAddress().equalsIgnoreCase(_address) &&
            address.getPostCode().equalsIgnoreCase(_postCode)
        );
    }

    public void setAddress(String address){
        _address = address;
    }
    
    public String getAddress(){
        return _address;
    }
    
    public void setTown(String town){
        _town = town;
    }
    
    public String getTown(){
        return _town;
    }
    
    public void setCounty(String county){
        _county = county;
    }
    
    public String getCounty(){
        return _county;
    }
        
    public void setPostCode(String postCode){
        _postCode = postCode;
    }
        
    public String getPostCode(){
        return _postCode;
    }
    
    public String toString(){
        String out = "<p>";
        if (!_address.equals("")){
            out+=_address+"\n";
        }
        if (!_town.equals("")){
            out+=_town+"\n";
        }
        if (!_county.equals("")){
            out+=_county+"\n";
        }
        if (!_postCode.equals("")){
            out+=_postCode;
        }
        return out;
    }

}

Inside the equals() method you can see I've deemed any address where the first line and the post code (ZIP) match to be the same. Whether this holds true or not I don't know yet. But it's easy to change this logic. As is the case for changing how the compareTo() method sorts your addresses. You could choose to sort by Town/City or Post Code rather than by the first line. It's all up to you.

As you can probably tell I'm writing the code in Java 1.3 (ouch!) because the client is still on Domino 6.5.5 (double ouch!!). If you were using a later version of Java you could make the above code a lot simpler, but the theory still holds true and the principles are the same.

Comments

    • avatar
    • ChrisC
    • Wed 14 Dec 2011 04:16 AM

    Very nice Jake...sure we can't tempt you over to the XPages world yet?

    1. It's not really about being tempted (which I'm not really) it's all about work (money!). When a customer asks me to write them a web app and specifies it must be done in Xpages, then I'll be tempted (forced!) to. The chances of it happening are fairly remote though.

      Show the rest of this thread

  1. As you do not recycle you should check memory consumption at the server if you iterate over a large collection.

    Most parts of the code would fit well into an XPages environment too but a 6.5.5 customer would not benefit from an XPage solution anyway.

    In my dreams IBM enhanced the "classic" application approach so that old ugly applications automatically become nice looking modern GUI applications that work on both the web and a client simple by upgrading the server and starting the design task on a database level.

    That would mean enormous potential for customers that already said good-bye to Notes and Domino a long time ago but still keep it running. There are thousands of former customers falling into this category.

    1. Spot on. XPages is a solution in search of a problem. Most Domino application environments have been left on minimal life support for very good reasons. Since an XPages migration is effectively a total rewrite, it has little or no advantage over migrating to any other platform - especially one that might be cheaper, more robust, more open, better documented or more widely adopted. This is why XPages deployments are few and far between and developer interest and market demand for those skills is near non-existent.

      Show the rest of this thread

      • avatar
      • axel
      • Wed 14 Dec 2011 11:19 AM

      You should better use:

      [code]

      Document oldOne = d;

      d = dc.getNextDocument(d);

      oldOne.recycle();

      }

      [/code]

      Way much saver, when you iterate over a larger collection of Domino Objects.

  2. If you use a TreeSet instead of an ArrayList, you don't have to check for duplicates and you don't have to sort the collection.

    1. Are TreeSets in Java 1.3?

      How do they know if an object based on a custom class is already in them?

      How do they manage custom sorting?

      Hide the rest of this thread

        • avatar
        • Jeremy Hodge
        • Wed 14 Dec 2011 06:47 AM

        TreeSets since 1.2...

        "adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2))."

        TreeSet(Comparator<? super E> comparator)

        Constructs a new, empty tree set, sorted according to the specified comparator.

      1. http://docs.oracle.com/javase/1.4.2/docs/api/java/util/TreeSet.html

        Since 1.2

        Sorting:

        You just need a compareTo method, which you have already, or you could supply a comparator in the constructor.

        I don't know the inner workings of a tree set, but I could imagine it runs through the collection calling compareTo on the elements already in there till it finds the right sort position or an equal object (compareTo = 0), in that case the element is not added.

        1. Cool. Thanks for that. I'll probably update my code to use one. I'm all for saving a couple of lines here and there.

        • avatar
        • axel
        • Wed 14 Dec 2011 11:11 AM

        I second Peter.

        TreeSet is in Java1.3.

        java.util.Sets just call the equal methods of the objects that are allready member of the Set.

        They manage sorting by calling the compareTo method.

        And BillingAdress has all it needs: compareTo AND equals method overriden.

        Hm. Well there is something missing, that may generate nasty behaviour: You should ALLWAYS implement hashCode method whenever you override equals.

        http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20

        I allways use eclipse to implement this kind of stuff.

        Source/Generate Hash Code and Equals,

        Source/Generate ToString

        Source/Generate Setters and Getters.

          • avatar
          • axel
          • Wed 14 Dec 2011 11:39 AM

          This book explains all this nasty stuff quite well. Its short and worth the money.

          http://tinyurl.com/d5u3my6

        1. Thanks Axel. Advice taken. Now recycling and using a TreeSet. Now I'm off to add the hashCode() override...

        2. I tried adding equals() and hashCode() on my own but it wasn't working. So I used your Source/Generate tip to create them and now it works a charm. Thanks Axel!!

            • avatar
            • axel
            • Thu 15 Dec 2011 05:13 AM

            just paying back 8 year old debts ;-)

            Using TreeSet saves you just 2 or 3 lines. Not much.

            With a Collection of great size you may gain some performance, but probably its not significant.

            TreeSet documents to those who know the Java Collection framework that sorting is an issue with this collection. This code-as-documentation argument probably is the most powerfull.

            And sadly it defends you against certain breed of "competitive" Java devs.

            This year I dared to use

            ((someString != null) && (someString.trim().length() > 0)) as a not null, not whitespace check.

            This started a 1 hours interogation process, about if I am a "real developer" or some nasty kind of evil impostor as "real developers" out of their very nature use !StringUtils.isNotBlank(someString) from commons-string fame ;-) ... In a project that was long way over budget when I entered.

  3. Thanks Jake, I always like to see other peoples code samples to see how they use a language feature.

    Two questions.

    Does/can the post office provide address verification as a service or Database and API?

    Also, does this customer have less than a thousand seats?

    If so, sounds like a really good candidate to switch to express server licensing and upgrade in an incremental manner.

    1. Hi Wayne,

      1. I'd be surprised if it didn't.

      2. No.

      Jake

    2. Is express server licensing even available any more? Last I heard, big blue had gone to a 'one size fits all (we care about)' model... no more foundations, no more express.... maybe I totally misunderstood (hopefully so - both express and foundations were great ideas for small biz).

      Show the rest of this thread

  4. You could also use Session.evaluate() with @sort and @unique

    1. Now, come on Bob, that's hardly going to make me a better developer and prepare for a world without Domino is it?! ;-)

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Wed 14 Dec 2011

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content