10

I know this is a messy implementation, but I basically have this code (I wrote all of it), and I need to be able to remove a student or instructor from the list when using the appropriate menu choice. Everything else in the code works, just not menu options 3 and 4. I'm entering the exact same information for the object when trying to delete. Here's the code. All three classes are below.

Driver class:

import java.util.ArrayList;
import java.util.Scanner;

public class Driver {
private ArrayList<Student> students;
private ArrayList<Instructor> instructors;

public static void main(String[] args) {        
    Driver aDriver = new Driver();
    aDriver.run();      
}

public Driver() {
    students = new ArrayList<Student>();
    instructors = new ArrayList<Instructor>();
}

private void run() {
    Student aStudent;
    Instructor anInstructor;
    Scanner inp = new Scanner(System.in);
    int choice = -1;
    String str = "Enter a menu option:\n";

    str += " 0: Quit\n";
    str += " 1: Add new student\n";
    str += " 2: Add new instructor\n";
    str += " 3: Delete existing student\n";
    str += " 4: Delete existing instructor\n";
    str += " 5: Print list of students\n";
    str += " 6: Print list of instructors\n";
    str += "Your choice: ";

    do {
        System.out.print(str);
        choice = inp.nextInt();

        switch(choice) {
        case 0:
            System.out.println("Thanks! Have a great day!");
            break;
        case 1:
            aStudent = getStudentInfo();
            addStudent(aStudent);
            break;
        case 2:
            anInstructor = getInstructorInfo();
            addInstructor(anInstructor);
            break;
        case 3:
            aStudent = getStudentInfo();
            deleteStudent(aStudent);
            break;
        case 4:
            anInstructor = getInstructorInfo();
            deleteInstructor(anInstructor);
            break;
        case 5:
            printStudents();
            break;
        case 6:
            printInstructors();
            break;
        default:
            System.out.println("Invalid menu item " + choice);  
        }
    }
    while(choice != 0);
}

public Student getStudentInfo() {
    Student aStudent;
    String name = null;
    String id = null;
    double GPA = 0.0;
    Scanner inp = new Scanner(System.in);

    System.out.print("\n\nEnter the student's name: ");
    name = inp.nextLine();
    System.out.print("Enter the student's ID: ");
    id = inp.nextLine();
    System.out.print("Enter the student's GPA: ");
    GPA = inp.nextDouble();

    aStudent = new Student(name, id, GPA);
    return aStudent;
}

public Instructor getInstructorInfo() {
    Instructor anInstructor;
    String name = null;
    String id = null;
    String dept = null;
    String email = null;
    Scanner inp = new Scanner(System.in);

    System.out.print("\n\nEnter the instructor's name: ");
    name = inp.nextLine();
    System.out.print("Enter the instructor's ID: ");
    id = inp.nextLine();
    System.out.print("Enter the instructor's department: ");
    dept = inp.nextLine();
    System.out.print("Enter the instructor's email address: ");
    email = inp.nextLine();

    anInstructor = new Instructor(name, id, dept, email);
    return anInstructor;
}

public void addStudent(Student aStudent) {
    students.add(aStudent);
}

public void addInstructor(Instructor anInstructor) {
    instructors.add(anInstructor);
}

public void deleteStudent(Student aStudent) {
    students.remove(aStudent);
}

public void deleteInstructor(Instructor anInstructor) {
    instructors.remove(anInstructor);
}

public void printStudents() {
    System.out.println("\n\n" + Student.printHeader());

    for(int i = 0; i < students.size(); i++) {
        System.out.print(students.get(i));
    }

    System.out.print("\n\n");
}

public void printInstructors() {
    System.out.print("\n\n" + Instructor.printHeader());

    for(int i = 0; i < instructors.size(); i++) {
        System.out.print(instructors.get(i));
    }

    System.out.print("\n\n");
}
}

Student class:

public class Student {
private String name;
private String id;   //String to allow for the possibility of leading zeroes
private double GPA;

public Student() {
    name = "TestFirst TestLast";
    id = "00000";
    GPA = -1.00;
}

public Student(String name1, String id1, double GPA1) {
    name = name1;
    id = id1;
    GPA = GPA1;
}

public static String printHeader() {
    String str = String.format("%-25s%-7s%-6s\n", "Name", "ID", "GPA");
    return str;
}

public String toString() {
    String str = String.format("%-25s%-7s%-6.3f\n", name, id, GPA);
    return str;
}

public String getName() {
    return name;
}

public void setGPA(double GPA2) {
    GPA = GPA2;
}
}

Instructor class:

public class Instructor {
private String name;
private String id;
private String dept;
private String email;

public Instructor() {
    name = "TestFirst TestLast";
    id = "-00001";
    dept = "TestDept";
    email = "[email protected]";
}

public Instructor(String name1, String id1, String dept1, String email1) {
    name = name1;
    id = id1;
    dept = dept1;
    email = email1;
}

public static String printHeader() {
    String str = String.format("%-30s%-6s%-15s%-15s\n", "Name", "ID", "Department", "Email Address");
    return str;
}

public String toString() {
    String str = String.format("%-30s%-6s%-15s%-15s\n", name, id, dept, email);
    return str;
}

public String getName() {
    return name;
}
}

4 Answers 4

22

You must correctly override the equals() method for both Student and Instructor classes.

When overriding equals, it is good to override hashCode() as well. new Student(name, id, GPA);

For example, something like this:

public boolean equals(Object o) {
  if (!(o instanceof Student)) {
    return false;
  }
  Student other = (Student) o;
  return name.equals(other.name) && id.equals(other.id) && GPA == other.GPA;
}

public int hashCode() {
  return name.hashCode();
}

This way, you give a chance to the ArrayList figure out which object correspond to the one you passed as a parameter when deleting. If you don't override the above methods, it will use the default implementations in Object, which compare memory addresses which are definitely different as you remove a new Student object.

You can read even more information about the 2 methods in the javadocs for Object.

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

7 Comments

Isn't the hashCode going to give issues when different students with the same name exist?
No, because the hashCode() goal is to separate instances into buckets. Only instances in the same bucket are compared using equals. So, students with the same name should go into the same bucket.
Have you seen my updated answer? There is code that you can copy and paste in there.
Be that as it may, a better override of hashCode would probably take id into account either instead of or in addition to the name. Fewer conflicts would occur (assuming that student id is unique).
I pasted your code and it worked. I'd like to make sure I understand, however, if you wouldn't mind verifying for me. The Object o parameter is a placeholder that will accept any Object passed to it. The if statement checks that it is an object of the appropriate type (in this case Student, but in the Instructor class it would be Instructor), and returns false if the object isn't of that type. The line Student other ... simply places the Object into a Student object so that it can be compared, and the final statement actually checks for the above to be equal. Correct?
|
9

You need to Override equals and hashcode methods for collections to work properly.

@Override
public boolean equals(Object obj) {
    if (obj == null)
        return false;
    if (!(obj instanceof Student))
        return false;
    Student other = (Student) obj;
    return id == null ? false : id.equals(other.id);//Compare Id if null falseF
}

Since you are only using ArrayList there is hashcode method will not be used but it is still good practice to provide it.

 @Override
public int hashCode() {
    return id == null ? 0 : id.hashCode();
}

Comments

6

You didn't override the method equals for Student and Instructor.

This method is used by the ArrayList to check wether 2 objects are the same. Without a custom implementation it will just check references, which will be different in your case since they are two different objects.

To provide custom equality you will have to check all the fields of the involved classes to be the same. This can be done recursively by calling equals on instance variables.

2 Comments

Okay, I get what you're saying, but I'm not sure how to implement it. When I override toString, for example, all I need to do is return a String object from the method. When I override equals, I need to use an if statement to compare, but what two things do I compare, especially when using ArrayList.remove()? remove() takes an object in, but how do I compare?
The equals method is called by the ArrayList itself. You just need to implement the method such that it will return true if and only if two students are the same student (this may mean if they have the same name and the same whatever you need)
3

Overriding the equals method of Student and Instructor will work:

Here is an example for the Student class:

public boolean equals(Object other){
    if(other == null) return false;
    if(other == this) return true;
    if(!(other instanceof Student)) return false;
    Student otherStudent = (Student)other;
    return otherStudent.id.equals(this.id);
}

You may also want to override hashCode():

public String hashCode(){
    return new HashCodeBuilder(17, 31).
        append(name).
        append(id).
        toHashCode();
}

Comments

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.