-1

I'm new to Java and was wondering why exactly this method I wrote is not working:

public boolean checkOut(Person p, Book b, String dueDate){
    ArrayList<Book> removeBooks = new ArrayList<Book>();
    if (libraryBooks.contains(b) && patrons.contains(p)){
        for (Book book1 : libraryBooks){
            if (book1.equals(b)){
                p.addBook(book1);
                removeBooks.add(book1);
                book1.setDueDate(dueDate);
                break;
            }}
        for (Book b2 : removeBooks){
            libraryBooks.remove(b2);    
        }
        return true;
    }
    else{
        return false;
    }
    }

The method takes in a person, book and dueDate. libraryBooks is a list of all of the book objects that the library class has. Library has patrons, a list of Persons that are members of the library.

This method is supposed to check if the Book object b and the Person b are in the libraryBooks and patrons list respectively. Next it loops through each books object in libraryBooks and uses an overridden equals method to compare if the objects are the same. If they are, it assigns the book to the Persons list of books and remove it from libraryBooks as it is checked out and not inside the library anymore.

After submitting the class files to be graded however, I get these errors: . A person was able to check out a book that was already checked out.

. When checking out a book you should update the book in the library not the one being passed in.

I am confused how a person would be able to check out a book object that has already been checked out because this method should 1. check if the book object being passed is in libraryBooks and 2. remove it from libraryBooks if it gets checked out!

Here is Book.java which holds the book objects:

    public class Book {
    //Initializing variables
    private String title;
    private String author;
    private String dueDate;
    private boolean checkedOut;
    private double bookId;
    private double bookValue;

//Constructor
public Book(String t, String a, double id, double bv){
    title = t;
    author = a;
    bookId = id;
    bookValue = bv;
}

//Accessor
public String getTitle(){
    return title;
}

//Accessor
public String getAuthor(){
    return author;
}

//Accessor
public String getDueDate(){
    return dueDate;
}

//Accessor
public boolean isCheckedOut(){
    return checkedOut;
}

//Accessor
public double getBookId(){
    return bookId;
}

//Accessor
public double getBookValue(){
    return bookValue;
}

//Mutator
public void setDueDate(String dd){
    dueDate = dd;
}

//Mutator
public void setBookValue(double bv){
    bookValue = bv;
}

//Mutator
public void setCheckedOut(boolean b){
    checkedOut = b;
}
@Override
public boolean equals(Object o){
    //Testing to see if value isnt null
    if(o == null){
        return false;
    }
    //Testing to see if value is getting compared to itself
    if (this == o){
        return true;
    }
    //Checking if the values are of the same class
    if (getClass() != o.getClass()){
        return false;
    }
    Book book = (Book)o;
    return (book.bookId == this.bookId);
}

And here is Person.java:

public Person(String n, String a, int lcn){
    name = n;
    address = a;
    libraryCardNum = lcn;
}

//Accessor
public String getName(){
    return name;
}

//Accessor
public int getLibraryCardNumber(){
    return libraryCardNum;
}

//Accessor
public ArrayList<Book> getCheckedOut(){
    return checkedOut;
}

//Accessor
public String getAddress(){
    return address;
}

//Accessor
public int getLibraryCardNum(){
    return libraryCardNum;
}

//Mutator
public void setAddress(String a){
    address = a;
}

//Mutator
public void setLibraryCardNum(int lcn){
    libraryCardNum = lcn;
}

//Mutator Method
public void setName(String n){
    name = n;
}

public boolean addBook(Book b){
    //Checks to see if the book is already in the AL
    if (checkedOut.contains(b)){
        return false;
    }
    else{
        checkedOut.add(b);
        return true;
    }
}

public boolean hasRead(Book b){
    if (checkedOut.contains(b)){
        return true;
    }
    else{
        return false;
    }
}

public boolean forgetBook(Book b){
    if (checkedOut.contains(b)){
        checkedOut.remove(b);
        return true;
    }
    else{
        return false;
    }
}

public int numBooksRead(){
    return checkedOut.size(); //Returns the amount of book objects in AL
}
@Override
public boolean equals(Object o){
    //Checks to make sure the object isnt null
    if (o == null){
        return false;
    }
    //Checks to see if objects are of the same class
    if (getClass() != o.getClass()){
        return false;
    }
    //Casts the object to the person class
    Person person = (Person)o;
    //Checks to see if the name and ID are the same
    return (this.libraryCardNum == person.libraryCardNum);
}

And this is the full Library.java:

import java.util.ArrayList;
import java.util.GregorianCalendar;

import org.junit.Test;
public class Library {
     private ArrayList<Book> libraryBooks = new ArrayList<Book>();
     private ArrayList<Person> patrons = new ArrayList<Person>();
     private String name;
     private int numBooks;
    private int numPeople;
private static String currentDate;

//Constructor
public Library(String n){
    name = n;
}

//Accessor
public ArrayList<Book> getLibraryBooks(){
    return libraryBooks;
}

//Accessor
public ArrayList<Person> getPatrons(){
    return patrons;
    }

//Accesor 
public String getName(){
    return name;
}

//Accesor 
public int getNumBooks(){
    int checkedOutBooks = totalNumBooks() - libraryBooks.size();
    numBooks = libraryBooks.size() - checkedOutBooks;
    return numBooks;
    }

//Accesor 
public int getNumPeople(){
    numPeople = patrons.size();
    return numPeople;
}

//Accesor 
public String getCurrentDate(){ 
    return currentDate;
        }

//Mutator
public void setName(String n){
    name = n;
}

//Mutator
public void setCurrentDate(String d){
    currentDate = d;
    }

//Mutator
public void setLibraryBooks(ArrayList<Book> b){
    libraryBooks = b;
    }

//Mutator
public void setPatrons(ArrayList<Person> p){
    patrons = p;
    }
@Test
public int checkNumCopies(String title, String author){
    int numCopies = 0;
    for (Book b1 : libraryBooks){
        String t = b1.getTitle();
        String a = b1.getAuthor();
        if (t == title && a == author){
            numCopies++;
        }
    }
    for (Person p1 : patrons){
        ArrayList<Book> books = p1.getCheckedOut();
        for (Book b1: books){
            String t = b1.getTitle();
            String a = b1.getAuthor();
            if (t == title && a == author){
                numCopies++;
        }
        }
        }
    return numCopies;
   }


public int totalNumBooks(){
    int numCopies = 0;
    for (@SuppressWarnings("unused") Book b1 : libraryBooks){
            numCopies++;
        }
    for (Person p1 : patrons){
        ArrayList<Book> books = p1.getCheckedOut();
        for (Book b1: books){
            numCopies++;
        }
        }
    return numCopies;
}

public boolean checkOut(Person p, Book b, String dueDate){
    ArrayList<Book> removeBooks = new ArrayList<Book>();
    if (libraryBooks.contains(b) && patrons.contains(p) && b.isCheckedOut()== false){
        for (Book book1 : libraryBooks){
            if (book1.equals(b)){
                p.addBook(book1);
                removeBooks.add(book1);
                book1.setDueDate(dueDate);
                b.setCheckedOut(true);
                System.out.println("Checked out!");
                break;
            }}
        for (Book b2 : removeBooks){
            libraryBooks.remove(b2);    
        }
        return true;
    }
    else{
        System.out.println("Not checked out!");
        return false;
    }
    }
brennan mcgowan
  • 115
  • 1
  • 5
  • Have you implemented an `equals()` method for `Book` and `Person`? for example, "equals" might be true if the [ISBN](https://en.wikipedia.org/wiki/International_Standard_Book_Number) numbers match, even thought they're different *instances* of `Book` – Bohemian Feb 13 '18 at 20:58
  • I did not think of that! Right now my equals() method looks like this: Book book = (Book)o; return (book.bookId == this.bookId); where bookId is the ISBN. This will not take into account copies of the same book. – brennan mcgowan Feb 13 '18 at 21:00
  • Joshua Bloch tells you how to override equals and hashCode properly: http://fpl.cs.depaul.edu/jriely/450/extras/Chapter3.pdf – duffymo Feb 13 '18 at 21:02
  • The instances of classes which you write yourself, such as `Book`, inherit their `equals()` method from the class `Object`. Because Object knows nothing about your class, its equals() method will certainly not test for logical equality in the way you intend. You need to override equals (and hashcode). – scottb Feb 13 '18 at 21:03
  • It looks you already overriden equals() method. though it doesn't look this is the culprit for your case, you need to find a better way of implementing it instead of comparing a book ids' [in Effective java, Joshua blotch outlined a better way of doing it]. Aside from that your issue looks caused due to not implementing a hashcode(). java collection uses both equals and hashcode to compare objects, hence your `libraryBooks.remove(b2`) will be valid if you implement both methods. – Yohannes Gebremariam Feb 13 '18 at 21:08
  • 1
    Please [edit] your post and include the code for the `Book` class. – Jim Garrison Feb 13 '18 at 21:09
  • Would be nice to have the correct code: `if (libraryBooks.contains(b) && patrons.contains(p)){` or `if (libraryBooks.contains(b) && patrons.contains(p) && b.isCheckedOut()== false){` or even something else? – user85421 Feb 13 '18 at 21:40
  • Sorry I just updated this after reading some comments, the new method uses if (libraryBooks.contains(b) && patrons.contains(p) && b.isCheckedOut()== false){ – brennan mcgowan Feb 13 '18 at 21:44
  • IMHO the posted code should work... are you sure that there are distinct books in the library, not the same instance (repeated)? Also sure the tests are correct? – user85421 Feb 13 '18 at 22:42

1 Answers1

0

I don't think that this will fix the problem but it's worth a shot.

if (book1.equals(b)){
        p.addBook(book1);
        removeBooks.add(book1);
        book1.setDueDate(dueDate);
        b.setCheckedOut(true);
        System.out.println("Checked out!");
        break;
    }

Take a look at that line

b.setCheckedOut(true);

It changes the status of the inputted book from false to true, but doesn't change the status of the book in the library from false to true.

The corrected lined should read

book1.setCheckedOut(true);

If that fix doesn't work, could you add your test cases as well? I'm having trouble replicating your problem, as your code seems to work just fine for me.