Library.java: Searching Library.java: Searching Like most self-respecting databases, Library allows users to search for entries by different attributes and check if a particular item is present. The simplest search method is contains. This method returns true if and only if books contains an equivalent entry according to Book's equals method.
public boolean contains(Book findMe)
{
for (int i = 0; i < size; i++) {
if (books[i].equals(findMe)) {
return true;
}
return false;
}
The remaining search methods allow the user to search by a certain attribute. searchByTitle and searchByAuthor look for case insensitive partial matches for title and author fields, respectively. These are implemented using the Book class' titleContains and author contains methods. Note that roughly half of the code in our search functions is devoted to creating a new array and copying matching items into it.
public Book[] searchByTitle(String title)
{
int numBooks = 0;
for (int i = 0; i < size; i++) {
if (books[i].titleContains(title)) {
numBooks++;
}
}
Book[] selection = new Book[numBooks];
int bookCounter = 0;
for (int i = 0; i < size; i++) {
if (books[i].titleContains(title)) {
selection[bookCounter] = books[i];
bookCounter++;
}
}
return selection;
}
public Book[] searchByAuthor(String author)
{
int numBooks = 0;
for (int i = 0; i < size; i++) {
if (books[i].authorContains(title)) {
numBooks++;
}
}
Book[] selection = new Book[numBooks];
int bookCounter = 0;
for (int i = 0; i < size; i++) {
if (books[i].authorContains(title)) {
selection[bookCounter] = books[i];
bookCounter++;
}
}
return selection;
}
The searchByRating method is similar. The main difference is that searchByRating gathers Books that are rated greater than or equal to the provided rating.
public Book[] searchByRating(int rating)
{
int numBooks = 0;
for (int i = 0; i < size; i++) {
if (books[i].getRating() >= rating)) {
numBooks++;
}
}
Book[] selection = new Book[numBooks];
int bookCounter = 0;
for (int i = 0; i < size; i++) {
if (books[i].getRating() >= rating) {
selection[bookCounter] = books[i];
bookCounter++;
}
}
return selection;
}
Let us consider for a moment how a user may actually call our methods:
public static void main(String[] args)
{
Library myLib = new Library(100);
//add some Books using myLib.addBook or myLib.addBooks
Book[] results = myLib.searchByTitle("Java"); //Find some study materials
//Now I want to find all Java books written by someone named "John"
Library javaLib = new Library(results);
Book[] javaByJohn = javaLib.searchByAuthor("John");
//Do something with resulting books on Java by someone named John
...
}
Thanks to our Library(Book[] books) convenience constructor, we can conduct multiple searches and wittle down the answer set. However, this code is a little cumbersome and it would be much nicer if the user could write the following code:
public static void main(String[] args)
{
Library myLib = new Library(100);
//add some Books using myLib.addBook or myLib.addBooks
Library javaByJohn = myLib.searchByTitle("Java").searchByAuthor("John");
//Do something with resulting books on Java by someone named John
...
}
How did we manage to remove the intermediate code? The change was simple: make our search functions return new Library objects instead of Book[]. Since myLib.searchByTitle("Java") returns a perfectly valid Library object, we can go ahead and call our next search function on the result in line. Recall that the union method we discussed earlier behaves in a similarly. As such, you could also incorporate union method calls into the chain. Suppose the user now wants to search for Java books written by someone named John or Elaine:
public static void main(String[] args)
{
Library myLib = new Library(100);
//add some Books using myLib.addBook or myLib.addBooks
Library javaByJohnOrElaine = myLib.searchByTitle("Java").searchByAuthor("John").union(myLib.searchByTitle("Java").searchByAuthor("Elaine"));
//Do something with resulting books
...
}
Below are the final modifications to our search methods. While there was an alternative way to implement the changes, this way is more convenient for future use.
public Library searchByTitle(String title)
{
int numBooks = 0;
for (int i = 0; i < size; i++) {
if (books[i].titleContains(title)) {
numBooks++;
}
}
Library selection = new Library(numBooks);
for (int i = 0; i < size; i++) {
if (books[i].titleContains(title)) {
selection.addBook(books[i]);
}
}
return selection;
}
public Library searchByAuthor(String author)
{
int numBooks = 0;
for (int i = 0; i < size; i++) {
if (books[i].authorContains(title)) {
numBooks++;
}
}
Library selection = new Library(numBooks);
for (int i = 0; i < size; i++) {
if (books[i].authorContains(title)) {
selection.addBook(books[i]);
}
}
return selection;
}
public Library searchByRating(int rating)
{
int numBooks = 0;
for (int i = 0; i < size; i++) {
if (books[i].getRating() >= rating)) {
numBooks++;
}
}
Library selection = new Library(numBooks);
for (int i = 0; i < size; i++) {
if (books[i].getRating() >= rating) {
selection.addBook(books[i]);
}
}
return selection;
}
Questions How do the searchBy methods differ from one another (in terms of code)? By modifying the searchBy methods to return Library objects, we are able to link multiple searches together or even create a union. What other class have you seen (and used) thus far in CS 161 that behaves similarly? We have already identified how to find all Java books written by John or Elaine. How could we further refine our search to books with a rating ≥ 3?