Baba
Baba

Reputation: 3

Duplicate Objects being stored in ArrayList with add method

I have two classes, one named Bird the other Runtime. The bird class creates birds - name, latin name. The Runtime class has 4 methods, only one is important for this question, that is the 'add' method. The add method when called upon needs to take input from the user that is name and latin name, these are saved into a string variable 'name' and 'latin name' and I call the Bird class constructor and pass in these string variables into its parameter and finally it is added to an ArrayList. However I get duplicate values, if I were to write the same bird twice.

I have tried to convert the ArrayList into a set and convert it back again into an ArrayList, i did this within the add method, this did not work. I suspect it is down to my poor understanding of how objects are stored in an ArrayList. I also created a getName method within the Bird class, so I can use list.get(i).getName, and if the name is equal to the one typed by the user, it prompts the user accordingly, if not it is added to my ArrayList. This also did not work. I also tried a for loop that would go through the ArrayList and an if statement would determine if the name typed by the user exists within the ArrayList, this also did not work, the attempt was early on so I can't remember exactly the error message, but the add method is called from within a while loop, and I think the error message was concurrent modification, I'm not entirely sure so please ignore that, my point is showing the various solutions I tried.

Below is The Bird class

    public class Bird{

       int obeservation = 0;
       String name;
       String latinName;

       public Bird(String name, String latinName){
         this.name = name;
         this.latinName = latinName;
       }

       public void addBird(String name, String latinName){
         this.name = name;
         this.latinName = latinName;
       }

       public String getName(){
         return this.name;
       }

       public String statistics(){
         return this.name + " (" + this.latinName + ") : " +         
         this.obeservation + " observation";
       }
   }

Below is the Runtime class

    public class Runtime {

        ArrayList<Bird> birds = new ArrayList<Bird>();

        Scanner scan = new Scanner(System.in);

        public void scan() {
            System.out.println("?");
            String answer = scan.nextLine().trim();
            while (!answer.equalsIgnoreCase("EXIT")) {
              System.out.println("?");
              answer = scan.nextLine().trim().toUpperCase();
            if (answer.equalsIgnoreCase("ADD")) {
                add();
            } else if (answer.equalsIgnoreCase("OBSERVATION")) {
                observation();
            } else if (answer.equalsIgnoreCase("STATISTICS")) {
                System.out.println("jhjh");//just to see if this is     
                working
                statistics();
            } 
        }
    }

below is the add method, also what I've commented is the attempts, currently the add method does not have an if statements to decide duplicates.

    public void add() {

         System.out.print("Name: ");
         String name1 = scan.nextLine().trim().toUpperCase();

         System.out.print("Latin Name: ");
         String latinName1 = scan.nextLine().trim().toUpperCase();

         birds.add(new Bird(name1, latinName1));


         /*
         Bird newBird = new Bird(name1, latinName1);

         for (int i = 0; i < birds.size(); i++) {
             if (birds.get(i).getName().equals(name)) {
                 System.out.println("Bird already exist");
                 return;
             } else {
                 birds.add(newBird);
             }
         }
         /*
          * hBirds.addAll(birds); birds = new ArrayList<Bird>();     

        birds.addAll(hBirds);
            * 
            * // Bird newBird = new Bird(name, latinName); 
            * /* if(birds.contains(name)){
            * System.out.println("That name already exist"); 
            * return; 
            * }else{ 
            * birds.add(newBird(name, latinName));
            * 
            * }
            */
     } 

The statistics method prints out the ArrayList, a foreach loop that goes through the ArrayList prints it out. The expected result if I input seagull twice should be one seagull value not two. How do i reject the duplicate?

Upvotes: 0

Views: 2493

Answers (2)

mdoflaz
mdoflaz

Reputation: 571

You can have two approaches here:

  • First: Traverse through ArrayList, if you can't find the same bird, add it to ArrayList. It is a worse approach.

  • Second: Store birds inside HashSet. In this case, you need to override .hashCode() and .equals(Object obj) methods. It is a better approach.

Before talking about how to generate .hashCode() and .equals(Object obj) methods, I want to mention about .hashCode() method and HashSet<T>.

HashSet<T>s provide a unique set of the elements inside. To achieve this, .hashCode() method of a class is used. If you override .hashCode() method in any class, you can get the benefit of using HashSet<T>s. If you don't override this method, Java automatically returns the memory address of the object. That's why your HashSet<Bird> was including duplicate elements.

.hashCode() and .equals() methods can be generated by lots of IDEs. I copied and pasted your Bird class to Eclipse. By using Alt+Shift+S -> h for Eclipse or Alt+Insert -> equals() and hashCode() for IntelliJ, automatically generated the methods below:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((latinName == null) ? 0 : latinName.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + obeservation;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Bird other = (Bird) obj;
    if (latinName == null) {
        if (other.latinName != null)
            return false;
    } else if (!latinName.equals(other.latinName))
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    if (obeservation != other.obeservation)
        return false;
    return true;
}

If you add these methods(I encourage you to generate in your IDE) to Bird class, you can use HashSet<Bird>. To avoid duplicates, simply add all of your Bird objects into defined HashSet<Bird>. You don't need any other data structure or equality check to control if any two Bird type objects are equal.

You will just need to change your object collection from ArrayList<Bird> birds = new ArrayList<Bird>(); to Set<Bird> birds = new HashSet<>();.

Upvotes: 2

Maurice Perry
Maurice Perry

Reputation: 9651

Move the add out of the loop:

    for (int i = 0; i < birds.size(); i++) {
        if (birds.get(i).getName().equals(name1)) {
            System.out.println("Bird already exist");
            return;
        }
    }
    birds.add(new Bird(name1, latinName1));

Upvotes: 0

Related Questions