I'm having problems changing the ISBN number to the name of the title of the book
Starts of printing the ISBN, author, title and level of book left:
0201403765 Jan Skansholm Ada 95 from the Beginning 100
0202535665 M. Ben-Ari Software Engineering 25
034565976X Michael Feldman Program Construction 12
080539057X M.A. Weiss Data Structures 30
0805645782 Ken Arnold Java for Programmers 10
0905297568 A. Badone Chaos Theory 15
Prints out whats in transactions.txt:
0201403765 -55
0201403765 2
0202535665 10
0202535665 -28
034565976X -7
080539057X -15
0905297568 13
0905297568 -5
So basically what I need to do is change the ISBN to the the title of the book if it matches, like this:
Java from the Beginning -55
Java from the Beginning 2
Software Engineering 10
Software Engineering -28
Program Construction -7
Data Structures -15
Chaos Theory 13
Chaos Theory -5
The problem im having is at 1 marked in the code below , really unsure how to check if the isbn matches and if so how to check what title matches the isbn and write it out , I think my problem is the arraylist ( should i make a third arraylist) or just make everything into arrays, any advice will do , cheers !!!! btw 1 is completely ludacrisly wrong....
import java.util.*;
import java.io.*;
class inventory{
static void intial(){
try{
RandomAccessFile in = new RandomAccessFile("books.dat","r");
ArrayList<String> list1=new ArrayList<String>();
String author ,title , isbn;
int level=0;
while(in.getFilePointer()<in.length()){
author = in.readUTF(); // author, at most 20 characters
title = in.readUTF(); // title, at most 40 characters
isbn = in.readUTF(); // ISBN
level = in.readInt(); // level, i.e. copies in stock (>=0)
//System.out.printf("%5d", isbn+author+title+level);
System.out.println(isbn+" "+author+" "+title+" "+level);
list1.add(title);
list1.add(isbn);
//list1.add(level);
}
in.close();
System.out.println(" ");
String isbn2;
int level2=0;
//try{
Scanner out = new Scanner(new File ("transactions.txt"));
ArrayList<String> list2=new ArrayList<String>();
while(out.hasNextLine()){
isbn2 = out.next();
level2 = out.nextInt();
System.out.println(isbn2 +" "+level2);
list2.add(isbn2);
//list2.add(level2);
}
out.close();
1) for (isbn: list1){
for(isbn2: list2){
if(isbn.contains(isbn2)){
System.out.println(title+" "+level);
}
}
}
}
catch(IOException f){
System.out.println("file error");
f.printStackTrace();
}
}
}
class BookShop{
public static void main(String[]args){
inventory x = new inventory();
x.intial();
First create a Book object to store your book data.
public Book{
private String ISBN ="";
private String title="";
private String author="";
private int level;
public Book(String ISBN, String title,String author, int level){
this.ISBN=ISBN;
this.title=title;
this.author=author;
this.level=level;
}
public String getTitle(){
return title;
}
public String getISBN(){
return ISBN;
}
public String getAuthor(){
return author;
}
public int getLevel(){
return level;
}
}
Add the Book objects to the ArrayList.
ArrayList<Book> bkList = new ArrayList<Book>();
bkList.add(new Book('ISBN','Title','Author'));
Get Book data with the get() method.
Book tempBook;
for (int x=0;x<bkList.Size();x++){
tempBook=bkList.get(x);
System.out.println(tempBook.getTitle()+" "+tempBook.getLevel());
}
I would create an object to hold each book, like this:
class Book {
public final String isbn;
public final String title;
public final String author;
public final int level;
public Book(String isbn, String title, String author, int level) {
this.isbn = isbn; this.title = title; this.author = author; this.level = level;
}
}
and populate the ArrayList with Book objects. That way everything for one Book is in one place, as opposed to needing parallel arrays.
(The way I wrote this class it is immutable, because you don't have any reason to update the objects once they're read in from the input file. If this was Python or Haskell we'd just use a tuple and do without the ceremony, but with Java we don't have that option.)
Related
I have two classes and they both form ArrayLists. I have a menu option where the user needs to be able to add a book (title, copyright, ISBN, edition, and AUTHOR). This works entirely, but the problem is I need an option to add multiple authors and I cannot think of a way around this. Here is my working code below for adding a single author:
public void addBook(ArrayList<Book> books, ArrayList<Author> aut) {
Scanner scan = new Scanner(System.in);
System.out.println("Please enter the title:");
String title = scan.nextLine();
System.out.println("Please enter the copyright:");
int copy = scan.nextInt();
System.out.println("Please enter the edition:");
int ed = scan.nextInt();
System.out.println("Please enter the isbn:");
String isbn = scan.nextLine();
scan.nextLine();
System.out.println("Please enter the author: ");
String authors = scan.nextLine();
ArrayList<Author> aut = new ArrayList<>();
String firstName = authors.split(" ")[0];
String lastName = authors.split(" ")[1];
Author bookAuthor = new Author(firstName, lastName);
boolean foundAuthor = false;
for (int i = 0; i < aut.size(); i++) {
Author currentAuthor = aut.get(i);
if (currentAuthor.getFirst().equalsIgnoreCase(firstName)
&& currentAuthor.getLast().equalsIgnoreCase(lastName)) {
bookAuthor = currentAuthor;
foundAuthor = true;
break;
}
}
if (!foundAuthor) {
aut.add(bookAuthor);
}
au.add(bookAuthor);
books.add(new Book(title, copy, ed, isbn, au));
}
What is best approach to support the user entering multiple authors?
This will be fairly long, but hopefully this should help you.
First off, you should put a method in your Book class, that will prompt a user for authors, and add any of entered authors into the list for that object.
Here is what that class would look like along with a main that is just for testing purposes. I have excluded all of your other fields:
public class Book {
ArrayList<Author> authors = new ArrayList<>();
public Book() {
}
public Book(String title, int copyright, int edition, String isbn, ArrayList<Author> authors) {
/*
I left these fields out of this example on purpose.
this.title = title;
this.copyright = copyright;
this.edition = edition;
this.isbn = isbn; */
this.authors = authors;
}
public void promptForAuthors()
{
Scanner scan = new Scanner(System.in);
String response = "Y";
do {
System.out.println("Please enter the author. ");
String input = scan.nextLine();
String [] splitAuthors = input.split(" ");
Author author = new Author(splitAuthors[0], splitAuthors[1]);
if (!this.authors.contains(author)) {
this.authors.add(author);
}
System.out.println("Would you like you add an additional author? (Y or N) ");
response = scan.nextLine();
} while(response.equalsIgnoreCase("Y"));
}
public void printAuthors() {
for (Author a : this.authors) {
System.out.println(a.getFirstName() + " " + a.getLastName());
}
}
public static void main(String[] args) {
Book b = new Book(); //This will normally be the constructor that includes the ISBN, copyright, etc.
b.promptForAuthors();
b.printAuthors();
}
}
You can see from the main how you should use this in your addBooks code. Basically you create your Book out of all the other fields you used as input, then you can call this method on that object.
You will probably need to modify your current constructor so that it no longer requires the list for authors to be input when constructed, so you can use it afterward (you can just have both constructors available as well).
The promptForAuthors() will continue to prompt the user to enter in an Author until they hit anything other than Y or y.
This method will always ask for an author as least a single time, due to the use of a do-while loop. One of the main advantages of doing it in the Book class itself, is this method could be reused at any time to add more authors to the same book down the line if that is functionality eventually needed.
Additionally, the method will use .contains() to check if the Author already exists inside of the list, and only add the Author if it is a new Author. This requires an Override of .hashCode() and .equals() in your Author class which you can find the one I made below:
//IN THE AUTHOR CLASS PLACE THESE METHODS AND MODIFY FOR EXTRA FIELDS
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Author)) {
return false;
}
Author user = (Author) o;
return user.firstName.equals(this.firstName) &&
user.lastName.equals(this.lastName);
}
#Override
public int hashCode() {
int result = 17;
result = 31 * result + this.firstName.hashCode();
result = 31 * result + this.lastName.hashCode();
return result;
}
Note: I included a printAuthors() method just as an easy way to verify no extra duplicate Authors were added.
Example Run of adding Authors:
Please enter the author.
Joe Smith
Would you like you add an additional author? (Y or N)
y
Please enter the author.
Billy Bob
Would you like you add an additional author? (Y or N)
n
Joe Smith
Billy Bob
Try allowing the user to enter a special string to exit the input loop.
Change
String authors = scan.nextLine();
into a loop to populate a list of strings from input
ArrayList<String> authorNames = new ArrayList<>();
System.out.println("Please enter authors. Enter DONE when you are done.");
String nextLine = scan.nextLine();
while (!nextLine.equals("DONE")) {
authorNames.add(nextLine);
nextLine = scan.nextLine();
}
// This doesn't prevent the user from entering zero authors. Idk if you care about that.
alternatively, accept input of authors as only one line with some delimiter and use String.split on that delimiter later.
1 - create a list of lists.(List of Another list author).
2 - create an object of author list.
3 - perform all the action you want to perform on this author list.
4 - add author list to list of author list.
5 - To access author you need syntax like first_list_object.get(index).author_object_variable_or_member.
ArrayList<ArrayList<Author>> authorList = new ArrayList<>();
ArrayList<Author> au = new ArrayList<Author>();
String firstName = authors.split(" ")[0];
String lastName = authors.split(" ")[1];
Author bookAuthor = new Author(firstName, lastName);
au.add(bookAuthor);
authorList.add(au);
I think You're working with the wrong collection. You have a couple of author's. Each author could have written several books. So the right thing would be a Map<Author,ArrayList<Book>>.
It will make Your programming logic for addBook() easier, if You can use a map.
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?
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
//Sorting userDefined object from ArrayList<>...
import java.io.*;
import java.util.*;
class Song implements Comparable<Song>{
String title;
String movie;
String rating;
public int compareTo(Song s){
//System.out.println(getTitle()+" "+s.getTitle());
/*The upper comment is for testing purpose,
*because i wanted to see whats the value getTitle() compares..
*but i couldn't understand.
*/
return getTitle().compareTo(s.getTitle());
}
public Song(String t, String m, String r){
//R.I.P. Naming Convention.
title = t;
movie = m;
rating = r;
}
public String getTitle(){
return title;
}
public String toString(){
return title;
}
}
class ArrayListDemo{
ArrayList<Song> songsList = new ArrayList<Song>();
public static void main(String[] args){
new ArrayListDemo();
}
public ArrayListDemo(){
getSongs();
System.out.println(songsList);
Collections.sort(songsList);
System.out.println(songsList);
}
public void getSongs(){
try{
File file = new File("SongsList.txt");
//check below for SongsList.txt
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
while((line = reader.readLine()) != null){
addSong(line);
}
} catch(IOException e){
e.printStackTrace();
}
}
public void addSong(String lineToParse){
String[] token = lineToParse.split("/");
Song nextSong = new Song(token[0], token[1], token[2]);
songsList.add(nextSong);
}
}
SongsList.txt
Soch Na Sake / Airlift / 9.1
Jeena / Badlapur / 8.7
Tere Sang Yaara / Rustom / 8.8
Aayat Ki Tarah / BaajiravMastaani / 7.9
Ikk Kudi / UdtaPunjab / 7.5
Tay Hai / Rustom / 7.8
Output:-
Before Sorting...
[Soch Na Sake , Jeena , Tere Sang Yaara , Aayat Ki Tarah , Ikk Kudi , Tay Hai ]
After Sorting...
[Aayat Ki Tarah , Ikk Kudi , Jeena , Soch Na Sake , Tay Hai , Tere Sang Yaara ]
Caution:- Beginner Level English Ahead!!!
So this is working of my program... Reference :-HeadFirstJava 2nd , JukeBox3 Page no.- 550
So, coming to the problem..
i understood most of them...but this is where my mind is rolling.. o.O
public int compareTo(Song s){
return getTitle().compareTo(s.getTitle());
}
getTitle() & s.getTitle()
from where getTitle() gets value and compares it...
ok, i know that compareTo() compares String but and i also know the -1,0,1 (<,=,>) rule,
the thing which cracking me up is from where getTitle() gets the value.
and one more thing... the book says that
Collections.sort(songsList);
when this method gets called, the sort method sends an element from songsList to compareTo() method.. means s.getTitle() = title of the element sent bye sort(). Right ?
but from where the first getTitle() gets the value... the one which is after the return and before the .compareTo().
Kindly assist me here, checked docs, other answers, everything i can in last two days....
in simple words i want to know that from where and which values getTitle() gets to compare.
public int compareTo(Song s) is used to compare 2 Song objects. One of them is the one the method is called on, and the other is passed as an argument.
For example :
Song s1 = ...
Song s2 = ...
int s1.compareTo(s2);
In this example, getTitle() in the body of public int compareTo(Song s) will return the title of s1, while s.getTitle() wil return the title of s2.
Collections.sort(songsList); will always use compareTo to compare 2 Song objects - one of them it will call the method on, and the other will be passed as an argument.
I am running into some issues with my Java program. We have to create a library, which contains the title(halo, lotr) , the format (xbox, dvd etc), the date loaned (if it is ever loaned), and the person it is loaned to (if it is ever loaned).
I am not complete with my code, however I am testing it out as I go along instead of just compiling the entire finished code after 5 hours of coding. I am running into a problem. Whenever I set a public string variable to a value, it saves in the method I declared it in, but it will display "null" when system.out.print'd in other methods.
heres my code. First class is Library.
package p1;
import java.util.Scanner;
public class Library {
// \/ FIELDS
private String[] mediaItemTitle = new String[100];
public String[] mediaItemFormat = new String[100];
public String[] mediaItemLoanedTo = new String[100];
public String[] mediaItemOnLoan = new String[100];
public String[] mediaItemDateLoaned = new String[100];
public String today = "3/9/2015";
public int numberOfItems;
// /\ FIELDS
// \/ METHODS
public static void main(String[] brad){
Scanner input = new Scanner(System.in);
MediaItem main;
main = new MediaItem();
String title;
String format;
String date;
String name;
for ( int i = 0; i != 5; ){
i = displayMenu();
if (i == 1){
System.out.println("What is the title? ");
title = input.nextLine();
System.out.println("What is the format? ");
format = input.nextLine();
main.MediaItem(title,format);
}else if (i == 2){
System.out.println("Which Item (Enter the title? ");
title = input.nextLine();
System.out.println("Who are you loaning it to? ");
name = input.nextLine();
System.out.println("When did you loan it to them? ");
date = input.nextLine();
}else if (i == 3){
main.MediaItem();
}else if (i == 4){
System.out.print("Which item? (enter the title) ");
title = input.nextLine();
main.markReturned(title);
}else if (i == 5){ // DONE
System.out.print("Goodbye!");
break;
}
}
}
public static int displayMenu(){ // DONE
Scanner input = new Scanner(System.in);
int choice = 0;
System.out.println("1. Add new item");
System.out.println("2. Mark an item as on loan");
System.out.println("3. List all items");
System.out.println("4. Mark an item as returned");
System.out.println("5. Quit");
choice = input.nextInt();
return choice;
}
public void addNewItem(String title, String format){
this.mediaItemTitle[numberOfItems] = title;
this.mediaItemFormat[numberOfItems] = format;
System.out.print("TEST: " + mediaItemTitle[numberOfItems]);
}
public void incrementNumberOfItems(){
numberOfItems++;
}
public void listAllItems(){
for (int i = 0; i < numberOfItems; i++){
System.out.print(mediaItemTitle[i])
}
}
Here is the second part of code, my second class MediaItem
package p1;
public class MediaItem {
// \/ METHODS
public void MediaItem(){
Library list;
list = new Library();
list.listAllItems();
}
public void MediaItem(String title, String format){
Library call;
call = new Library();
call.addNewItem(title, format);
call.incrementNumberOfItems();
}
// /\ METHODS
}
This is driving me insane. I would love to just have me public variables save their value between methods but its not happening. the console (when 3 is chosen from displayMenu)
0
null
which means numberOfItems and mediaItemTitle[i] are read to be 0, and null. Which I dont understand, because I declared them earlier in the program!!!
I dont understand what Im doing wrong. please help me! Thank you!!
Your main mistake is that you are creating a new instance of Library inside your MediaItem method. That Library object will only live in the scope of MediaItem method. Plus Library is your main static class.
Your design is all wrong in my opinion. It looks like you are learning you way to Java or OOP, which is perfectly fine to have these mistakes.
Separate your data from your main class, create new classes just for your data. Have a look at java POJO (Plain Old Java Objects), like here
For example:
String title;
String format;
String date;
String name;
Should be in a new object, a POJO. Something like:
public class MyDataPOJO {
private String title;
private String format;
private String date;
private String name;
public MyDataPOJO(String title, String format, String date, String name) {
this.title = title;
this.format = format;
this.date = date;
this.name = name;
}
public String getTitle() {return title;}
public String getFormat() {return formate;}
// And the rest of the getter methods for date and name
}
In you Library class you may only need to hold your logic. But even that can be re-factored to another class.
On a side note, please check the java naming convention. Here is a guideline: link. In other words, start you methods name with lower case.
Example, your public void MediaItem(){/** something*/} should be public void mediaItem(){/** something*/ }
Follow the answer above and treat this as a comment, since the persons answer is correct and my statement isn't regarding your primary problem.
In your for-loop, I think you should add another else if statement. If the user enters a number that is not 1-5, they should receive an error. So maybe something like
else if (i < 1 || i > 5)
System.out.println("Error: Enter a choice 1-5\n");
Also, I think you may have forgotten a } to end your listAllItems() method.
But as I was saying, the answer to your real problem has already been handled, so give them the check mark. This is just a minor UI error I noticed.
I'm working on a type of inventory program that deals with reading in a list of items from a file and I'm having some trouble.
Here's the code I have finished so far:
import java.util.Scanner;
import java.io.*;
public class Store {
public static void main(String[] args) throws Exception {
Book[] books = readInventory();
for (Book book : books) {
System.out.printf("ISBN: %s, Price: %f, Copies: %d%n",
book.getISBN(), book.getPrice(), book.getCopies());
}
}
public static Book[] readInventory() throws Exception {
Book[] books = new Book[15];
java.io.File file = new java.io.File("../instr/prog4.dat");
Scanner fin = new Scanner(file);
String isbn;
double price;
int copies;
int i = 0;
while (fin.hasNext()) {
isbn = fin.next();
if (fin.hasNextDouble()); {
price = fin.nextDouble();
}
if (fin.hasNextInt()); {
copies = fin.nextInt();
}
Book book = new Book(isbn, price, copies);
books[i] = book;
i++;
}
fin.close();
return books;
}
public static void printInfo(Book[] books) {
for(int x=0; x<books.length; x++) {
System.out.println("ISBN: " + books[x].getISBN() + "\n Price: " +
books[x].getPrice() + "\n Copies: " + books[x].getCopies());
}
}
}
class Book {
private String isbn;
private double price;
private int copies;
public Book(String isbnNum, double priceOfBook, int copiesInStock) {
isbn = isbnNum;
price = priceOfBook;
copies = copiesInStock;
}
public String getISBN() {
return isbn;
}
public double getPrice() {
return price;
}
public int getCopies() {
return copies;
}
public void setISBN(String isbn) {
this.isbn = isbn;
}
public void setPrice(double price) {
this.price = price;
}
public void setCopies(int copies) {
this.copies = copies;
}
#Override
public String toString() {
return String.format("ISBN: %s, Price: %f, Copies: %d%n",
this.getISBN(), this.getPrice(), this.getCopies());
}
}
The program compiles fine, but when I run the program I get the error
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:855)
at java.util.Scanner.next(Scanner.java:1364)
at Store.readInventory(Store.java:31)
at Store.main(Store.java:13)
Here is the contents of the file I am supposed to use:
1234567 31.67 0
1234444 98.50 4
1235555 27.89 2
1235566 102.39 6
1240000 75.65 4
1247761 19.95 12
1248898 155.91 0
1356114 6.95 17
1698304 45.95 3
281982X 31.90 5
I have been looking at another program I wrote recently that dealt with reading files to see that I was throwing the exceptions in the same types of places and it appears that I am (everything dealing with the file in that program was in the main method so that was the only one throwing an exception). From what I remember from an earlier Java programming class, we were supposed to throw exceptions at the main method and any other methods that deal with the file, so in this case I have the one on main and another on my readInventory() method.
What am I missing?
Check for next value before reading to avoid such exception as you are doing for isbn but not for price and copies.
sample code:
if(fin.hasNextDouble()){
price = fin.nextDouble();
}
if(fin.hashNextInt()){
copies = fin.nextInt();
}
For example Scanner#nextInt() method throws:
InputMismatchException - if the next token does not match the Integer regular expression, or is out of range
NoSuchElementException - if input is exhausted
IllegalStateException - if this scanner is closed
You are creating array of size 15 where is there is only 10 line in file that result in NullPointerException. Use List in that case.
You can use Java 7 - The try-with-resources Statement for better resource management even in case of error.
sample code
public static BookDetail[] readInventory() throws Exception {
List<BookDetail> books = new ArrayList<BookDetail>();
java.io.File file = new java.io.File("../instr/prog4.dat");
try (Scanner fin = new Scanner(file)) {
String isbn;
double price = 0;
int copies = 0;
while (fin.hasNext()) {
isbn = fin.next();
if (fin.hasNextDouble()) {
price = fin.nextDouble();
}
if (fin.hasNextInt()) {
copies = fin.nextInt();
}
BookDetail book = new BookDetail(isbn, price, copies);
books.add(book);
}
}
return books.toArray(new BookDetail[books.size()]);
}
Currently, you are checking if the file has more data, then you attempt to read 15 books, no matter what. Your for-loop goes from 0 to books.length-1, whatever is in the file.
Since you don't know (in theory) how many books there are in the file, you need to check fin.hasNext before reading each book.
So get rid of your for-loop and replace your reading code with something like this:
int i = 0;
while (fin.hasNext()) {
// read book here and assign to books[i]
// increment i for next iteration
i++;
}
The while condition fin.hasNext() will be checked before reading each book. When it returns false, you'll stop looping, and i will be the number of books you read.
Note that you're still assuming that each book has all its fields. If there was only half a book in the file, your code would still crash. But that's probably a good thing, since there's not really a way you can recover from that, and presumably you can assume you will receive only well-formed input.
I would suggest you use exception handling. I especially recommend using try with resources, since you forget to close the scanner that you are using.
You need to check in the code that you receive all the information that you need for each book. You don't want to have only partial information on the book just because you couldn't receive the rest of the data on that particular book.