0

How can I can read my text file into the array list of Book type that shall be able to be modified in the program?

[Edited] I have edited my code to copy each string into one Book type. But it returns error as shown:

Exception in thread "main" java.lang.NumberFormatException: For input string: "eillance Valley"

May I know how to solve this?

p.s. I am trying on GUI approach in my main class, just in case it matters.

This is my text file (booklist.txt):

9781785785719,Surveillance Valley,Yasha Levine,Political Science,57.95,NONE
9780241976630,How to Speak Machine,John Maeda,Non-Fiction,89.95,NONE
9781119055808,R For Dummies,Andre De Vries,Design,107.77,NONE
9780062018205,Predictably Irrational,Dan Ariely,Legal opinion,39.90,NONE
9780008327613,The Globalist,John Waish,Non-Fiction,109.90,NONE
9780525538349,Measure What Matters,John Doerr,Management,86.95,NONE
9780807092156,Man's Search for Meaning,Viktor Frankl,Biography,49.90,NONE

This is my file-reading code:

import java.util.ArrayList;
import java.util.Scanner;
import java.io.*;

public class FileReadDemo {
    public static void main(String[] args) {
        //ArrayList<String> arrayList = new ArrayList<>();
        ArrayList<Book> bookList = new ArrayList<>();
        
        try (Scanner s = new Scanner(new File("c:/Users/brightnow/Documents/booklist.txt")).useDelimiter(",")) {
           
            while (s.hasNext()) {
                // bookList.add(s.next()); // does not work
                //arrayList.add(s.nextLine());
                String[] bookInfo = s.next().split(",");
                
                for (int i = 0; i < bookInfo.length; i++) {
                    String ISBN = bookInfo[i].substring(0);
                    String title = bookInfo[i].substring(1);
                    String author = bookInfo[i].substring(2);
                    String genre = bookInfo[i].substring(3);
                    String price = bookInfo[i].substring(4);
                    String borrower = bookInfo[i].substring(5);
                    Double price2 = Double.parseDouble(price); // error here?
                    bookList.add(new Book(ISBN, title, author, genre, price2, borrower));
                }
            }
        }
        catch (FileNotFoundException e) {
            // Handle the potential exception
        }
        
        // data are broke down into pieces?
        for(int i = 0; i < bookList.size(); i++)
            System.out.println(bookList.get(i));
        
        // data showed as list with "," as delimiter?
        System.out.println(bookList);
    }
}
    

    

This is my Book type:

public class Book {
    private String ISBN;
    private String title;
    private String author;
    private String genre;
    private double price;
    private String borrower;
    
    public Book(String ISBN, String title, String author, String genre, Double price) {
        ISBN = this.ISBN;
        title = this.title;
        author = this.author;
        genre = this.genre;
        price = this.price;
        borrower = "NONE"; // set default no borrower
    }
    
    public String getISBN() {
        return ISBN;
    }
   
   public String getTitle() {
       return title;
   }
   
   public String getAuthor() {
       return author;
   }
   
   public String getGenre() {
       return genre;
   }
   
   public double getPrice() {
       return price;
   }
   
   public String getBorrower() {
       return borrower;
   }
   
   public void setISBN(String aISBN) {
       ISBN = aISBN;
   }
   
   public void setTitle(String aTitle) {
       title = aTitle;
   }
   
   public void setAuthor(String aAuthor) {
       author = aAuthor;
   }
   
   public void setGenre(String aGenre) {
       genre = aGenre;
   }
   
   public void setPrice(double aPrice) {
       price = aPrice;
   }

   public void setBorrower(String aBorrower) {
       borrower = aBorrower;
   }
   
}

4
  • 1
    You didn't ask a question. Beyond that, the file is essentially a CSV file, so you could consider using a CSV parser for that. (If the file format is guaranteed to be that simple and always the same, this might be an overkill, though). Commented Aug 24, 2020 at 15:55
  • 1
    1) Instead of s.hasNext(), use s.hasNextLine() to read the input line by line. 2) Do a split() to get an array of strings for every line. 3) Convert each item of this array to the corresponding member in a Book object and construct a Book. 4) Add the Book you built to a List<Book>. 5) Return the list as the result of your program Commented Aug 24, 2020 at 15:58
  • You probably want to remove those calls to substring. I don’t think they are doing what you think they’re doing. Don’t you want each segment in its entirety that resulted from your call to split? Commented Aug 24, 2020 at 20:35
  • @brightnow in the code quote you have swapped positions for borrower and price paramseters. You are trying to parse number value of Null, which leads to NPE. Make sure you are pointing the correct indices in the array. Also you have an array of length N, but you are reading 7 items at a time from it, so basically you should loop N/7 times. Commented Aug 25, 2020 at 7:44

5 Answers 5

1

I'd do that like this in Kotlin:

import java.io.*

data class Book(
    var ISBN: String,
    var title: String,
    var author: String,
    var genre: String,
    var price: Double,
    var borrower: String
)

operator fun <T> List<T>.component6() = this[5]
fun main() {
    val books = File("c:/Users/brightnow/Documents/booklist.txt").useLines {  // open and close stream
        it.map { line ->  // map each line of Sequence<T> to Book
            line.split(",").let { (iSBN, title, author, genre, price, borrower) ->
                Book(iSBN, title, author, genre, price.toDouble(), borrower)
            }
        }
    }.toList()  // start the operation
}

For Java, I'll do it like this:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

// class Book{...}

public final class FileReadDemo {
    public static void main() {
        List<Book> books = new ArrayList<>();
        try {
            BufferedReader in = new BufferedReader(new FileReader("c:/Users/brightnow/Documents/booklist.txt"));
            String lineText;
            while ((lineText = in.readLine()) != null) {
                // split the line with delimiter
                String[] line = lineText.split(",");
                // create new Book and add that to the list
                books.add(new Book(line[0], line[1], line[2], line[3], Double.parseDouble(line[4]), line[5]));
            }
            in.close();
        } catch (IOException e) {
            System.out.println("File Read Error");
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

To split your String by comma(,) use str.split(",")

try {
    BufferedReader in = new BufferedReader(
                           new FileReader("c:/Users/brightnow/Documents/booklist.txt"));
    String str;

    while ((str = in.readLine())!= null) {
        String[] bookLine=str.split(",");
        // Create an object from bookLine
        // Add the object to an Array
    }
    in.close();
} catch (IOException e) {
    System.out.println("File Read Error");
}

1 Comment

And how is this different from what he already has... The problem he is facing is that he doesn't know how to create a list of N * Book from a list of N * 6 * String...
0

bookList.add(s.next()); will not work because s.next() does not return an instance of Book. What you can do is store the value returned by s.next() into an ArrayList of String like you are doing, and then iterate through that ArrayList and construct a new Book that you can store in bookList since you already have your tokens that s.next() returns split using the comma as a delimiter.

Comments

0

Scanner.hasNext() returns a String. Your bookList is an ArrayList<Book>. You need to create instances of Book before you can add them to bookList.

EDIT

Sebastian Lopez's answer shows you how to change the reading of each line from the file so that you can split() the line string into an array of pieces.

You'll still have to feed those to your Book constructor, and for any value that's not a String, e.g. a Double, you need to do the type conversion.

7 Comments

According to the docs tokens are already split...
Beware, though, that this is a simplistic approach, and will break your code in unexpected ways if you have commas as part of a field value in your data. For this and many other reasons, there are widely used, battle-tested CSV parsing libraries out there, so if you're going to work with CSV data in any serious way, you should use one of them.
Ah yes, you're right. So OP just needs to access the right token for each argument to Book.
I would suggest you to edit your answer or remove it as it is irrelevant for the topic.
Edited my answer as you suggest but I think irrelevant is incorrect, because OP's main problem is typing: trying to insert a String into ArrayList<Book> and not constructing instances of Book in the first place, and I point out the type mismatch.
|
0

You could write another constructor in you Book class:

public Book(String raw) {
    String[] data = raw.split(",");
    ISBN = data[0];
    title = data[1];
    author = data[2];
    genre = data[3];
    price = data[4]; //add conversion to Double here, if needed
    borrower = "NONE";

Then you can just create and add the new Book to you list:

bookList.add(new Book(s.nextLine()));

In order to make it a bit more elegant, you can change the litterals to define the position of each value to constants:

private static final int POS_ISBN = 0;

and then:

ISBN = data[POS_ISBN];

and so on.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.