This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 7 years ago.
So this is my text file:
CareFlight101 0 2
PiperCub 2 99
AirAmbulance 2 1
TransWorld122 2 5
Cessna152 3 99
Eastern429 4 10
They are suppose to be aircrafts name followed my arrival time and landing priority.
I am trying to splitting it so that it takes each into account. I am having trouble splitting it though because it it throwing a 'java.lang.ArrayIndexOutOfBoundsException: 1' error
This is what I have so far:
public class TheAircrafts {
public static ArrayList<Plane> planeList;
public static void main(String[] args){
try {
File f = new File("sample_data_p3.txt");
Scanner sc = new Scanner(f);
List<Plane> people = new ArrayList<Plane>();
while(sc.hasNextLine()){
String line = sc.nextLine();
String[] details = line.split("\\s+");
String flightID = details[0];
int arrivalTime = Integer.parseInt(details[1]);
int landingPriority = Integer.parseInt(details[2]);
Plane p = new Plane(flightID, arrivalTime, landingPriority);
planeList.add(p);
}
for(Plane p: planeList){
System.out.println(p.toString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
And in my plane class I have:
public class Plane {
private String flightID;
private int arrivalTime;
private int landingPriority;
private int numRunways;
public Plane(String flightID, int arrivalTime, int landingPriority) {
this.setflightID(flightID);
this.arrivalTime = arrivalTime;
this.landingPriority = landingPriority;
}
followed by get and set and get methods for each of the variables
You get a IndexOutOfBoundsException in this case when there is a line which not more than i elements seperated by a space.
In your case there is a line which has only one word in it. And hence when you try to get the second word which didn't exist you get an Exception.
To avoid getting so, you can check if that line has 3 words or not.
String []details = line.split("\\s+");
if(details.length == 3)
{
//do your setting
}
Related
This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 6 years ago.
Brief description
I am currently writing a massive (For my skill level) java program with my first UI. My goal is to make the program use the UI to save career information to a text file and allow it to read that file into a JTable, these two actions are done through JButtons.
The file uses a # between variables and is in the format:
name#placeOfWork#description#highestSalary#lowestSalary#indexOfDegree#indexOfDegreeLevel and studYears#yearOfMatriculation#
The issue arose when I tried to instantiate a Career constructor (Code below) from the file by splitting the line into the necessary parts, I have no idea how this is giving me an ArrayIndexOutOfBounds exception as it seems to be within the array's boundaries...
The Career's parameterised constructor: (Career)
public final int[] ARR_STUDY_YEARS = { 0, 0, 1, 2, 4, 6, 10 };
public final String ARR_DEGREE[] = { "None", "Commerce", "Science", "Arts", "Computer Sciences", "Education",
"Medicine", "Engineering" },
ARR_DEGREE_LEVEL[] = { "None", "Matriculent", "Undergraduate", "Associate", "Bachelor", "Masters",
"Doctorate" };
// Variables
private String name, setting, description, degree, degreeLevel, qualification;;
private int highestSalary, lowestSalary, avgSalary, sYears, matricYear;
public Career(String name, String setting, String description, int highestSalary, int lowestSalary,
int degreeNo, int degreeLevelNo, int matricYear){
this.name = name;
this.setting = setting;
this.description = description;
this.highestSalary = highestSalary;
this.lowestSalary = lowestSalary;
sYears = ARR_STUDY_YEARS[degreeLevelNo];
degreeLevel = ARR_DEGREE_LEVEL[degreeLevelNo];
degree = ARR_DEGREE[degreeNo];
this.matricYear = matricYear;
}
The Code giving me an error: (CareerUI)
JButton btnDisplay = new JButton("Display");
btnDisplay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ArrayList<Career> careerList = new ArrayList<Career>();
File file = new File("Careers.txt");
try {
Scanner reader = new Scanner(file);
while (reader.hasNextLine()) {
String[] line = reader.nextLine().split("#");
Career career = new Career(line[0], line[1], line[2], Integer.parseInt(line[3]), Integer.parseInt(line[4]),
Integer.parseInt(line[5]), Integer.parseInt(line[6]), Integer.parseInt(line[7]));
//^ This constructor is on line 200
careerList.add(career);
}
reader.close();
String[][] cMatrix = new String[careerList.size()][6];
String[] header = { "Name", "Setting", "Description", "Average Salary", "Tertiary Qual. Required",
"Qualification" };
for (int i = 0; i < cMatrix.length; i++) {
for (int j = 0; j < cMatrix[i].length; j++) {
Career c = careerList.get(j);
cMatrix[i] = c.toTableSummary();
}
}
JTable table = new JTable(cMatrix, header);
// table.set
table.setBounds(519, 53, 489, 437);
panel.add(table);
} catch (FileNotFoundException ex) {
System.out.println("There was an error while reading your file");
}
}
});
The File: (Careers.txt)
Chartered Accountant#Office#Balances finances#100000#80000#1#4#2017#
Plumber#House Calls#Fixes Plumbing#50000#10000#0#0#2019#
Doctor#Clinic#Treats illness#150000#50000#6#6#2016#
Architect#Construction Firm#Designs Buildings#80000#50000#6#5#2018#
The Error:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1
at career.CareerUI$3.actionPerformed(CareerUI.java:200)
Update
Just did a test with converting a text file into a multi dimensional array and it worked, the code is below. I might be close to figuring this out.
public class ScanToArray {
public static void main(String[] args) {
try {
Scanner scFile = new Scanner(new File("test.txt"));
int x = 0;
String[][] multi = new String[5][5];
while (scFile.hasNextLine()){
String[] next = scFile.nextLine().split("#");
multi[x][0] = next[0];
multi[x][1] = next[1];
multi[x][2] = next[2];
multi[x][3] = next[3];
multi[x][4] = next[4];
x++;
}
scFile.close();
int ln = 0;
for (int i = 0; i < multi.length; i++) {
for (int j = 0; j < multi[i].length; j++) {
if(i>ln){
System.out.println();
ln = i;
}
System.out.print("|" +multi[i][j] +"|");
}
}
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "Error: File not found");
}
}
}
The File used (test.txt)
0.0#0.1#0.2#0.3#0.4
1.0#1.1#1.2#1.3#1.4
2.0#2.1#2.2#2.3#2.4
3.0#3.1#3.2#3.3#3.4
4.0#4.1#4.2#4.4#4.4
The output:
|0.0||0.1||0.2||0.3||0.4|
|1.0||1.1||1.2||1.3||1.4|
|2.0||2.1||2.2||2.3||2.4|
|3.0||3.1||3.2||3.3||3.4|
|4.0||4.1||4.2||4.4||4.4|
Going to mess around and see if I can convert that to a Jtable and then try to work out where I went wrong initially.
Note: I am not asking what a arrayindexoutofbounds is, I am asking why this particular code is giving me it.
There are few problems with your code:
(1) In the 4th line of your input, there is 7th index (if you split with #), which breaks when you try to get line[7], which will throw ArrayIndexOutOfBoundsException
Buildings#80000#50000#6#5#2017#
(2) You will not be able to parse the 6th element using Integer.parseInt(line[6]) as it throws NumberFormatException
(3) The input data is not right even in the 3rd line, it has more than 7 indexes after split, which does not throw any exceptions (as you are retrieving upto 7 indexes), but ensure that correct data is passed as input.
sYears = ARR_STUDY_YEARS[degreeLevelNo];
degreeLevel = ARR_DEGREE_LEVEL[degreeLevelNo];
You most likely don't want to use the same variable as index to different arrays.
So I am trying to create an object array that from a text file. The objects I am placing in the array are people objects with 4 parameters. 1st name, last name, an ID number and a height. The text file has a certain number of lines and each element is separated by an exclamation mark. I am trying to take each of the 4 elements to create an object and then place that object into an object array. Here is my code up until now. Also because I am new to java, there is not a lot that I know so the code needs to be simple.
import java.io.File;
import java.io.IOException;
import java.util.*;
public class Participants {
public static void main(String[] args) {
String array[] = new String[35];
Object participants[] = new Object[35];
int count = 0;
int counter = -1;
try {
File myFile1 = new File("Participants.txt");
Scanner scan1 = new Scanner(myFile1);
while (scan1.hasNext()) {
counter++;
array[counter] = scan1.next();
}
} catch (IOException ioe) {
System.out.println("The file can not be read");
}
for (int i = 0; i < array.length; i++) {
StringTokenizer st = new StringTokenizer(array[i], "!");
while (st.hasMoreTokens()) {
People person = new People(st.nextToken(), st.nextToken(), st.nextToken(),
st.nextToken());
participants[i] = person;
}
}
}
}
I commented that your code basically looks okay. There are some problems I spotted, and I think you may be running into them. You are probably getting a
Exception in thread "main" java.lang.NullPointerException
at java.util.StringTokenizer.<init>(Unknown Source)
at java.util.StringTokenizer.<init>(Unknown Source)
at Participants.main(Participants.java:22)
because arrays[i] is empty in
StringTokenizer st = new StringTokenizer(array[i], "!");
which is because you allocate 35 entries:
String array[] = new String[35];
and the file contains less lines than that. At least, that's what I'm getting it with this input file:
A!B!C!D
E!F!G!H
I!J!K!L
which is to be expected.
If I change the first line of the input file into
A!B!C
I get
Exception in thread "main" java.util.NoSuchElementException
at java.util.StringTokenizer.nextToken(Unknown Source)
at Text2ObjArray.main(Text2ObjArray.java:28)
which is because you only check once for a token, but then proceed to read four:
while (st.hasMoreTokens()) {
Person person = new Person(st.nextToken(), st.nextToken(), st.nextToken(), st.nextToken());
I'll update with a solution, if it is needed, but here are two suggestions:
1) use an ArrayList instead of an array[]:
2) Check what you parse: make sure there are 4 tokens per line, and deal with the exceptional case that they are not 4.
UPDATE
Basically, there's nothing wrong with your program. You already know "
How to put values from a text file into an object array in java?".
Your program runs just fine if you feed it a file with exactly 35 lines containing at least 3 exclamation marks each. If not, it throws the appropriate exceptions:
a NullPointerException if there are less than 35 lines and
an ArrayIndexOutOfBoundsException if there are more, and
a NoSuchElementException if there are less than 3 exclamation marks on any of the lines.
(Unless, there is a problem is in the People class which is unlikely if it is a POJO).
Your code only needed a few minor changes to make it work for files with other content. I've kept it simple:
import java.io.File;
import java.io.IOException;
import java.util.*;
public class Text2ObjArray {
public static void main(String[] args) {
Person[] participants = loadFile(new File(args.length > 0
? args[0] : "Participants.txt"));
for (Person p : participants)
System.out.println("Participant: " + p);
}
I split off main merely as good practice - see 'top-down' and 'bottom-up'.
To address the NullPointerException and ArrayIndexOutOfBoundsException We'll use an ArrayList instead of an array[] to keep track of the lines we read from the file. The advantage of an ArrayList is that it can grow and shrink, which is useful if you don't know for sure if "Participants.txt" always contains 35 lines.
Also it saves us from replacing our array with a bigger one when it's full. It's a cheap, handy upgrade from an array[], and all that has changed is writing
array.get(i) instead of array[i]
array.set(i,foo) instead of array[i]=foo and
array.add(foo) instead of array[counter++]=foo and
array.size() instead of array.length. It is a dynamic array, so you can insert into any position, remove etc.
private static Person[] loadFile(File file) {
List<String> lines = new ArrayList<>();
try (Scanner scan1 = new Scanner(file)) {
while (scan1.hasNext())
lines.add(scan1.next());
} catch (IOException e) {
System.out.println("File read error: " + e.getMessage());
}
This section is changed only in that it reads up to 4 tokens, dealing with the NoSuchElementException:
Person participants[] = new Person[lines.size()];
for (int i = 0; i < lines.size(); i++) {
StringTokenizer st = new StringTokenizer(lines.get(i), "!");
String[] fields = new String[4];
for (int k = 0; k < fields.length && st.hasMoreTokens(); k++)
fields[k] = st.nextToken();
participants[i++] = new Person(fields[0], fields[1], fields[2], fields[3]);
}
return participants;
}
}
To run it successfully you'll need to replace Person to People or use this Person class:
public class Person {
private String id;
private String lName;
private String fName;
private String height;
public Person(String id, String fName, String lName, String height) {
this.id = id;
this.fName = fName;
this.lName = lName;
this.height = height;
}
public String toString() {
return "Person[" + id + ": " + lName + ", " + fName + ", " + height + "]";
}
}
I hope that this has been helpful.
I am making a program that reads a file of mixed values (int and string), prints only the integer values and keeps a running total of the amount of integer values within the file. Everything is working except for my running total of integer values within a given file and i am very confused on why it keeps printing 0 when i know there are more then 0 integer values within the file.
Here is my code:
package davi0030_a03;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class MyFile {
private String fileName; // name of the file
private int count = 0; // number of valid integers in the file
private final int MAX_SIZE = 10; // the size of the array
private Scanner inputStream = null;
private int[] theArray = new int[MAX_SIZE];
private boolean strangeInt = false;
private int total = 0;
// constructor to set the file name
public MyFile(String theName) { // constructor to set the file name
this.fileName = new String(theName);
// you may or may not want to do other stuffs here
}
public void openFile() {
System.out.println("opening file: " + fileName);
try {
inputStream = new Scanner(new FileInputStream("src/davi0030_a03/"
+ fileName));
} catch (FileNotFoundException e) {
System.out.println("File was not found or could not be opened");
}
}
// log a message on whether two ints in the file add to target
public void findPair(int target) {
openFile();
fileToArray();
findStrangeInt();
findTotal();
}
public void findTotal(){
inputStream.reset();
while(inputStream.hasNext()){
if(inputStream.hasNextInt()){
total +=1;
}
inputStream.next();
}
System.out.println(total);
}
public void findStrangeInt() {
inputStream.reset();
while (inputStream.hasNext()) {
try {
Integer.parseInt(inputStream.next());
} catch (NumberFormatException nfe) {
strangeInt = true;
}
}
if (strangeInt = true) {
System.out.println("File contains an incorrectly written int");
}
}
public void fileToArray() {
inputStream.reset();
while (inputStream.hasNext() && count < MAX_SIZE) {
if (inputStream.hasNextInt()) {
theArray[count] = inputStream.nextInt();
count++;
}
}
}
// print the content of the file
public void printFile() {
openFile();
inputStream.reset();
System.out.println("Printing content of file " + fileName);
while (inputStream.hasNext()) {
try {
int convert = Integer.parseInt(inputStream.next());
System.out.println(convert);
} catch (NumberFormatException nfe) {
System.out.println("xxx");
}
}
}
}
content of file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
a
b
d
EDIT: My solution below most likely solves the logic issue regarding your searching the file. However, I suggest you read some of the other comments the question has gotten. The IO handling here especially needs some improvement.
I believe your issue lies in your while statement. According to java documentation on the Scanner class,here, the method .hasNextInt() is returning based on the next element scanned. I think you are assuming it will return true as long as there are ints in the file. This is not the case. If the first thing the scanner hits is not an int, it is returning false and exiting your while loop. This would explain the returned 0, the value you initialize your variable 'total' to. I would suggest you do something like the following:
while(scanner.hasNext()){
if(scanner.hasNextInt()){
total +=1;
}
scanner.next();
}
I currently have this program read the contents of a text file and calculate the averages and amount of test scores taken and print them out neatly in a small data table. These are the names, amount of quizes taken and average of each student:
James Tiberius Kirk 8 91.63
Buffy Summers 7 83.14
Tom Baker 15 100.00
Malcolm Reynolds 9 84.22
Elizabeth Bennet 9 93.33
John Blutarsky 9 0.00
Dorthy Gale 6 85.83
All of these Students are stored within the Array named Anames[]. I was wondering if it was at all possible to sort these students alphabetically by last name using the code that I have now. When I run the program it gives me the error:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1927)
at text.reader.TextReader.compareLastNames(TextReader.java:117)
at text.reader.TextReader.main(TextReader.java:94)
Here is the code of my main class:
public static void main(String[] args)throws IOException{
Double score=0.0;
int b,j;
String tempfirst = "";
String templast = "";
Student Anames[] = new Student[30];
Student Temp[] = new Student [1];
int Stucount = 0;
Scanner reader = new Scanner(new File("quizScores.txt"));
boolean runProgram = true;
PrintWriter writer = new PrintWriter(new File("scoreReport.txt"));
//prints header for report
System.out.println("Name Number Quizes Quiz Socres");
writer.println("Name Number Quizes Quiz Socres");
//check to see if end of file string
while (!reader.hasNext("-10")){
String name="", first="", last="";
//gets the name from file
while(!reader.hasNextDouble()){
last = reader.next();
while (!reader.hasNextDouble()){
first = first+reader.next()+" ";
}
name=first+last;
}
//creates new student with given name
Student newStudent = new Student(first, last);
Anames[Stucount] = newStudent;
Stucount++;
//gets the quiz scores and makes sure does not averge in the end of file string.
while (reader.hasNextDouble()&& !reader.hasNext("-10")){
newStudent.addQuiz(reader.nextDouble());
}
//Prints out the formated data
System.out.printf("%-30s%4.0f%30.2f \n",newStudent.getName(), newStudent.getQuizNumber(), newStudent.getAverage());
writer.printf("%-30s%4.0f%30.2f",newStudent.getName(), newStudent.getQuizNumber(), newStudent.getAverage());
writer.println();
}
System.out.println("\n");
for (b = 0; b < Stucount; b++){
int INTEGERTEMP = b;
for (j= b+1; j < Stucount; j++){
int INTEGERTEMP2 = j;
if ((compareLastNames(Anames[INTEGERTEMP].getLAST(), Anames[INTEGERTEMP2].getLAST()))>0){
Temp[0] = Anames[b];
Anames[b] = Anames[j];
Anames[j] = Temp[0];
}
}
}
System.out.println("Name Number Quizes Quiz Socres");
for (int i = 0; i < Stucount; i++) {
System.out.printf("%-30s%4.0f%30.2f \n", Anames[i].getName(), Anames[i].getQuizNumber(), Anames[i].getAverage());
}
writer.close();
}
private static int compareLastNames(String a, String b){
int index_a = a.lastIndexOf(" ");
String surname_a = a.substring(index_a);
int index_b = b.lastIndexOf(" ");
String surname_b = b.substring(index_b);
int lastNameCmp = surname_a.compareToIgnoreCase(surname_b);
return lastNameCmp;
}
Here is the Student.java which contains most of the methods used:
public Student (String inName, String inLast){
studentName=inName;
studentLast = inLast;
quizAverage = 0;
quizScore=0;
numberQuizes=0;
}
public void addQuiz(double inQuiz){
quizScore += inQuiz;
numberQuizes++;
}
public double getAverage(){
quizAverage = quizScore/numberQuizes;
return quizAverage;
}
public String getName(){
return studentName+studentLast;
}
public double getQuizNumber(){
return numberQuizes;
}
public String getLAST(){
return studentLast;
}
You can use java.util.Arrays.sort(Student [] arr, Comparator<Student> comp) instead of your own compare code. In single line you can achieve it like this:
Student arr[];//considering this array you will populate
Arrays.sort(arr,new java.util.Comparator<Student>(){
public int compare(Student o1, Student o2) {
return o1.studentLast.compareTo(o2.studentLast);
}
});
//then the arr will be sorted with studentLast name
Let's work our way back from your exception to figure out where the problem is. First, it tells us we've got a StringIndexOutOfBoundsException on line 117; that is, the line (it might actually be the surname_b line, you've removed code from the class that means I can't match up the lines properly)
String surname_a = a.substring(index_a);
You'll notice the message from the exception helpfully tells us that the index used was -1. Let's take a look at why a.lastIndexOf(" "); would return -1. We see in the documentation for String that it returns -1 when the character does not occur in the String.
Now, let's work another step back in the Exception's stack trace to figure out why there's no space in that String. The Exception tells us to check line 94, where we see
if ((compareLastNames(Anames[INTEGERTEMP].getLAST(), Anames[INTEGERTEMP2].getLAST()))>0){
So, what's going on here? We're passing in the last names (and just the last names) from each of the students into our comparison function. The last names, for the most part, have no spaces in them.
So, how do we fix this? Well, you'll have to change your function to only take substrings of the surname if there actually is a space in them, i.e. if the index returned isn't -1.
Once you've got the comparison function done, I recommend looking at how to write an Object that implements the Comparable interface. This will allow you to use library sorting functions, which will be faster and less buggy than your own sorting functions (most likely!).
I have been working on this sort of ATM (With a maximum of 50 customers), where I read a .txt file, and then create multiple instances, store them in an array, so that other classes can call on them.
When I read the file, only the last customer's information are inputted correctly - I can't ever get the first few customers to have their output correct.
There are multiple methods for each 'Set', just in case the field says 'none', so that I can leave it as a
Double.NaN or null, for example.
I have researched on a few websites, and there wasn't very much on storing instances in arrays, although on one website, it said that I should declare it just like a normal array.
private static String firstname = "";
private static String lastname = "";
private static int sin = 0;
private static int year = 0;
private static int month = 0;
private static int day = 0;
private static double sbalance = 0.0;
private static double cbalance = 0.0;
private static double cardbal = 0.0;
private static boolean confirm = false;
public int customernumber;
public static customer [] customerarray = new customer [50];
public static void readfile(){
String sb = "";
String cb = "";
String ca = "";
int counter = 0;
String thisLine;
try {
BufferedReader br = new BufferedReader(new FileReader("bankinfo.txt"));
while ((thisLine = br.readLine()) != null) {
customerarray[counter].setLastName(thisLine);
System.out.print (customerarray[counter].getLastName());
customerarray[counter].setFirstName(br.readLine());
System.out.print (customerarray[counter].getFirstName());
customerarray[counter].setSin(Integer.parseInt(br.readLine()));
System.out.print (customerarray[counter].getSin());
customerarray[counter].setYear(Integer.parseInt(br.readLine()));
System.out.print (customerarray[counter].getYear());
customerarray[counter].setMonth(Integer.parseInt(br.readLine()));
System.out.print (customerarray[counter].getMonth());
customerarray[counter].setDay(Integer.parseInt(br.readLine()));
System.out.print (customerarray[counter].getDay());
sb = br.readLine();
if (sb.equals("none")){
customerarray[counter].setSBalance("none") ;
System.out.print (customerarray[counter].getSBalance());
}
else {
customerarray[counter].setSBalance(Double.parseDouble(sb));
System.out.print (customerarray[counter].getSBalance());
}
cb = br.readLine();
if (cb.equals ("none")){
customerarray[counter].setCBalance ("none");
}
else if (cb != "none"){
customerarray[counter].setCBalance(Double.parseDouble(cb));
}
else{
System.out.print ("error CBalance");
}
ca = br.readLine();
if (ca.equals("none")){
customerarray[counter].setSBalance("none") ;
}
else {
customerarray[counter].setCardbal(Double.parseDouble(ca));
}
counter = counter + 1;
}
br.close();
}
catch (IOException e) {
System.err.println("Error: " + e);
}
}
The text file is fairly simple- it is composed of 9 fields for each customer.
If they do not have a certain account, it is listed as 'none', and when the reader reads them, it uses a variant method with a String input, and sets the double = Double.NaN();
The following is an example of the text file.
Each customer has 9 fields.
Tam
Christian
984635684
1996
6
12
none
10233.52
none
Yang
Wesley
324917400
1996
8
1
3233.36
none
none
Lin
Sophia
1984
1985
5
6
912.12
58.96
95.63
I don't see where you're instantiating each individual location of your customer[] with actual customer objects.
Add this line before after the start of your while loop:
customerarray[counter] = new customer();
When creating an object array, all of the elements in it default to null. You can't dereference null, so you're running into issues.