Thursday, 1 June 2017

Java Collections Tutorial 6: Using Custom Objects in Maps and Sets



So now, we’ve covered a lot with regards to Lists, Sets and Maps. However, so far, we’ve only used Java’s inbuilt datatypes as elements of the collections. What if we want to use our own custom objects as keys to maps or as elements in sets? How do we do it? 

Well, let us first create a class Bird. We will give each bird a tagNumber to identify it and a name. We will also create a constructor for the class that allows us to initialize the two member variables of the class as we create a new Bird object. Finally, we will give Bird a toString() method so that we can get some nice output when we use System.out.println() on an object of the class. 

public class Bird {
            private int tagNumber;
            private String name;
            public Bird(int tagNumber, String name) {
                        this.tagNumber = tagNumber;
                        this.name = name;
            }
            public String toString () {
                        return “tagNumber is: ” + tagNumber + “ name is: ” + name;
            }
}

Custom Objects with Sets

So let’s create a set containing items of the class Bird and add some items into it:

Set<Bird> birds = new HashSet<Bird>();
birds.add(new Bird(1, “hawk”));
birds.add(new Bird(5, “pigeon”));
birds.add(new Bird(7, “owl”));
birds.add(new Bird(1, “hawk”));

Now, notice that we have two elements that have the same tagNumber and name. What this implies is that the two objects are identical and based on how sets are supposed to behave, there should be only one item with the tagNumber 1 and the name “hawk”.

But if we try to output the set birds, we find that all the elements are output, including the two “hawk” objects. This is undesirable.
Figure 1: When you add custom objects to sets, Java by default does not know if they are equal


To get around this, we need to implement the equals() and hashCode() methods. The easiest way is to get your IDE to generate the two methods for you. In Eclipse, which I use, you right-click within the class file and go to Source, then click in “Generate hashCode() and toString(). Select the fields needed to determine the equality. 

For example, if you feel that two Bird objects are equal if they have the same tagNumber regardless of their name, then only select the tagNumber. if you feel that two Bird objects are equal if they have the same name regardless of their tagNumber, then only select the tagNumber. if you feel that two Bird objects are equal if they have the same tagNumber and name, then select the two fields. 
Figure 2: Now Java shows unique objects after overriding the equals() and hashCode() methods



Now, if you run the program again, you see that only one “hawk” object is listed, which is as it should be. The reason why this didn’t work in the first place is because Java doesn’t go into your objects to look what equality really means. You have to tell Java the criteria needed to conclude that two objects are equal.

Custom Objects with Maps

So let’s create a set containing items of the class Bird and add some items into it:

Map<Integer, Bird> birds = new HashMap<Integer, Bird>();
birds.put(2, new Bird(1, "hawk"));
birds.put(6, new Bird(5, "pigeon"));
birds.put(9, new Bird(7, "owl"));
birds.put(2, new Bird(1, "hawk"));

Now, notice that we have two elements that have the same tagNumber and name. What this implies is that the two objects are identical and based on how sets are supposed to behave, there should be only one item with the tagNumber 1 and the name “hawk”.

But if we try to output the set birds, Java will only output one of the objects with the same key and ignore the first one.

for (Integer key: birds.keySet()) {
            System.out.println(key + “: ” + birds.get(key));
}
 Figure 3: After overriding the hashCode() and equals() methods, Java only displays objects with unique keys.


That’s it for this tutorial. In the next tutorial, we are going to look at the concept of natural order in collections framework.

If you have any questions or comments, please leave them in the comments section below and I will make sure to address them. 

Until next time, take care.

No comments:

Post a Comment