Reputation: 6683
I recently saw a topic of some Uni coursework which was being conducted by a friend whom was instructed to do it a certain way. I thought I'd take the opportunity to jump in on the task.
I created a Book class like so:
class Book
{
private String author, title;
public Book setAuthor(String a)
{
author = a;
return this;
}
public Book setTitle(String t)
{
title = t;
return this;
}
public String getAuthor()
{
return author;
}
public String getTitle()
{
return title;
}
}
The concept is that a user can create multiple books at the start of the program and then search for an author:
private final static int BOOK_NO = 3;
private final static SO instance = new SO(); // This is whatever you called the class
public static void main(String[] args)
{
Book[] books = new Book[BOOK_NO];
Scanner kybd = new Scanner(System.in);
for(int i = 0; i < BOOK_NO; i++)
{
books[i] = instance.addBook(kybd, new Book());
}
Arrays.stream(instance.findBook(kybd, books)).forEach(o -> {
System.out.println(o.getTitle() + " by " + o.getAuthor());
});
}
public Book addBook(Scanner s, Book b)
{
System.out.println("Enter the Author of this book:");
b.setAuthor(s.next());
System.out.println("Enter the Title of this book:");
b.setTitle(s.next());
return b;
}
public Book[] findBook(Scanner s, Book[] bs)
{
System.out.println("Search a book by author:");
List<Book> finding = Arrays .stream(bs)
.filter(o -> o.getAuthor().equalsIgnoreCase(s.next()))
.collect(Collectors.toList());
System.out.println("Found " + finding.size() + " matches.");
Book[] output = new Book[finding.size()];
output = finding.toArray(output);
return output;
}
Now the whole program works fine, however I am experience unexpected behaviour with the Scanner when it comes to searching for a book. Here is a direct input/output behaviour I am experiencing:
Enter the Author of this book:
Foo
Enter the Title of this book:
Bar
Enter the Author of this book:
Foo
Enter the Title of this book:
FooBar
Enter the Author of this book:
Bar
Enter the Title of this book:
Foo
Search a book by author:
Foo
Foo
Foo
Found 2 matches.
Bar by Foo
FooBar by Foo
As you can see, I am having to type the author of the book into the scanner 3 times before getting any result. How can I mitigate this? What is causing this to happen?
Upvotes: 4
Views: 66
Reputation: 12819
This is because in your Stream
you call next()
, so for every Book
object in the Stream
, the Predicate
in the call to filter is applied to it, and next()
will be called. Resolve it to a variable so it isn't called more than once:
String book = s.next();
List<Book> finding = Arrays.stream(bs)
.filter(o -> o.getAuthor().equalsIgnoreCase(book))
.collect(Collectors.toList());
filter()
accepts a Predicate
, which in this case will be something like:
Predicate<String> pred = str -> str.equalsIgnoreCase(s.next());
So every time it is applied, next()
will be called
Upvotes: 3