0

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?

8
  • An ArrayList does not check for duplicates, you could stuff the same object in there over and over again. Use a SortedSet<Bird>, make Bird implements Comparable<Bird> and implement the methods equals(Bird anotherBird), hashCode() and compareTo(Bird differentBird). Having done that, you won't have any duplicates anymore... Maybe a Set<Bird> is sufficient if you don't care for your birdies being sorted. Commented Jul 1, 2019 at 12:24
  • You're not defining your equal condition for your class. Override equals method and use it to check if it already exists in the ArrayList before adding Commented Jul 1, 2019 at 12:25
  • You could have your Bird class override equals and hashcode method. Then you could simply use the contains method of the list to check if the bird is already in there. Commented Jul 1, 2019 at 12:25
  • @OHGODSPIDERS - this is also mentioned in the popular answer below, how do I go about overriding the equals method and hashcode? Commented Jul 1, 2019 at 13:22
  • @Baba many IDEs already have a built in function to create those methods for you. If you are using Eclipse you would just need to select the Option "Source -> Generate hashCode() and equals()" and then in the following dialogue select the class fields that you want involve in checking for equality which would just be the "name" field in your case. Commented Jul 1, 2019 at 13:26

2 Answers 2

2

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<>();.

Sign up to request clarification or add additional context in comments.

4 Comments

Either way, you'll want to properly implement hashCode() and equals() on Bird in order for it to work.
Thank you for the contribution. He is applying string comparison on name of the birds while new bird object is being added. So I didn't need to add this. Surely, it would be better to override equals method and compare objects that way.
@mahmutoflaz Thanks for the reply, the answer below sorted my issue by Maurice Perry. You mention the second way is better. If I am honest i don't know how to go about doing it that way. But I really want to learn it if that is the best way.
@mahmutoflaz Unfortunately this worked but only till i used my observation method, this method would ask the user, what was observed? for which the user will reply with a name of a bird, if the bird existed in the set then it would take that object and increment its 'observation' field. However after a successful increment, I used the add method to add an existing birds name, and it would let me. Printing the set would show that two objects of the same name fields existed, only their observation fields were different. After calling the observation field again it would increment all objects.
0

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));

1 Comment

Why was this answer down voted, it has sorted my issue out. So if i understand this, for loop quite simply goes through the array, and if the 'if' statement is false the loop ends and carries on normally to the next statement which is birds.add...Thank you, only thing to sort out now is case sensitivity but that's easy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.