Why did I get an "ArrayIndexOutOfBoundsException"? - java

I'm pretty new to programming and working on an assignment for class. Now, I'm not asking for anyone to write my code for me but I'm stuck with a runtime error. In the assignment we need to read a file, use the first line, "15", to initialize the size of an array, and proceed to fill the array with the information from each line.
edit: I didn't want to post all of the code because I thought it would look too long but because of the downvotes for being vague, here it goes.
File:
15
produce,3554,broccoli,5.99,1
produce,3554,broccoli,5.99,1
produce,3555,carrots,2.23,0.25
produce,3555,carrots,2.23,0.25
produce,3555,carrots,2.23,0.25
cleaning,2345,windex,5.99,1 unit
cleaning,2345,windex,5.99,1 unit
cleaning,2345,windex,5.99,1 unit
cleaning,2345,windex,5.99,1 unit
cleaning,2346,toilet paper,12.99,4 rolls
cleaning,2346,toilet paper,12.99,4 rolls
cleaning,2335,windex,2.25,1 mini sprayer
cleaning,1342,wipes,3.99,10 units
cleaning,1342,wipes,3.99,10 units
produce,3546,lettuce,2.99,0.5
My Error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 15
at Inventory.readFile(Inventory.java:45)
at Inventory.<init>(Inventory.java:12)
at Supermarket.main(Supermarket.java:3)
Class with the Line 45 in Question (line 45 is commented, scroll to the right)"
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class Inventory{
Product[] list;
String[] invData;
private int i = 0;
public int count;
public Inventory (String f){
readFile(f);
}
public int indexOfProduct(int code){
for(i=0; i<list.length; i++){
if (list[i] != null)
if (list[i].getCode() == code)
return i;
}
return -1;
}
public Product delete(int pos){
Product temp = new Product();
temp = list[pos];
list[pos] = null;
return temp;
}
public void readFile(String fileName){
try{
File invList = new File (fileName);
Scanner s = new Scanner(invList);
int itemCount = s.nextInt();
list = new Product[itemCount];
count = itemCount;
while (s.hasNext()){
String line = s.nextLine();
invData = line.split(",");
if (invData[0].equals("produce")){
list[i] = new Produce(invData[1], invData[2], invData[3], invData[4]); // This is Line 45, Where the error occurs
} else if(invData[0].equals("cleaning")){
list[i] = new Cleaning(invData[1], invData[2], invData[3], invData[4]);
}
i++;
}//end of while loop
} catch (FileNotFoundException Abra) {
String error = Abra.getMessage();
System.out.println(error);
}
} // end of method
public Product findCode(int c){
for(int i=0; i<list.length;i++)
if(list[1].getCode() == c)
return list[i];
return null;
}//end of method
}//end of class
Why did I get an "ArrayIndexOutOfBoundsException"? I hope someone can point out the flaw in my logic so I don't repeat it again.

Your issue is clearly with the use of i, as that is the only variable index on that line, and the out of range index is "15", which is just past the end of your 15-item array. So, couple of issues, all surrounding the use of i:
As nhellwig mentioned, be sure that i is actually initialized to 0 before calling this function.
Additionally, you're putting a lot of faith in the consistency of the item number in the file and the actual number of items. You should either produce a warning and stop trying to store items in the array if i >= itemCount, or use a container like an ArrayList that can grow to accommodate new items instead of a fixed size array.
Edit: Also, I should point out that you increment i whether you read an item or not, which means even blank lines will increment i, causing gaps in your list or array overruns. Since itemCount is the number if items, you should stick to that and only increment i if you read an actual item.
In that same spirit, you should verify that invData.length == 5 after you call split(), because a misplaced comma, etc. in your file may also end up with an OOB error. Granted, for your project, it's probably OK to make assumptions about the number of elements in a line that starts with "produce" or "cleaning", but in general it's important to be cautious with data coming from a user-created file.

I found the answer to be that I needed an "s.nextLine();"
Because I used "s.nextInt();" the pointer was just hangin around at the end of "15" in my file. Then, when the first line in the While loop "String line = s.nextLine();" executed the pointer moved from the end of 15 to before the p in produce in the 2nd line of the list file.
The working method looks like this:
public void readFile(String fileName){
try{
File invList = new File (fileName);
Scanner s = new Scanner(invList);
int itemCount = s.nextInt();
s.nextLine(); // This is the new line that made it work
list = new Product[itemCount];
count = itemCount;
while (s.hasNext()){
String line = s.nextLine(); //moves file pointer over one
invData = line.split(",");
if (invData[0].equals("produce")){
list[i] = new Produce(invData[1], invData[2], invData[3], invData[4]);
} else if(invData[0].equals("cleaning")){
list[i] = new Cleaning(invData[1], invData[2], invData[3], invData[4]);
}
i++;
}//end of while loop
} catch (FileNotFoundException Abra) {
String error = Abra.getMessage();
System.out.println(error);
}
} // end of method

How many times do you call readFile? You should have i = 0; at the beginning of the function.

"i" should not be a global value but should be a method local variable, initialized to zero.

Related

Java Reading Strings to a 2D Boolean Array

I am trying to read a txt file which consists of # and spaces to a 2D boolean array, so that technically a # represents true and a space represents false.
With the help of similar posts i got together a code, although they were reading integers to an array.
My code is:
public static void main(String[] args) {
String x;
String y;
Scanner fileName = null;
try {
fileName = new Scanner(new File("C:/Users/USER/Desktop/hashtag.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
x = fileName.nextLine();
y = fileName.nextLine();
boolean[][] cells = new boolean[x][y];
String finalX = fileName.nextLine();
String finalY = fileName.nextLine();
cells[finalX][finalY] = true;
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
if (cells[i][j])
System.out.print("#");
else
System.out.print(" ");
}
System.out.println();
}
}
In my code where I have written boolean[][] cells = new boolean[x][y];
It says the [x] and [y] requires an int, but found a string. The same issue is for cells[finalX][finalY] = true;
I tried parsing i.e. Integer.parseInt(x) however this gets me an error:
Exception in thread "main" java.lang.NumberFormatException: For input string: "#####################"
At what point is my issue? If I parse to an Int, then it can't read the # correct?
I think this would solve it:
1- read each line of file until the end of it to get the number of cells rows which is n then take length of any String line to get number of columns which is m.
2- create boolean array cells[n][m].
3- read file line by line and put each line in String variable and iterate over the string variable characters if character is # put true in cells array otherwise put false.
String line="";
int n=0;
while(fileName.hasNextLine()){
line = fileName.nextLine();
n++;
}
int m = line.length();
boolean[][] cells = new boolean[n][m];
// initialize Scanner to read file again
Scanner in = new Scanner(new File("C:/Users/USER/Desktop/hashtag.txt"));
int i=0;
while(in.hasNextLine()){
line = in.nextLine();
for(int j=0; j < line.length(); j++){
char c = line.charAt(j);
if(c == '#'){
cells[i][j] = true;
}
else{
cells[i][j] = false;
}
}
i++;
}
You have many mistakes in code and this approach is definitely wrong, you don't even save values that you read from file inside array. Also this code is simply not how you do it, for reading files where you don't know length of file you want to use Lists where you don't need to specify number of elements that list will take(its possible to do get semi-working solution with arrays but there is no point of learning something that is simply wrong). Before even trying to work with files you should learn more basic things, you don't even initialize your arrays properly, you use string for size and index which is causing those issues you mentioned, another beginner mistake is trying to parse non-integer string to int(you are trying to convert ############ to int which is impossible, you can only use this if you know that string is an integer like 1 or 5 or 1000).
So my answer to your question is to just go slowly and learn basics then add new stuff step by step instead just rushing with it.
It says the [x] and [y] requires an int, but found a string. The same
issue is for cells[finalX][finalY] = true;
I tried parsing i.e. Integer.parseInt(x) however this gets me an
error: Exception in thread "main" java.lang.NumberFormatException: For
input string: "#####################"
One approach you could do is first read the entire file.
Example:
List<String> tempList = new ArrayList<>();
while (fileName.hasNextLine()) {
String line = fileName.nextLine();
tempList.add(line);
}
then you can do this:
boolean[][] cells = new boolean[tempList.size()][tempList.get(0).length()];
note - this solution assumes the length() of each line is the same and the columns of each line is the same.
Also, why do you need to perform this outside the loop?
cells[finalX][finalY] = true;
you should remove that line and let the loop do all the work to determine what's # or ' '. Also, your if condition doesn't seem to be doing the correct operation. Consider implementing this approach and then go on from there.

Java Scanner not working as expected

I am trying to read a file into my java program where the first row in the txt file is an int and everything after is a long. The issue that I am having is every single line of code in the while loop is calling s.nextint() and s.nextLong() (at least when I put a watch on them in Eclipse). I want them only to increment through the text file where I call them.
Firstly, what am I doing wrong because it was my understanding they should only increment when called and not on every line of code, and is there a better way to do this? I was thinking if need be I could just load them all in as a single type to an array and cast later, but this wouldn't be what I consider reasonable. I feel this should be fairly simple but I am overlooking something.
Also lets say there are 10 numbers in the text file and go 1-10. I understand that it is a waste to save a small number as an int but just go with it.
public static long[] readfile()
{
int row = 1;
Scanner s = null;
long[] nums = null;
try {
s = new Scanner(new BufferedReader( new FileReader("text.txt")));
while (s.hasNext()) {
if(row == 1){
nums = new long[s.nextInt()];
row++;
}
else {
nums[row - 2] = s.nextLong();
row++;
}
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if (s != null) {
s.close();
}
}
return nums;
}
I'd prefer something like this:
do
{
if(row == 1){
nums = new long[s.nextInt()];
row++;
}
else
{
nums[row] = s.nextLong();
row++;
}
}while(s.hasNextLong());
I didn't try to compile or debug it; holler if you need further help. (It assumes there will be an integer atop the file, as you said would be the case. You should probably add code to guard against that not happening.)
You're code is throwing an ArrayIndexOutOfBoundsException. You're trying to use row for two purposes which throws off your array indexing. By the time we get to the else block, row is equal to 2 and you're trying to apply row to an array from 0 - 9 (10 longs for example).
You should trying initializing your array after checking hasNextInt() then get your long numbers after checking hasNextLong()
Code Sample (text.txt has 10 numbers [1234567890]):
public static void main(String[] args) throws Exception {
long[] longs = readfile();
if (longs != null) {
for (long l : longs) {
System.out.println(l);
}
}
}
public static long[] readfile() {
int row = 0;
Scanner s = null;
long[] nums = null;
try {
s = new Scanner(new BufferedReader(new FileReader("text.txt")));
if (s.hasNextInt()) {
nums = new long[s.nextInt()];
}
while (s.hasNextLong()) {
nums[row] = s.nextLong();
row++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (s != null) {
s.close();
}
}
return nums;
}
Results:
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
I've generally found that Scanners behave oddly when attempting to read multiple types. I'd create a separate Scanner for each type that you'll be reading.
It seems that the issue i stated was having something to do with an eclipse error. If i just run the code or set a breakpoint after the readfile in the main my code works as expected, but when I stepped through values weren't being assigned right by eclipse i'm guessing. Interesting issue. I would like to see exactly what was causing it. Seems very unlikely but isn't that coding? nothing goes as expected.

Getting Objects From A Text File

I have a text file like this;
7-Georgia
1-Andrew
6-John
8-Luke
9-Erica
3-Kim
2-Jude
5-Phil
4-Leo
The first column is id and second is name. How can I get these id's and names? So far I wrote this;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
public class Main {
#SuppressWarnings("resource")
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
#SuppressWarnings("unused")
Scanner fromFile = new Scanner(new File("id_name.txt"));
fromFile.useDelimiter("-");
while(fromFile.hasNext()){
String temp = fromFile.next();
System.out.println(temp);
}
while(fromFile.hasNext()){
String temp= fromFile.next();
int[] fileID;
fileID= new int[9];
for(int i=0; i<9; i++){
fileID[i]= Integer.parseInt(temp);
}
System.out.println(fileID);
}
}
}
But this doesn't get the id's. I'm not sure how to fix this, I'd be grateful if you help me.
You have two while loops in your code. Typically one while loop will go through every item until the condition is no longer true. I think you need to rework this to have a better "flow of control" which might mean using only one while loop (with sections to grab the number and then the name.
I imagine that you are looking for results from the second while loop, but by the time you get to it, the first while loop will have exhausted all of your data.
Finally, printing an array will print out the array reference identifier. If you want to actually print the contents of the array, you need a loop over the elements within the array, and you need to print out each array element explicitly.
As an alternative to the array printing technique above (which you should master), you can also use the Arrays.toString(<insert array here>) method call. However, in many cases it will give you a format that is not desired. That's why you need to know the above technique too.
Also, you have one hidden issue. You (in the second while loop) make the assumption that there are only nine inputs. Pay close attention to what you are writing. Every time you have to reach for a number, consider whether it is a "magic" number. Magic numbers are numbers that are in your code with no explanation or reason why they exist. They are indicators of errors in the code made by assumptions that probably won't last the test of time.
For example, you are using the number 9 because you have seen the input file. The next input file will probably not have nine entries in it, and your program will probably not work right if you gave it an input with eight entries, or an input with ten entries. Perhaps you should rewrite the loop to remove the magic number, by making the logic process while there is still (some) input.
Try this on for size
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
try {
Scanner fromFile = new Scanner(new File("id_name.txt"));
} catch (FileNotFoundException e) {
System.err.println("File not found");
}
String[] arr = new String[9];
String[] oth = new String[9];
int i = 0;
while(fromFile.hasNextLine()) {
String temp = fromFile.nextLine();
oth[i] = temp.substring(0,1);
arr[i] = temp.substring(2);
i++;
}
int[] fileID;
fileID = new int[9];
for(int j = 0; j < 9; j++) {
fileID[j] = Integer.parseInt(oth[j]);
}
}
}
this should go through and retrieve the numbers(.substring(0,1)) and then the names(.substring(2)), and then converting the numbers to int values.
Try the following:
File file=new File("id_name.txt");
int[] fileID;
fileID= new int[9];
String[] result = file.nextLine().split("-");
for (int x = 0; x < result.length; x++){
if (Character.isDigit(result[x])) { // use the isDigit method to get the ids
System.out.println("this is an id");
fileID[i]= Integer.parseInt(result[x]);
}
Actually my friend, there are several mistakes here.
1) When the first while loop completes, it leaves fromfile.hasNext() as false Hence the second loop never starts.
>> To fix this, You need to put it all in one while loop.
2) fileID is an array. You cannot print it using System.out.println(fileID).
>> You have to tell what kind of output you want. The code will depend on that. For simply printing all the values, you need to make a for loop that prints each value separartely. You should use fileID.length for the no. of times you need to loop it.
3) Basically, fromfile.next() is not the way to do it.
>> You need to use fromfile.nextLine().

Getting InputMismatchException When Reading Text File into Integer Array

I am reading a text file filled with numbers (on individual lines) into an integer array. I thought I wrote the program well but am having issues when I try to run it. Netbeans is telling me "InputMismatchException." I think the problem is located in my second method called readTxtFile specifically the while loop. Any help would be greatly appreciated.
package arrayspa;
import java.util.Scanner;
public class ArraysPA {
/**
* Using the enrollment.txt file, count and display the number of full
* sections and the percentage of the sections that are full. A section is
* full if it contains 36 students.
*/
public static void main(String[] args) throws Exception
{
//an array to hold total # of students in each section
int[] numStud = new int[100];
int count; //number of elements actually used
int fullSections; //number of full sections (36 enrolled students)
int percent; //percentage of sections that are full
//read data into numStud[] from txt file
count = readTxtFile(numStud);
//print the array on the screen
System.out.println("The original file:");
displayLines(numStud,count);
//calculate number of sections that are full and display number
fullSections = calcFullSections(numStud, count);
System.out.println("There are "+fullSections+ "full sections.");
//display percentage of sections that are full
percent = fullSections/count;
System.out.println("The percentage of sections that are full is "
+percent);
} //end main()
/**
* This methods read data from enrollment.txt (located in project folder)
* line by line into an integer array. It then uses an if statement to
* display the total number of full sections (a section is considered full
* if there are 36 students enrolled).
*/
public static int readTxtFile(int[] numStud) throws Exception
{
int i=0; //number of elements in array initialized to zero
//Create File class object linked to enrollment.txt
java.io.File enrollment = new java.io.File("enrollment.txt");
//Create a Scanner named infile to read input stream from file
Scanner infile = new Scanner(enrollment);
/**Create while loop to read lines of text into array. It uses the
*Scanner class boolean function hasNextLine() to see if there is
*another line in the file.
*/
while (infile.hasNextLine())
{
//read a line and put it in an array element
numStud[i] = infile.nextInt();
i ++; //increment the number of array elements
} //end while
infile.close();
return i; //returns number of items used in the array
} //end readTxtFile(int[] numStud
public static void displayLines(int[] lines, int count)
{
int i; //loop counter
// iterate the elements actually used
for (i=0; i < count; i++)
System.out.println(lines[i]);
} //end displayLines()
public static int calcFullSections(int[] numStud, int count)
{
int fullSections=0; //number of full sections
int i; //loop counter
for (i=0; i < count; i++)
if (numStud[i]==36)
{
fullSections = fullSections + 1;
}
return fullSections;
} //end calcFullSections()
}
An InputMismatchException is thrown when input does not match the type of variable you are writing to. I have tested your code and it seemed to work fine unless the file "enrollment.txt" has a blank line or spaces. I have tested adding a blank line to the end of the file and running it, and I received a NoSuchElementException, so the problem is probably a blank line or non-integer somewhere in your file. To fix this, you can either remove any blank lines/non-integers in your file, or, preferably, you can modify your readTxtFile() method to ignore blank lines by catching a NoSuchElementException, like so:
public static int readTxtFile(int[] numStud) throws Exception
{
int i=0; //number of elements in array initialized to zero
//Create File class object linked to enrollment.txt
java.io.File enrollment = new java.io.File("enrollment.txt");
//Create a Scanner named infile to read input stream from file
Scanner infile = new Scanner(enrollment);
/**Create while loop to read lines of text into array. It uses the
*Scanner class boolean function hasNextLine() to see if there is
*another line in the file.
*/
while (infile.hasNextLine())
{
// Add this try/catch block to prevent reading blank line
try {
numStud[i] = infile.nextInt();
i ++;
} catch (NoSuchElementException e) {
}
} //end while
infile.close();
return i; //returns number of items used in the array
} //end readTxtFile(int[] numStud
As you can see, I have added a try/catch block into your readTxtFile() void that catches a NoSuchElementException, which includes InputMismatchException, preventing an attempt to add in any non-integers. I hope this solves your problem!

How a write a method that iterates through a text file and adds all elements to an arrayList using the Object's equals method

I am trying to create Line objects and add them to an array list. The problem I am having is excluding any lines that are similar to each other. I have already created an equals method that compares two lines to determine if they are equal. I am having trouble using the while loop. I do not have an error message. It compiles just fine. It just will not read from the text file. I am stuck and do not know where else to go from here.
public void read( File fileName ) throws Exception
{
reader = new Scanner(fileName);
//---------------------
//Have to read the first number before starting the loop
int numLines = reader.nextInt();
lines = new ArrayList <Line> (numLines);
//This loop adds a new Line object to the lines array for every line in the file read.
while( reader.hasNext() ) {
for( int i = 0; i < numLines; i++ ) {
int x = reader.nextInt();
int y = reader.nextInt();
Point beg = new Point(x,y);
x = reader.nextInt();
y = reader.nextInt();
Point end = new Point(x,y);
String color = reader.next();
Line l = new Line( beg, end, color );
if (l.equals(lines.get(i)))
break;
else
lines.add(i, l);
}
}
//Print the action to the console
System.out.println( "reading text file: " + fileName );
reader.close();
}
lines is an ArrayList. You cannot access an element i of an ArrayList by going lines(i) as you do in the code; you need to do lines.get(i).
the first exception is already explained by others so I'll explain the other one:
Void methods cannot return a value
You created the following method:
public void read( File fileName ) throws Exception
in your while loop you do this:
if (this.lines(i).equals(lines(i)))
return null;
else
lines.add(i, l);
You return null, while you can use return in a while loop, you cannot do it if you declare your method void. You should use break instead.
The exception is clear, you can't return anything in a void function.
So simply modify your code to:
Line l = new Line( beg, end, color );
//if not equals, add it
if (!this.lines(i).equals(lines.get(i))){
//TODO: add to you collection
}
I hope it helps
You should not "return null" on a method which has no return value (void). You can just use "return" instead. However I assume what you want is "continue" in stead. Also consider using HashSet in stead of an arraylist, then you don't need to check for equality anymore since the hashset does not allow duplicates.

Categories