Skip to content
Related Articles
Open in App
Not now

Related Articles

Maven Project – HashMap and HashSet Collections with JUnit Testing

Improve Article
Save Article
  • Last Updated : 29 Dec, 2022
Improve Article
Save Article

In many software, we will be working with HashMap and HashSet and always there is confusion exists that when to use HashMap and when to use HashSet. As a sample project, a use case containing the “GeekAuthor” class is taken and it has different attributes namely 

  • authorName
  • authorId
  • areaOfInterest
  • publishedArticles

Let us try to add the “GeekAuthor” data both in HashMap and HashSet separately and check the behaviors one by one. Along with JUNIT, we can test effectively also.

Example Maven Project

Project Structure:

Project Structure

 

Project is prepared as of type maven and hence all the dependencies required for the project are present in

pom.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gfg.CollectionServicesInJava</groupId>
    <artifactId>CollectionServicesInJava</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>5.3.1</junit.version>
        <pitest.version>1.4.3</pitest.version>
    </properties>
 
    <dependencies>
 
        <!-- junit 5, unit test -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
 
    </dependencies>
    <build>
        <finalName>maven-mutation-testing</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M1</version>
            </plugin>
 
            <plugin>
                <groupId>org.pitest</groupId>
                <artifactId>pitest-maven</artifactId>
                <version>${pitest.version}</version>
 
                <executions>
                    <execution>
                        <id>pit-report</id>
                        <phase>test</phase>
                        <goals>
                            <goal>mutationCoverage</goal>
                        </goals>
                    </execution>
                </executions>
                 
                <!-- Need this to support JUnit 5 -->
                <dependencies>
                    <dependency>
                        <groupId>org.pitest</groupId>
                        <artifactId>pitest-junit5-plugin</artifactId>
                        <version>0.8</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <targetClasses>
                        <param>com.gfg.CollectionServicesInJava.*CollectionServicesInJava*</param>
                    </targetClasses>
                    <targetTests>
                        <param>com.gfg.CollectionServicesInJava.*</param>
                    </targetTests>
                </configuration>
            </plugin>
 
        </plugins>
    </build>
 
</project>


As we are going to add GeekAuthors, we need the model class for it

GeekAuthor.java

Java




package com.gfg.CollectionServicesInJava;
 
public class GeekAuthor {
    public GeekAuthor(String authorName, int authorId, String areaOfInterest, int publishedArticles) {
        super();
        this.authorName = authorName;
        this.authorId = authorId;
        this.areaOfInterest = areaOfInterest;
        this.publishedArticles = publishedArticles;
    }
 
    public GeekAuthor() {
        // via setter methods, rest fields are done
    }
 
    String authorName;
    int authorId;
    String areaOfInterest;
    int publishedArticles;
 
    public String getAuthorName() {
        return authorName;
    }
 
    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }
 
    public int getAuthorId() {
        return authorId;
    }
 
    public void setAuthorId(int authorId) {
        this.authorId = authorId;
    }
 
    public String getAreaOfInterest() {
        return areaOfInterest;
    }
 
    public void setAreaOfInterest(String areaOfInterest) {
        this.areaOfInterest = areaOfInterest;
    }
 
    public int getPublishedArticles() {
        return publishedArticles;
    }
 
    public void setPublishedArticles(int publishedArticles) {
        this.publishedArticles = publishedArticles;
    }
 
    // We need to override 2 methods namely
    // equals and hashcode whenever we no need
    // to store two author objects    
    // if their names are same
    @Override
    public boolean equals(Object o) {
        if (o instanceof GeekAuthor) {
            GeekAuthor other = (GeekAuthor) o;
            return authorName.equals(other.getAuthorName());
        }
 
        return false;
    }
 
    @Override
    public int hashCode() {
        return authorName.hashCode();
    }
 
}


Here we need to pay attention to two specific methods namely “equals” and “hashCode”. They should be overridden according to our requirements. These two methods are essentially required to check whether the objects are duplicates or not. They are again given here for reference.

// We need to override 2 methods namely equals
// and hashcode whenever we no need
// to store two author objects     
// if their names are same
@Override
public boolean equals(Object o) {
        if (o instanceof GeekAuthor) {
            GeekAuthor other = (GeekAuthor) o;
            return authorName.equals(other.getAuthorName());
        }
        return false;
    }

    @Override
    public int hashCode() {
        return authorName.hashCode();
    }

This set of code is highly essential and with that only HashSet functionality disallows duplicates. Here we need to know that HashMap allows duplicate keys but what will happen is that newly added data is overwritten in place of old data. For example

authorMap.put("Rachel",new GeekAuthor("Rachel", 1, "Java", 200));
authorMap.put("Monica",new GeekAuthor("Monica", 1, "Python", 100)); 
authorMap.put("Rachel",new GeekAuthor("Phoebe", 1, "Java", 100));
In line 1 and 3, "Rachel" is the key. Hence finally in the HashMap we can able to see only 2 entries only
and when we try to retrieve the data for "Rachel" key, we will get 
authorName as Phoebe, authorId as 1 etc.,
i.e. 1st data is overwritten

Now coming to HashSet, if we try to add duplicate data, they will not be considered at all because of the existing 2 methods namely “equals” and “hashCode”

GeekAuthor rachel = new GeekAuthor("Rachel", 1, "Java", 200);
GeekAuthor monica = new GeekAuthor("Monica", 1, "Python", 100);
GeekAuthor phoebe = new GeekAuthor("Rachel", 1, "Java", 200);
authorSet.add(rachel);
authorSet.add(monica); 
authorSet.add(phoebe);
Here though "phoebe" named author object is created and since it is a duplicate value ("rachel" named author
objectis already added with the same data, finally only 2 author data is there.

Let us see the full set of codes via

HashMapCollectionServicesInJava.java

Java




import java.util.HashMap;
 
public class HashMapCollectionServicesInJava {
    // In order to represent HashMap does not allow
    // duplicates in a HashMap for the same key "Rachel",
    // two separate author data is added
    // Though adding is allowed, instead of keeping
    // 3 different entries, only 2 will be the size and for
    // "Rachel" key, last data is updated
    public int addAuthors(HashMap authorMap)
    {
        authorMap.put("Rachel",new GeekAuthor("Rachel", 1, "Java", 200));
        authorMap.put("Monica",new GeekAuthor("Monica", 1, "Python", 100));
        authorMap.put("Rachel",new GeekAuthor("Phoebe", 1, "Java", 100));
        return authorMap.size();
    }
    public int getAuthors(HashMap authors) {
        return authors.size();
    }
    public String getAuthorName(HashMap authorMap,String authorNameKey) {
        GeekAuthor geekAuthor = new GeekAuthor();
        if (authorMap.containsKey(authorNameKey)) {
            // Mapping the retrieved value
            geekAuthor = (GeekAuthor) authorMap.get(authorNameKey);           
        }
        return geekAuthor.getAuthorName();
    }
 
}


HashSetCollectionServicesInJava.java

Java




import java.util.HashSet;
import java.util.Set;
 
public class HashSetCollectionServicesInJava {
     
    public int addAuthorsViaHashSet(Set authorSet)
    {
        GeekAuthor rachel = new GeekAuthor("Rachel", 1, "Java", 200);
        GeekAuthor monica = new GeekAuthor("Monica", 1, "Python", 100);
        GeekAuthor phoebe = new GeekAuthor("Rachel", 1, "Java", 200);
        authorSet.add(rachel);
        authorSet.add(monica);
        authorSet.add(phoebe);
        return authorSet.size();
    }
    public int getAuthors(HashSet authorsSet) {
        return authorsSet.size();
    }
     
    public String getAuthorName(HashSet author,GeekAuthor geekAuthor) {
        if (author.contains(geekAuthor)) {
            // Mapping the retrieved value
            return geekAuthor.getAuthorName();           
        }
        return null;
    }
}


Ok, now let’s test it out. We need to test whether our assumptions are correct or not. i.e. during hashmap addition what is happening and with HashSet addition what is happening, we can justify with the below testcases.

TestCollectionServicesJava.java

Java




import static org.junit.jupiter.api.Assertions.assertEquals;
 
import java.util.HashMap;
import java.util.HashSet;
 
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
 
public class TestCollectionServicesJava {
    @DisplayName("Test check for adding geekauthors in HashMap collection ")
    @Test
    public void testCheckForAdditionOfAuthorsInHashMap() {
        HashMap<String,GeekAuthor> authors = new HashMap<String,GeekAuthor>();
        HashMapCollectionServicesInJava hashMapCollectionServicesJavaObject = new HashMapCollectionServicesInJava();
        assertEquals(true, hashMapCollectionServicesJavaObject.getAuthors(authors) == 0);
        // adding few authors
        hashMapCollectionServicesJavaObject.addAuthors(authors);
        // "Rachel" key is duplicated and hence we expect only 2
        assertEquals(true, hashMapCollectionServicesJavaObject.getAuthors(authors) == 2);
        // "Rachel" key is duplicated, now lets assert that the
        // last taken value is updated for "Rachel" key
        assertEquals(true, hashMapCollectionServicesJavaObject.getAuthorName(authors,"Rachel").equalsIgnoreCase("Phoebe"));
                 
    }
    @DisplayName("Test check for adding geekauthors in HashSet collection ")
    @Test
    public void testCheckForAdditionOfAuthorsInHashSet() {
        HashSet<GeekAuthor> authors = new HashSet<GeekAuthor>();
        HashSetCollectionServicesInJava collectionObject = new HashSetCollectionServicesInJava();
        assertEquals(true, collectionObject.getAuthors(authors) == 0);
        // adding few authors
        collectionObject.addAuthorsViaHashSet(authors);
        // "Rachel" author is duplicated and since we have overridden
        // equals and hashcode method,
        // only 1 time "Rachel" named author is added and hence
        // the total number of authors are 2
        assertEquals(true, collectionObject.getAuthors(authors) == 2);
        GeekAuthor rachel = new GeekAuthor("Rachel", 1, "Java", 200);
        // "Rachel" author is duplicated and since we have overridden
        // equals and hashcode method,
        // duplicates are not allowed and hence
        // we get only "Rachel" as the output
        assertEquals(true, collectionObject.getAuthorName(authors,rachel).equalsIgnoreCase("Rachel"));               
    }
}


Output of the JUNIT testcase:

Output of the JUNIT testcase

 

Two lines of code, we need to carefully observe. In HashMap, it allows duplicates and when there are duplicates, the new value is replaced in the place of the old value. Hence below assert has come correct

// "Rachel" key is duplicated, now lets assert that the last taken value is updated for "Rachel" key
assertEquals(true, hashMapCollectionServicesJavaObject.getAuthorName(authors,"Rachel").equalsIgnoreCase("Phoebe"));

At the same time, in the case of HashSet, it will not allow duplicates; because of the “equals” and “hashCode” methods, the duplicates cannot be added.

GeekAuthor rachel = new GeekAuthor("Rachel", 1, "Java", 200);
// "Rachel" author is duplicated and since we have overridden equals and hashcode method,
// duplicates are not allowed and hence we get only "Rachel" as the output
assertEquals(true, collectionObject.getAuthorName(authors,rachel).equalsIgnoreCase("Rachel"));

My Personal Notes arrow_drop_up
Related Articles

Start Your Coding Journey Now!