Clearing and removing
An object's list can shrink as well as grow. There are three usual ways: empty the whole list, remove one object, or remove every object that matches a rule.
Emptying the list
The list's own clear() does it:
public void clear() {
this.books.clear();
}
Another way is to replace the list with a new, empty one: this.books = new ArrayList<>();. Either way the shelf is empty afterwards.
Removing one object
A method can pass an object on to the list's remove:
public void remove(Book book) {
this.books.remove(book);
}
remove looks for the book with equals (module 23). Book has no equals of its own, so the one every class gets finds only the very same object: the caller must give a book that's on the shelf, not a new Book with the same title. Often it's handier to remove by a value, such as the title. This method removes the first book with that title, and tells whether it found one:
public boolean removeTitle(String title) {
for (int i = 0; i < this.books.size(); i++) {
if (this.books.get(i).getTitle().equals(title)) {
this.books.remove(i);
return true;
}
}
return false;
}
this.books.remove(i) removes by index, since i is an int (module 14). The loop never goes on after a removal, because return true ends the method right away.
Removing every object that matches
Module 14 warned about this one: removing inside a for-each loop. It crashes inside a class just as it does in main:
public class Main {
public static void main(String[] args) {
Bookshelf shelf = new Bookshelf("Attic");
shelf.add(new Book("Poems", "Dickinson", 96));
shelf.add(new Book("Emma", "Austen", 474));
shelf.add(new Book("Dracula", "Stoker", 418));
shelf.removeShorterThan(100);
System.out.println(shelf);
}
}import java.util.ArrayList;
public class Bookshelf {
private String room;
private ArrayList<Book> books;
public Bookshelf(String room) {
this.room = room;
this.books = new ArrayList<>();
}
public void add(Book book) {
this.books.add(book);
}
public void removeShorterThan(int pages) {
for (Book book : this.books) {
if (book.getPages() < pages) {
this.books.remove(book);
}
}
}
public String toString() {
return this.room + ": " + this.books;
}
}public class Book {
private String title;
private String author;
private int pages;
public Book(String title, String author, int pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
public int getPages() {
return this.pages;
}
public String toString() {
return this.title + " by " + this.author + ", " + this.pages + " pages";
}
}Exception in thread "main" java.util.ConcurrentModificationException
at Bookshelf.removeShorterThan(Bookshelf.java:17)
at Main.main(Main.java:7)Line 17 of Bookshelf.java is the for-each line: the list changed while the loop was going through it. The fix is the same as in module 14, an index loop that goes backwards:
public void removeShorterThan(int pages) {
for (int i = this.books.size() - 1; i >= 0; i--) {
if (this.books.get(i).getPages() < pages) {
this.books.remove(i);
}
}
}
Going from the end, a removal only moves books the loop has already checked. With this version, the attic shelf keeps Emma and Dracula.