I am writing a program which will allow users to reserve a room in a hotel (University Project). I have got this problem where when I try and read data from the file and store it in an array I receive a NumberFormatException.
I have been stuck on this problem for a while now and cannot figure out where I am going wrong. I've read up on it and apparently its when I try and convert a String to a numeric but I cannot figure out how to fix it.
Any suggestions, please?
This is my code for my reader.
FileReader file = new FileReader("rooms.txt");
Scanner reader = new Scanner(file);
int index = 0;
while(reader.hasNext()) {
int RoomNum = Integer.parseInt(reader.nextLine());
String Type = reader.nextLine();
double Price = Double.parseDouble(reader.nextLine());
boolean Balcony = Boolean.parseBoolean(reader.nextLine());
boolean Lounge = Boolean.parseBoolean(reader.nextLine());
String Reserved = reader.nextLine();
rooms[index] = new Room(RoomNum, Type, Price, Balcony, Lounge, Reserved);
index++;
}
reader.close();
This is the error message
This is the data in my file which I am trying to read:
Change your while loop like this
while (reader.hasNextLine())
{
// then split reader.nextLine() data using .split() function
// and store it in string array
// after that you can extract data from the array and do whatever you want
}
You're trying to parse the whole line to Integer. You can read the whole line as a String, call
.split(" ")
on it. This will split the whole line into multiple values and put them into an array. Then you can grab each item from the array and parse separately as you intended.
Please avoid posting screenshots next time, use proper formatting and text so someone can easily copy your code or test data to IDE and reproduce the scenario.
Use next() instead of nextLine().
With Scanner one must use hasNextLine, nextLine, hasNext, next, hasNextInt, nextInt etcetera. I would do it as follows:
Using Path and Files - the newer more general classes i.o. File.
Files can read lines, here I use Files.lines which gives a Stream of lines, a bit like a loop.
Try-with-resources: try (AutoCloseable in = ...) { ... } ensures that in.close() is always called implicitly, even on exception or return.
The line is without line ending.
The line is split into words separated by one or more spaces.
Only lines with at least 6 words are handled.
Create a Room from the words.
Collect an array of Room-s.
So:
Path file = Paths.get("rooms.txt");
try (Stream<String> in = Files.lines(file)) {
rooms = in // Stream<String>
.map(line -> line.split(" +")) // Stream<String[]>
.filter(words -> words.length >= 6)
.map(words -> {
int roomNum = Integer.parseInt(words[0]);
String type = words[1];
double price = Double.parseDouble(words[2]);
boolean balcony = Boolean.parseBoolean(words[3]);
boolean lounge = Boolean.parseBoolean(words[4]);
String reserved = words[5];
return new Room(roomNum, type, price, balcony, lounge, reserved);
}) // Stream<Room>
.toArray(Room[]::new); // Room[]
}
For local variables use camelCase with a small letter in front.
The code uses the default character encoding of the system to convert the bytes in the file to java Unicode String. If you want all Unicode symbols,
you might store your list as Unicode UTF-8, and read them as follows:
try (Stream<String> in = Files.lines(file, StandardCharsets.UTF_8)) {
An other issue is the imprecise floating point double. You might use BigDecimal instead; it holds a precision:
BigDecimal price = new BigDecimal(words[2]);
It is however much more verbose, so you need to look at a couple of examples.
Related
I have a scanner with many lines of text(representing number) and I want to convert all the text in the scanner to a List.
Example:
Scanner myScanner = new Scanner(new File("input.txt"));
input.txt:
000110100110
010101110111
111100101011
101101001101
011011111110
011100011001
110010011100
000001011100
101110100110
010001011100
011111001010
100111100101
111111000010
My first thought was to convert it to a String by changing the delimiter to something I know is not in the file:
myScanner.useDelimiter("impossible String");
String content = myScanner.next();
and then use
List<String> fullInput = Arrays.asList(content.split("\n"));
However, it gives me problems later on with parsing the numbers on the scanner. I've tried debugging it but I can't seem to understand the problem. For example, I made it print the String to the console before parsing it. It would print a proper number(asString) and then give me NumberFormatException when it is supposed to parse.
Here's the runnable code:
public static void main(String[] args) throws FileNotFoundException {
Scanner myScanner = new Scanner(new File("input.txt"));
myScanner.useDelimiter("impossible String");
String content = myScanner.next();
List<String> fullInput = Arrays.asList(content.split("\n"));
System.out.println(fullInput.get(1));
System.out.println(Long.parseLong(fullInput.get(1)));
}
This is what I ended up using after the first didn't work:
Scanner myScanner = new Scanner(new File("input.txt"));
List<String> fullInput = new ArrayList<>();
while (sc.hasNextLine())
fullInput.add(myScanner.nextLine());
Do you know what's wrong with the first method or is there a better way to do this?
Because you are parsing a string that represents a number that's beyond the size of an integer.
int values can be between -2,147,483,648 to 2,147,483,647.
fullInput.get(1) gives you 010101110111 which is greater than 2,147,483,647.
You can use long.
long val = Long.parseLong(fullInput.get(1));
If the string represents binary numbers and you want to convert them to int, then you need to provide the base when parsing the string.
int val = Integer.parseInt(fullInput.get(1), 2);
For what you are trying to do here, Scanner is the wrong solution.
If your goal is to simply read the all lines of the file as String[] you can use the Files.readAllLines(Path, Charset) method (javadoc) to do this. You could then wrap that as a List using Arrays.asList(...).
What you are actually doing could work under some circumstances. But one possible problem is that String.split("\n") only works on systems where the line terminator is a single NL character. On Windows, the line terminator is a CR NL sequence. And in that case, String.split("\n") will leave a CR at the end of all but the last string / line. That would be sufficient to cause Long.parseLong(...) to throw a NumberFormatException. (The parseXxx methods do not tolerate extraneous characters such as whitespace in the argument.)
A possible solution to the extraneous whitespace problem is to trim the string; e.g.
System.out.println(Long.parseLong(fullInput.get(1).trim()));
The trim() method (javadoc) returns a string with any leading and/or trailing whitespace removed.
But there is another way to deal with this. If you don't care whether each number in the input file is on a separate line, you could do something like this:
Scanner myScanner = new Scanner(new File("input.txt"));
List<Long> numbers = new ArrayList<>();
while (myScanner.hasNextLong()) {
numbers.append(myScanner.nextLong());
}
Finally, #ChengThao makes a valid point. It looks like these are binary numbers. If they are in fact binary, then it makes more sense to parse them using Long.parseLong(string, radix) with a radix value of 2. However if you parse them as decimal using parseLong (as you are currently doing) the values in your question will fit into a long type.
This is a project from school, but i'm only asking for help in the logic on one small part of it. I got most of it figured out.
I'm being given a file with lines of string integers, for example:
1234 123
12 153 23
1234
I am to read each line, compute the sum, and then go to the next one to produce this:
1357
188
1234
I'm stuck on the scanner part.
public static void doTheThing(Scanner input) {
int[] result = new int[MAX_DIGITS];
while(input.hasNextLine()) {
String line = input.nextLine();
Scanner linesc = new Scanner(line);
while(linesc.hasNext()) {
String currentLine = linesc.next();
int[] currentArray = convertArray(stringToArray(currentLine));
result = addInt(result, currentArray);
}
result = new int[MAX_DIGITS];
}
}
In a nutshell, I want to grab each big integer, put it an array of numbers, add them, and then i'll do the rest later.
What this is doing it's basically reading all the lines and adding everything and putting it into a single array.
What i'm stuck on is how do I read each line, add, reset the value to 0, and then read the next line? I've been at this for hours and i'm mind stumped.
Edit 01: I realize now that I should be using another scanner to read each line, but now i'm getting an error that looks like an infinite loop?
Edit 02: Ok, so after more hints and advice, I'm past that error, but now it's doing exactly what the original problem is.
Final Edit: Heh....fixed it. I was forgetting to reset the value to "0" before printing each value. So it makes sense that it was adding all of the values.
Yay....coding is fun....
hasNext method of the Scanner class can be used to check if there is any data available in stream or not. Accordingly, next method used to retrieve next continuous sequence of characters without white space characters. Here use of the hasNext method as condition of if doesn't make any sense as what you want is to check if the there are any numerical data left in the current line. You can use next(String pattern).
In addition, you can try this solution even though it is not optimal solution...
// In a loop
String line = input.nextLine(); //return entire line & descard newline character.
String naw[] = line.split(" "); //split line into sub strings.
/*naw contains numbers of the current line in form of string array.
Now you can perfom your logic after converting string to int.*/
I would also like to mention that it can easily & efficiently be done using java-8 streams.
An easier approach would be to abandon the Scanner altogether, let java.nio.io.Files to the reading for you and then just handle each line:
Files.lines(Paths.get("/path/to/my/file.txt"))
.map(s -> Arrays.stream(s.split("\\s+")).mapToInt(Integer::parseInt).sum())
.forEach(System.out::println);
If i were you i would be using the BufferedReader insted of the Scanner like this:
BufferedReader br = new BufferedReader(new FileReader("path"));
String line = "";
while((line = br.readLine()) != null)
{
int sum = 0;
String[] arr = line.split(" ");
for(String num : arr)
{
sum += Integer.parseInt(num);
}
System.out.println(sum);
}
Considering the level you're on, I think you should consider this solution. By using only the scanner, you can split the lines into an array of tokens, then iterate and sum the tokens by parsing them and validating that they're not empty.
import java.util.*;
class SumLines {
public static void main(String[] args) {
Scanner S = new Scanner(System.in);
while(S.hasNext()) {
String[] tokens = S.nextLine().split(" ");
int sum = 0;
for(int i = 0; i < tokens.length; i++) {
if(!tokens[i].equals("")) sum += Integer.parseInt(tokens[i]);
}
System.out.println(sum);
}
}
}
My question is -
how to convert a String ArrayList to an Integer ArrayList?
I have numbers with ° behind them EX: 352°. If I put those into an Integer ArrayList, it won't recognize the numbers. To solve this, I put them into a String ArrayList and then they are recognized.
I want to convert that String Arraylist back to an Integer Arraylist. So how would I achieve that?
This is my code I have so far. I want to convert ArrayString to an Int Arraylist.
// Read text in txt file.
Scanner ReadFile = new Scanner(new File("F:\\test.txt"));
// Creates an arraylist named ArrayString
ArrayList<String> ArrayString = new ArrayList<String>();
// This will add the text of the txt file to the arraylist.
while (ReadFile.hasNextLine()) {
ArrayString.add(ReadFile.nextLine());
}
ReadFile.close();
// Displays the arraystring.
System.out.println(ArrayString);
Thanks in advance
Diego
PS: Sorry if I am not completely clear, but English isn't my main language. Also I am pretty new to Java.
You can replace any character you want to ignore (in this case °) using String.replaceAll:
"somestring°".replaceAll("°",""); // gives "sometring"
Or you could remove the last character using String.substring:
"somestring°".substring(0, "somestring".length() - 1); // gives "somestring"
One of those should work for your case.
Now all that's left is to parse the input on-the-fly using Integer.parseInt:
ArrayList<Integer> arrayInts = new ArrayList<Integer>();
while (ReadFile.hasNextLine()) {
String input = ReadFile.nextLine();
try {
// try and parse a number from the input. Removes trailing `°`
arrayInts.add(Integer.parseInt(input.replaceAll("°","")));
} catch (NumberFormatException nfe){
System.err.println("'" + input + "' is not a number!");
}
}
You can add your own handling to the case where the input is not an actual number.
For a more lenient parsing process, you might consider using a regular expression.
Note: The following code is using Java 7 features (try-with-resources and diamond operator) to simplify the code while illustrating good coding practices (closing the Scanner). It also uses common naming convention of variables starting with lower-case, but you may of course use any convention you want).
This code is using an inline string instead of a file for two reasons: It shows that data being processed, and it can run as-is for testing.
public static void main(String[] args) {
String testdata = "55°\r\n" +
"bad line with no number\r\n" +
"Two numbers: 123 $78\r\n";
ArrayList<Integer> arrayInt = new ArrayList<>();
try (Scanner readFile = new Scanner(testdata)) {
Pattern digitsPattern = Pattern.compile("(\\d+)");
while (readFile.hasNextLine()) {
Matcher m = digitsPattern.matcher(readFile.nextLine());
while (m.find())
arrayInt.add(Integer.valueOf(m.group(1)));
}
}
System.out.println(arrayInt);
}
This will print:
[55, 123, 78]
You would have to create a new instance of an ArrayList typed with the Integer wrapper class and give it the same size buffer as the String list:
List<Integer> myList = new ArrayList<>(ArrayString.size());
And then iterate through Arraystring assigning the values over from one to the other by using a parsing method in the wrapper class
for (int i = 0; i < ArrayString.size(); i++) {
myList.add(Integer.parseInt(ArrayString.get(i)));
}
Below is how i count the number of lines in a text file. Just wondering is there any other methods of doing this?
while(inputFile.hasNext()) {
a++;
inputFile.nextLine();
}
inputFile.close();
I'm trying to input data into an array, i don't want to read the text file twice.
any help/suggestions is appreciated.
thanks
If you are using java 7 or higher version you can directly read all the lines to a List using readAllLines method. That would be easy
readAllLines
List<String> lines = Files.readAllLines(Paths.get(fileName), Charset.defaultCharset());
Then the size of the list will return you number of lines in the file
int noOfLines = lines.size();
If you are using Java 8 you can use streams :
long count = Files.lines(Paths.get(filename)).count();
This will have good performances and is really expressive.
The downside (compared to Thusitha Thilina Dayaratn answer) is that you only have the line count.
If you also want to have the lines in a List, you can do (still using Java 8 streams) :
// First, read the lines
List<String> lines = Files.lines(Paths.get(filename)).collect(Collectors.toList());
// Then get the line count
long count = lines.size();
If you just want to add the data to an array, then I append the new values to an array. If the amount of data you are reading isn't large and you don't need to do it often that should be fine. I use something like this, as given in this answer: Reading a plain text file in Java
BufferedReader fileReader = new BufferedReader(new FileReader("path/to/file.txt"));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
String everything = sb.toString();
} finally {
br.close();
}
If you are reading in numbers, the strings can be converted to numbers, say for integers intValue = Integer.parseInt(text)
I do not have enough reputation to comment but #superbob answer is almost perfect, indeed you must ensure to pass Charset.defaultCharset() as 2nd parameter like :
Files.lines(file.toPath(), Charset.defaultCharset()).count()
That's because Files.lines used UTF-8 by default and then using as it is on non default UTF-8 system can produce java.nio.charset.MalformedInputException.
So I have a .txt file with only this as the contents:
pizza 4
bowling 2
sleepover 1
What I'm trying to do is, for example in the first line, ignore the "pizza" part but save the 4 as an integer.
Here is the little bit of code I have so far.
public static void addToNumber() {
PrintWriter writer;
Int pizzaVotes, bowlingVotes, sleepOverVotes;
try {
writer = new PrintWriter(new FileWriter("TotalValue.txt"));
}
catch (IOException error) {
return;
}
// something like if (stringFound)
// ignore it, skip to after the space, then put the number
// into a variable of type int
// for the first line the int could be called pizzaVotes
// pizzaVotes++;
// then replace the number 4 in the txt file with pizzaVote's value
// which is now 5.
// writer.print(pizzaVotes); but this just overwrites the whole file.
// All this will also be done for the other two lines, with bowlingVotes
// and sleepoverVotes.
writer.close();
} // end of method
I am a beginner. As you can see my actual, functioning code is very short and I don't know to proceed. If anyone would be so kind as to point me in the right direction, even if you just give me a link to a site, it would be extremely helpful...
EDIT: I stupidly thought PrintWriter could read a file
It's pretty simple actually. All you need is a Scanner, and it's function nextInt()
// The name of the file which we will read from
String filename = "TotalValue.txt";
// Prepare to read from the file, using a Scanner object
File file = new File(filename);
Scanner in = new Scanner(file);
int value = 0;
while(in.hasNextLine()){
in.next();
value = in.nextInt();
//Do something with the value here, maybe store it into an ArrayList.
}
I have not tested this code, but it should work, but the value in the while loop is going to be the current value of the current line.
I don't fully understand your question, so comment if you want some clearer advice
Here is a common pattern you'll use in Java:
Scanner sc=new Scanner(new File(.....));
while(sc.hasNextLine(){
String[] line=sc.nextLine().split("\\s");//split the string up by writespace
//....parse tokens
}
// now do something
In your case, it seems like you want to do something like:
Scanner sc=new Scanner(new File(.....));
FrequencyCloud<String> votesPerActivity=new FrequencyCloud<String>()
while(sc.hasNextLine(){
String[] line=sc.nextLine().split("\\s");//split the string up by writespace
//if you know the second token is a number, 1st is a category you can do
String activity=line[0];
int votes=Integer.parseInt(line[1]);
while(votes>0){
votesPerActivity.incremendCloud(activity);//no function in the FrequencyCloud for mass insert, yet
votes--;
}
}
///...do whatever you wanted to do,
//votesPerActivity.getCount(activity) gets the # of votes for the activity
/// for(String activity:votesPerActivity.keySet()) may be a useful line too
FrequencyCloud: http://jdmaguire.ca/Code/JDMUtil/FrequencyCloud.java
String num = input.replaceAll("[^0-9]", " ").trim();
For sake of diversity this uses regular expressions.