I've got an issue getting a method to read a file, then converting it to an integer. Here is a brief explanation of the program. It is essentially a car dealership inventory that keeps track of the vehicles in the lot by keeping them written down in a text file. When the program starts it will need to read the file and put all the current cars into an array so they can be displayed. Then the rest of the program will do other things like remove cars and add news ones etc. The part I am at is when the program first starts it needs to read the file, but I can't seem to get it to work.
The text file consists of 6 lines in total; 4 numbers first then 2 words respectively. I want the method to read the first four lines and convert those into integers and store them in a temporary array. Then after that it will read the next two lines and store those in a temporary array as well. Afterwards I take all these stored values and send them to a constructor. The constructor is then stored in an Arraylist and the Arraylist can be accessed anytime. In the output it does all of this just fine. But it wants to run through the method a second time despite barriers in place to prevent this.
Here is the code. Its a class and not the main program. I will try to explain the program as best I can inside the code.
public class Vehicle {
//All the different private variables for the constructors and methods
private int intholder[], year, type, kilometres, price, loop;
private String make, model, myline, holder[];
//The Arraylist that the different vehicle objects will be stored
ArrayList<Vehicle> allCars = new ArrayList<Vehicle>();
//The Default constructor
public Vehicle(){
make = "Vehicle Make";
model = "Vehicle Model";
type = 0;
year = 0;
kilometres = 0;
price = 0;
}
//The constructor that has information sent to it
public Vehicle(int _type, int _year, int _kilometres, int _price, String _make, String _model){
make = _make;
model = _model;
type = _type;
year = _year;
kilometres = _kilometres;
price = _price;
}
//Text file information
/*
* CAR TYPE CODE:
* 1 - Sedan
* 2 - Truck
* 3 - Crossover
* 4 - SUV
* 5 - Sports
*
* There is a total of 6 lines for each car and are as follows
* 1 - int Type integer
* 2 - int Year
* 3 - int Kilometres
* 4 - int Asking price
* 5 - String Make
* 6 - String Model
*/
//The method in question. It reads through the file, converts the integers and stores them,
//stores the strings, and sends all the information to the constructor
public void readCars()throws IOException{
BufferedReader readFile = new BufferedReader(new FileReader("C:/Users/David/Desktop/FinalProject/Carlot.txt"));
//Setting the length of the temporary arrays
holder = new String[2];
intholder = new int[4];
//The main loop in the method.
do{
//Read the first 4 lines of the file and convert them to integers.
//The try catch shouldn't have to be there because the first 4 lines
//of the file are all numbers, but I put it in there to see when it was messing up.
for(int i = 0; i < 4; i++){
myline = readFile.readLine();
try{
intholder[i] = Integer.parseInt(myline);
}
catch(NumberFormatException e){
System.out.println(e);
}
//Had this in here to see how many lines down the file it would go before messing up.
System.out.println(myline);
}
//Loop to store the Strings
for(int i = 0; i < 2; i++){
myline = readFile.readLine();
holder[i] = myline;
System.out.println(myline);
}
//Sends all the data to the constructor
Vehicle V = new Vehicle(intholder[0], intholder[1], intholder[2], intholder[3], holder[0], holder[1]);
//Several if statements to determine which subclass of vehicle it is.
if(intholder[0]==1){
Sedan S = new Sedan();
allCars.add(S);
}
else if(intholder[0]==2){
Truck T = new Truck();
allCars.add(T);
}
else if(intholder[0]==3){
Crossover C = new Crossover();
allCars.add(C);
}
else if(intholder[0]==4){
SUV U = new SUV();
allCars.add(U);
}
else if(intholder[0]==5){
Sports P = new Sports();
allCars.add(P);
}
//Only break the loop if the myline equals null
}while(myline != null);
//if the loop breaks, close the file
readFile.close();
}
Now I think I know where it is going wrong. At the end of the do/while, it checks if "myline" is null. And because the last time it read the file it was still a String the loop continues. The last time it goes through the loop, everything is null so trying to convert the integer is impossible so I get errors. But I have no idea how to get it to read the file at the end of the loop without going to the next line. Here is what the text file looks like.
1
2007
150250
5000
Toyota
Corolla
2
2005
240400
4500
Chevorlet
Silverado
I can't have it read at the end of the loop because if it does and there are still more cars after the one I just did, It goes into the next line when the loop restarts everything is thrown off.
Any help is appreciated, Thanks!
Use a labeled break statement in your for loops to simply exit out of the main do while loop when myline becomes null. The way other objects are being instantiated within the loop doesn't leave much room for easy refactoring hence the use of a labeled break makes sense here.
outerloop:
do {
for (int i = 0; i < 4; i++) {
if ((myline = readFile.readLine()) == null) break outerloop;
// ..
}
for (int i = 0; i < 2; i++) {
if ((myline = readFile.readLine()) == null) break outerloop;
// ..
}
// ..
} while (myline != null);
Maybe you could use a while loop instead of a do-while loop and read the next line from the file before anything else. Something like this:
String myline = null;
while( (myline = readFile.readLine()) != null ) {
// All your logic...
}
readFile.close();
The condition of while loop does the following: first, read the next line of the file with myline = readFile.readLine(). The previous statement returns the value of myline, so now we check that it is not null with the comparison:
(myline = readFile.readLine()) != null
Related
so this is the main code for my text-based game.
import java.util.Scanner;
public class D_M_RPG {
public static void main(String[] args) {
//Creating the class to call on my toolbox
D_M_RPGtoolbox toolbox = new D_M_RPGtoolbox();
//Creating the scanner class for user input
Scanner input = new Scanner(System.in);
//Initiating variables and final variables aswell as arrays
//token variable to validate open spots in an array
int slotCounter = 0;
int inventoryExpander = 11;
//First initiated will be the character creation variables
String hairColor = "";
String eyeColor = "";
String skinColor = "";
String gender = "";
//Initiating the arrays for character inventory slots
String[] weaponSlots = new String[10];
//initiating the arrays for the character creation
String[] hairColorARR = {"black","Green","Yellow","Brown","Blue","Blonde","Grey","White"};
String[] eyeColorARR = {"Green","Brown","Blue","Grey",};
String[] skinColorARR = {"White","brown","Black",};
String[] genderARR = {"Male","Female"};
//Creating the introduction title and introduction
System.out.println("Welcome to, COLD OMEN.");
System.out.println("\nNOVEMBER 12th, 2150: ONTARIO, CANADA");
System.out.println("\nYou hear loud shouts and gun fire all around you but can't pinpoint the location of anything, you feel a bit dazed until someone grabs you and you open your eyes and snap out of it.");
System.out.println("\nUnknown: 'Get up, its time to move out. Take this.'");
System.out.println("\nUnknown hands you a 'M4-A4 RIFLE'");
System.out.println("\nyou manage to catch a small glimpse of him before you get up.");
//Character creation screen
System.out.println();
//ONLY WORKS ONCE WONT INCREMEMENT THE SLOTCOUNTER
toolbox.insert(weaponSlots, slotCounter, inventoryExpander, "M4-A4 RIFLE");
System.out.println("\n" + weaponSlots[0]);
toolbox.insert(weaponSlots, slotCounter, inventoryExpander, "ak47");
System.out.println(weaponSlots[0]);
}
}
so I have this method I made to basically add an "item" to the weaponSlots array (the inventory) but whenever I run it it will add to the first element in the array [0] but it wont incremement the slotcounter which should go up by one every time the method is used so that I dont replace any items in the array It should just add items until its full which is checked using the inventoryExpander variable. at the moment I have it printing the element at 0 and 0 for the array but i have checked 1 aswell and 1 is just null no item added it only just replaces the element at 0. heres the code for the method to increment etc:
public class D_M_RPGtoolbox {
//method for random number generating to be used for crit hits, turns, loot generation etc
public int randomGen(){
int x = (int) (Math.random()*((20-0)+1)+0);
return x;
}
//method for inserting into an array ONLY WORKS ONCE WONT INCREMEMENT THE SLOTCOUNTER FIX
public void insert(String[] a, int b, int d , String c) {
if(b < d) {
a[b] = c;
b++;
}//end of if statement
}//end of method
}
What you are actually performing the ++ operation on in b is a copy of the value in slotCounter.
The variable slotCounter is passed into insert "by-value".
This unlike what you probably imagine, that it is passed "by-reference".
One solution would be to do the slotCounter++ from the call row instead; and another would be to let the toolbox own the slotCounter variable completely.
This question uses the image of passing a copy of document content (by value) where changes to the document would not be seen by the sender; or as a link to a shared document (by reference), where changes could be made to the same page that the sender sees.
Its always going to be zero since you are passing zero and incrementing the local variable b.
Try calling the method as below with post increment ++ to slotCounter and see if it works for you,
toolbox.insert(weaponSlots, slotCounter++, inventoryExpander, "M4-A4 RIFLE");
I need to create a method which checks each element in my array to see if it is true or false, each element holds several values such as mass, formula, area etc for one compound, and in total there are 30 compounds (so the array has 30 elements). I need an algorithm to ask if mass < 50 and area > 5 = true .
My properties class looks like:
public void addProperty (Properties pro )
{
if (listSize >=listlength)
{
listlength = 2 * listlength;
TheProperties [] newList = new TheProperties [listlength];
System.arraycopy (proList, 0, newList, 0, proList.length);
proList = newList;
}
//add new property object in the next position
proList[listSize] = pro;
listSize++;
}
public int getSize()
{
return listSize;
}
//returns properties at a paticular position in list numbered from 0
public TheProperties getProperties (int pos)
{
return proList[pos];
}
}
and after using my getters/setters from TheProperties I put all the information in the array using the following;
TheProperties tp = new properties();
string i = tp.getMass();
String y = tp.getArea();
//etc
theList.addProperty(tp);
I then used the following to save an output of the file;
StringBuilder builder = new StringBuilder();
for (int i=0; i<theList.getSize(); i++)
{
if(theList.getProperties(i).getFormatted() != null)
{
builder.append(theList.getProperties(i).getFormatted());
builder.append("\n");
}
}
SaveFile sf = new SaveFile(this, builder.toString());
I just cant work out how to interrogate each compound individually for whether they reach the value or not, reading a file in and having a value for each one which then gets saved has worked, and I can write an if statement for the requirements to check against, but how to actually check the elements for each compound match the requirements? I am trying to word this best I can, I am still working on my fairly poor java skills.
Not entirely sure what you are after, I found your description quite hard to understand, but if you want to see if the mass is less than 50 and the area is greater than 5, a simple if statement, like so, will do.
if (tp.getMass() < 50 && tp.getArea() > 5) {}
Although, you will again, have to instantiate tp and ensure it has been given its attributes through some sort of constructor.
Lots of ways to do this, which makes it hard to answer.
You could check at creation time, and just not even add the invalid ones to the list. That would mean you only have to loop once.
If you just want to save the output to the file, and not do anything else, I suggest you combine the reading and writing into one function.
Open up the read and the write file
while(read from file){
check value is ok
write to file
}
close both files
The advantage of doing it this way are:
You only loop through once, not three times, so it is faster
You never have to store the whole list in memory, so you can handle really large files, with thousands of elements.
In case the requirements changes, you can write method that uses Predicate<T>, which is a FunctionalInterface designed for such cases (functionalInterfaces was introduced in Java 8):
// check each element of the list by custom condition (predicate)
public static void checkProperties(TheList list, Predicate<TheProperties> criteria) {
for (int i=0; i < list.getSize(); i++) {
TheProperties tp = list.get(i);
if (!criteria.apply(tp)) {
throw new IllegalArgumentException(
"TheProperty at index " + i + " does not meet the specified criteria");
}
}
}
If you want to check if mass < 50 and area > 5, you would write:
checkProperties(theList, new Predicate<TheProperties> () {
#Override
public boolean apply(TheProperties tp) {
return tp.getMass() < 50 && tp.getArea() > 5;
}
}
This can be shortened by using lambda expression:
checkProperties(theList, (TheProperties tp) -> {
return tp.getMass() < 50 && tp.getArea() > 5;
});
I got a task. The input of the Java Decathlon program is a CSV-like text file. The task is to output an XML file with all athletes in ascending order of their places, containing all the input data plus total score and the place in the competition (in case of equal scores, athletes must share the places, e.g. 3-4 and 3-4 instead of 3 and 4)
This is my cvs file:
Jana Kari;12.61;5.00;9.22;1.50;60.39;16.43;21.60;2.60;35.81;5.25.72
Eva Narun;13.04;4.53;7.79;1.55;64.72;18.74;24.20;2.40;28.20;6.50.76
Maja Hope;13.75;4.84;10.12;1.50;68.44;19.18;30.85;2.80;33.88;6.22.75
Kirke Kanda;13.43;4.35;8.64;1.50;66.06;19.05;24.89;2.20;33.48;6.51.01
I got these constants for each decathlon event
double[] A = new double[]{25.4347,0.14354,51.39,0.8465,1.53775,5.74352,12.91,0.2797,10.14,0.03768};
double[] B = new double[]{18,220,1.5,75,82,28.5,4,100,7,480};
double[] C = new double[]{1.81,1.4,1.05,1.42,1.81,1.92,1.1,1.35,1.08,1.85};
Formula for points is
Points = INT(A(B — P)^C) for track events (faster time produces a better score)
Points = INT(A(P — B)^C) for field events (greater distance or height produces a better score)
"P" is persons records (from cvs). I dont really understand how to read properly from file that it would allow me to do calculations with numbers only. Should i use two dimensional array for cvs file ? Its very confusing and im stuck.
EDIT
Well i believe for outputing later to xml file one dimensional array is better. The point of my task is code simplicity, but CVS file may be expanded to N lines so i never know how much rows it will have. I want to use number array in this code:
double[] A = new double[]{25.4347,0.14354,51.39,0.8465,1.53775,5.74352,12.91,0.2797,10.14,0.03768};
double[] B = new double[]{18,220,1.5,75,82,28.5,4,100,7,480};
double[] C = new double[]{1.81,1.4,1.05,1.42,1.81,1.92,1.1,1.35,1.08,1.85};
double PTS;
double finalscore;
for (int i = 0; i < P.length;i++ )
{
finalscore=0;
if (i == 0)
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
else if (i == 4)
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
else if (i == 5 || i == 9)
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
else
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
finalscore = finalscore + PTS;
}
System.out.println(finalscore);
}
}
Where P[] would be array first lane of number without name.
P.S it seems code above gives me result NaN when i use
double[] P = new double[]{12.61,5.00,9.22,1.50,60.39,16.43,21.60,2.60,35.81,5.272};
Yes, you have the right idea - you can use a two dimensional array. I would also recommend you create a class called Person, as this is Java programming and Java is object-oriented, but if you have not studied creating multiple classes yet, you can skip that bit and just do it with two arrays, one one-dimensional array for the names and one two-dimensional array for the numbers.
For the one-dimensional array approach
public class Person {
String name;
double[] scores;
int minutes;
int seconds;
int hundredths;
public Person(String line) {
String[] splitted = line.split(";");
name = splitted[0];
// now fill in the other fields
for(int i = 1; i < splitted.length - 1; i++) {
scores[i - 1] = Double.parseDouble(splitted[i]);
}
String times = splitted[splitted.length - 1].split("\\.");
minutes = Integer.parseInt(time[0]);
// etc. - fill in the rest
}
}
(Actually, this might be wrong, because I assumed most of the numbers are scores, but I guess they are really seconds and hundredths of a second. It doesn't really matter, unless you could have a time over one minute for those events.)
Then you need to have an array of Person objects in your other class - let's make it quite big so that it will be big enough hopefully:
Person[] array = new Person[10000];
Now have a loop, and whenever you read a line from the file you just call the constructor.
array[j] = new Person(line);
Nice approach, isn't it?
Ok guys this code is part of an assignment that I have, I am to implement an equals() method to check if two lines are equal, Two Lines are defined as equal if two end points are the same. However i can't check it because when i run the program as-is here, its blank as if the array list is empty. My question is: Do I need to change the loop reading through the file, or do I need to uncomment the initial array and do something with it in regards to the arrayList?
Any help would be greatly appreciate!!
//Line[] lines;
ArrayList<Line> lines;
Scanner reader;
public MyDrawing()
super();
this.setPreferredSize(new Dimension(500,500));
}
/**
* Reads the file and builds an array of Line objects.
*
* #param fileName The name of the file that contains the lines
* #throws Exception
*/
public void read( File fileName ) throws Exception
{
reader = new Scanner(fileName);
//----------------
// Change to Arraylist. Make the name of the arraylist "lines" so that code in paintComponent works.
//---------------------
//Have to read the first number before starting the loop
int numLines = reader.nextInt();
//lines = new Line[numLines];
ArrayList<Line>lines = new ArrayList<Line>();
Here i instantiate the arrayList
//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 );
//----------------
// Change to make sure that you only add lines that don't already exist.
//--------------------
lines.add(l);
//lines[i] = l;
and here i tried to add the line "l" to the list
}
}
if( lines != null ) {
for( Line l: lines ) {
int x1 = l.getBeg().getX();
int y1 = l.getBeg().getY();
int x2 = l.getEnd().getX();
int y2 = l.getEnd().getY();
g.setColor(l.color);
g.drawLine(x1, y1, x2, y2);
System.out.println(l);
}
}
//Print the action to the console
System.out.println( "drawing lines" );
}
}
You have an instance variable named lines but you are not using it inside the read method. Inside the read method you are declaring a local variable with the same name lines and reading into it but that’s not changing the instance field with the same name. Hence that instance field will be null at the later time when you try to use it. Unfortunately you are protecting that code with if(lines != null) instead of asking yourself why something is null which oughtn’t.
While your code that iterates over the instance field works regardless of whether lines is an array or an ArrayList your code that reads into it cannot work with an array as arrays don’t have an add method. So, when changing the instance variable to an array, the fact that the read method still compiles gives you a hint that it is not using that array.
Change the line ArrayList<Line>lines = new ArrayList<Line>(); inside the read method into lines = new ArrayList<Line>();. Then the list you are reading into will be stored in the instance field you are using later. And, of course, it won’t compile anymore if lines is declared as an array.
I am having some problems in getting a loop to work. My goal is to create a loop which will allow the user to fill in lottery numbers in several rows (the user may decide how many rows he/she wants to fill out, but it can not be more than a maximum number specified earlier in the code). So far, my code is as follows:
import java.util.Scanner;
public class LotteryTicket {
public LotteryRow[] rows;
public int numberOfRows;
public Player ticketOwner;
public LotteryTicket(int maxNumberOfRows) {
this.rows = new LotteryRow[maxNumberOfRows];
}
Scanner input = new Scanner(System.in);
public void fillInTicket() {
System.out.print("How many rows do you want to fill in? ");
int n = input.nextInt();
while (n < 1 || n > rows.length) {
System.out.println("The number of rows must lie between 1 and " + rows.length);
System.out.print("How many rows do you want to fill in? ");
n = input.nextInt();
}
for (int index = 0; index < n; index++) {
rows[index].fillInRow();
}
numberOfRows = n;
}
When I try to run this in a main-method, and I enter a proper number of rows, I get the error message:
Exception in thread "main" java.lang.NullPointerException
at LotteryTicket.fillInTicket(LotteryTicket.java:24)
Line 24 is the line in which I call upon the fillInRow()-method which I have created in another class, so I suspect the problem lies here. I know that this method works fine, as I have tried it in a test program. However, am I not referring correctly to this fillInRow()-method?
Any help will be much appreciated!
You created an array with size maxNumberOfRows, but you haven't populated it with any objects. It initially just contains null references.
To fix the code, you have to call the LotteryRow constructor to create an object and then put a reference to that object in your array. You can fix your code like this:
for (int index = 0; index < n; index++) {
rows[index] = new LotteryRow();
rows[index].fillInRow();
}
You must create a new object and place it in the array before you call a method on it. Java arrays of objects are initialized to all nulls.
You never initialize rows. Yes, you create the Array with this.rows = new LotteryRow[maxNumberOfRows]; but that does NOT create a new LotteryRow Object for every Array Entry, so the whole array is filled with null. You have to create the LotteryRow Objects by yourself