Quantcast
Viewing latest article 1
Browse Latest Browse All 6

Answer by Thomas Junk for Book program with arrayList

1) I know it is not your fault, but I strongly disagree with the specification

Methods: public Library(ArrayList other)

Throws a NullPointerException if other is null. Otherwise, the Library’s Book ArrayList should take on all the books in other.

I do not like the fact of killing objects in the constructor. The job of a constructor is: to initialize the object in a sane state - not killing it for user's faults. There are two ways to prevent this:

1) Use a factory or a builder method, which refuse to initialize the Library with null

2) Gracefully ignore the attempt to initialize with null and initialize with an empty ArrayList

Besides: Throwing a NullPointerException in the constructor leads to ugly code, since you have to wrap the construction in an unnecessary try-catch-block. Don't do this - please!

2) NamingYou could improve your naming a little bit:* allBooks should be renamed to justbooks, since the ArrayList contains all books. allBooks is a tautology.

  • add could be renamed to addBook - of course you could object, that this is a tautology too; since every IDE shows you, which type is expected. But not everyone uses an IDE. From this I would prefer addBook

3) Actual Code

First checks for null or empty Strings and calls the appropriate exception. Otherwise it adds the Book argument to the end of the library ArrayList. Notice it returns a boolean (whether or not the add operation succeeded) See the add method of ArrayList:

Again: These are very poor specifications!Why on earth do you have to return a boolean to signal, that there was no error, when the previous sentence clearly states, you have to throw an Exception if anything goes wrong? And more: Who cares for a boolean return-value? The only thing, which would make any sense, would be returning some kind of id in a persistence-context or for heavens sake the total number of books, but not a boolean.

I am unhappy with that implementation. Of course, your Book has a toString()-Method and you are checking if the book is literaly a blank book. But doing it this way:

public boolean add(Book book) {    if (book != null && !book.equals("")) {        throw new IllegalArgumentException("Can't be empty");    }    allBook.add(book);    return true;}

It reads wrong: »Check, whether the book is an empty string!« That doesn't make any sense at all. And honestly: At first, I didn't get it, unless I saw, the toString().

A better way of expressing this would be, adding a method to Book:

public boolean isBlank(){    return bookAuthor.isEmpty() && bookTitle.isEmpty();}

And the check becomes more readable and makes sense

public boolean addBook(Book book) {    if (book == null || book.isBlank()){        throw new IllegalArgumentException("Can't be empty");    }    allBook.add(book);    return true;}

»If the book is nullor the book is blank throw an IllegalArgumentException«Btw. Why did you you use the negative from: !a && !b instead of just a || b?

Generates an ArrayList of all books which have titles that match (exactly) with the passed argument and returns this list to the calling program. The String compareTo method is useful here.

Here the specification is clear, but your implementation is wrong:

public ArrayList<Book> findTitles(String title) {    for(Book b: allBook) {        if(title.compareTo(b.getTitle())== 0) {            return allBook;        }    }    return null;}

You iterate over all books in the library, and if one book matches, you return the whole library. That's not, what you intended. And more Do not return null! Please, never ever! That doesn't make any sense and leads to excessive use of Guard Clauses against null. It is a clear antipattern. In Java8 there is a nicer solution if you want to hidenull in an optional.

Say, your teacher asks you to look for a specific book on the shelf and you do simply nothing - what does that mean to your teacher? A) you are deaf or b) you are dumb or c) you are neither, but there is no book. If someone asks you for a list of books, when there is none, simply return an empty list, and say politely: »Sorry, the list is empty, because there was no such book«.

public ArrayList<Book> findTitles(String title) {    ArrayList<Book> result=new ArrayList<>();    for(Book b: allBook) {        if(title.compareTo(b.getTitle())== 0) {            result.add(b);        }    }    return result;}

This would be the polite way to answer the question.

Sorts the library’s book ArrayList in ascending order according to the title field (sort these titles just as they are, i.e. don’t worry about articles such as The or A, etc.). As illustrated in the textbook, p. 666 (Don’t let this number concern you :) ), you will use the Collections sort.

Sorry, the specification makes me cry.

How does this make sense in any way? Imagine someone going to a library, with a wizards hat on and a big staff: »Sort you, I, as your master, command you!«.

public void sort() {    Collections.sort(allBook);}

Of course, the implementation is according to the specification correct.But that doesn't make really sense. I would prefer two alternatives:

  • If it is crucial, that your library is sorted in some way, you could choose to always have a sorted collection of books

  • otherwise, I would generate a sorted List on the flyThe implementation depends on the usage.

And what is that?

public String toString() {    return Library.this.toString();}

The specification was for once clear at this point:

returns a properly formatted String representation of all the books in the library (Title followed by authors).

public String toString() {    StringBuilder sb=new StringBuilder();    for(Book b:books) sb.append(b.toString());    return sb.toString();}

That should do the trick.

Let's talk about Book:

public Book(String title, ArrayList<String> authors) {    if (title == null && authors == null) {        throw new IllegalArgumentException("Can't be null");    }    if (title.isEmpty() && authors.isEmpty()) {        throw new IllegalArgumentException("Can't be empty");    }    bookTitle = title;    bookAuthor = authors;}

The same as above: Don't throw exceptions in a constructor!Additionally: If you do not allow blank books, why check for blank books in the Library? Are you afraid of malicious subclasses of books, which allow blank books?

public int compareTo(Book other) {    return bookTitle.compareTo(other.bookTitle);}

Why only compare the title? There are at least two books calledFrench Kitchen, but they are not the same, since the authors differ.

public ArrayList<String> getAuthors() {    return bookAuthor;}

This is naughty and could bite you:

public static void main(String[] args) {    ArrayList<String> authors=new ArrayList<>();    authors.add("1");    authors.add("2");    authors.add("3");    authors.add("4");    Book b=new Book("test", authors);    ArrayList<String> list1=b.getAuthors();    list1.add("5");    ArrayList<String> list2=b.getAuthors();    for(String s:list2){        System.out.println(s);    }}

You are leaking the reference of your internal authors.

public List<String> getAuthors() {    List<String> result=new ArrayList<>();    for(String a:bookAuthor) result.add(a);    return result;}

This is what you want.


Viewing latest article 1
Browse Latest Browse All 6

Trending Articles