Simple java music database with NullPointerException - java

I'm first year computer science and our assignment for semester 1 is to design a simple music database in java.
I'm using 3 classes, Interface(handles all user in/out), Song(stores artist, name, duration and filesize) and Database(stores 4 song objects; a,b,c,d). I can compile and run the the program fine, but when I enter the last field(fileSize) instead of a message returning the recently entered information I receive a NullPointerException, I understand this has something to do with assigning the value of null.
The code for the database class is;
public class songDatabase
{
song sin = new song();
private song a,b,c,d;
public songDatabase()
{
a = null;
b = null;
c = null;
d = null;
}
public void addSong(String artist, String name, double duration, int fileSize)
{
if (a==null) setData(a,artist,name,duration,fileSize);
else if (b==null) setData(b,artist,name,duration,fileSize);
else if (c==null) setData(c,artist,name,duration,fileSize);
else if (d==null) setData(d,artist,name,duration,fileSize);
}
private void setData(song sin, String artist, String name, double duration, int fileSize)
{
sin.setArtist(artist);
sin.setName(name);
sin.setDuration(duration);
sin.setFileSize(fileSize);
}
public String visconfir()
{
if (a != null) return("You have imported: "+sin.getName()+"by"+sin.getArtist()+"which is"
+sin.getFileSize()+"kB and"+sin.getDuration()+"long(mm.ss)");
else return("Error - No file imported to database memory slot a");
}
}
Can anybody help me out with this?

if (a==null) setData(a,artist,name,duration,fileSize);
if a == null you call setData with a as the first parameter (which is null).
Now, in setData you do:
sin.setArtist(artist); where sin is the first parameter. Which is like writing:
null.setArtist(artist), which of course.. throws an NPE.
Additional side note: I suggest you to follow Java Naming Conventions. After you'll read this, you might want to change the class name to begin with a capital letter.

Related

How to Create Objects Using Records in a Text File (Java)

I'm working on a program for my Java class where I'm using a file of objects (clothing items) that represents inventory for a store. Each Retail_Item has four attributes: int itemNumber, String description, int numInInventory, and double price.
What I'm trying to figure out is how to read in each line from the file and turn each line into an object. My first thought was to create a while loop with vars like currentItemNumber, currentDescription, etc. So I tried this:
while (file.hasNextLine()) {
currentItemNumber = file.nextInt();
currentDescription = file.next
} // end while
But I got stuck there because every other time I've read in a String to a Scanner, I've always used nextLine. Can't use that here though, because each line contains multiple attributes of the object, not a String within a line. Is there a way to do this in the structure I'm trying to use, or should I be doing this a different way? I know I've seen and done some things where I parsed a String into separate pieces which I've seen people refer to as "tokens." Would people recommend reading each line in and then parsing it into separate tokens, then assigning each token to its appropriate attribute? Then I guess I'd have to cast those tokens into the appropriate object, since I think reading the whole line in and then parsing it would make each piece a String.
Here's a sample of what's in the text file (which can't be changed in any way, per the professor's instructions):
1000 Pants 10 19.99
2000 Jeans 2 25.95
3000 Shirt 12 12.50
Thanks in advance for your sage wisdom if you've got it.
The following code fulfills your requirement as stated in your question, namely how to create an instance of class RetailItem from a line of text from your text file. I presume it uses things that you may not have learned yet, like class Paths and try-with-resources. This is just used to scan through your file.
First, class RetailItem contains the members you described in your question. Next, I wrote a constructor for class RetailItem that creates a new instance and initializes the instance members. Then I wrote a toString() method that displays the contents of a RetailItem object in "human readable" form. Finally a main() method that reads your text file (which I named "clothes.txt"), line by line - using a Scanner. For each line read, the code splits it using a delimiter which consists of at least one whitespace character. (I presume you haven't yet learned about regular expressions in java.) Then I convert the elements of the String array returned by method split() into appropriate data types that are required by the RetailItem constructor. Then I call the constructor, thus creating an instance of class RetailItem (as you requested) and I print the created instance.
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Scanner;
public class RetailItem {
private static final int FIELDS = 4;
private int itemNumber;
private String description;
private int numInInventory;
private double price;
public RetailItem(int itemNumber, String description, int numInInventory, double price) {
this.itemNumber = itemNumber;
this.description = description;
this.numInInventory = numInInventory;
this.price = price;
}
#Override // java.lang.Object
public String toString() {
return String.format("%4d %-5s %2d %2.2f", itemNumber, description, numInInventory, price);
}
public static void main(String[] args) {
try (Scanner file = new Scanner(Paths.get("clothes.txt"))) {
while (file.hasNextLine()) {
String record = file.nextLine();
String[] fields = record.split("\\s+");
if (fields.length == FIELDS) {
int itemNumber = Integer.parseInt(fields[0]);
String description = fields[1];
int numInInventory = Integer.parseInt(fields[2]);
double price = Double.parseDouble(fields[3]);
RetailItem item = new RetailItem(itemNumber, description, numInInventory, price);
System.out.println(item);
}
}
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
I think the way that I would do is, like you said, parse each line into separate strings and then assign each piece to instance variables of the object you are building.
I have done something like this before, maybe it can be helpful.
Scanner fileScan;
File babyNameFile = new File("yob2015.txt");
try {
fileScan = new Scanner(babyNameFile);
} catch (FileNotFoundException e) {
System.out.println("File does not exist");
return;
}
String currentLine;
int numberOfGirlsNames = 0;
while (fileScan.hasNextLine()) {
String[] values;
currentLine = fileScan.nextLine();
values = currentLine.split(",");
if (values[1].equals("F")) {
numberOfGirlsNames = numberOfGirlsNames+1;
}
}
System.out.println("Number of female names was "+numberOfGirlsNames);

how many time the characters of string are to be found in another string

my professor gave me an exercise to find how many time the characters of string called "filter" are to be found in a second string called "query".
before I begin I am java noob and English isnt my native language.
example:
String filter="kjasd";
String query="kjg4t";
Output:2
getting how many times a char has been found in another string isnt my problem but the problem that the professor gave us some rules to stick with:
class filter. The class must be the following public
Provide interfaces:
public Filter (String letters) (→ Constructor of class)
The string representing the filter should be stored in the letters string
public boolean contains (char character)
Returns true if the passed character is contained in the query string, otherwise false
-public String toString ()
Returns an appropriate string representation of the class (just to be clear I have no clue about what does he means with this one!)
To actually determine the occurrences of the filter in the query, another class QueryResolver is to be created.
The class should be able to be used as follows:
QueryResolver resolver = new QueryResolver();
int count = resolver.where(query).matches(filter).count();
the filter and the query are given by the user.
(i couldnt understand this one! )The methods "where" and "matches" configure the "QueryResolver" to include a subsequent call of "count" the calculation based on the previously passed variables
"query" and "filter" performs.
The count method should use the filter's previously-created method.
The modifier static is not allowed to use!
I dunno if he means that we cant use static {} or we cant use public (static) boolean contains (char character){}
we are not allowed to use void
so the problems that encountered me
- I can not pass a char to the method contains as long as it is not static.
error "Non-static variable can not be referenced from a static context"
i did not understand what i should do with the method toStirng!
what I've done so far:
Approach Nr 1:
so I just wrote everything in the main method to check whether the principle of my code works or not and then I wanted to create that whole with constructor and other methods but unfortunately I did not succeed.
Approach Nr 2:
then I tried to write the code in small mthoden as in the exercise but I did not succeed !.
in both aprroaches i violated the exercise rules but i cant seem to be able to do it alone thats why i posted the question here.
FIRST APPROACH:
public class filter{
public filter(String letters) {
//constructor of the class
String filter;
int count;
}
public boolean contains (char character){
/*Subprogram without static!
*the problem that I can't pass any char to this method if it wasn't static
*and I will get the following error"Non-static variable cannot be referenced from a static context"
*I understand why I'm getting the error but I don't know how to get around it X( */
return true ;
}
public String toString (){
/*he told us to include it in the program but honestly, I don't know what shall I write in it -_-
*I make it to null because you have to return something and I don't know what to do yet
*so, for now, I let it null. */
return null;
}
public static void main(String[] args) {
Scanner in =new Scanner (System.in);
System.out.println("please enter the query string! ");
String query= in.next();
System.out.println("please enter the filter stirng!");
String filter= in.next();
System.out.println("the query string is : [" + query+ "]");
System.out.println("the filter string is : [" + filter+ "]");
int count=0;
// I initialized it temporarily because I wanted to print it!
//later I need to use it with the boolean contains as a public method
boolean contains=false;
//to convert each the query and the filter strings to chars
char [] tempArray=query.toCharArray();
char [] tempArray1=filter.toCharArray();
//to iterate for each char in the query string!
for (int i = 0; i < tempArray.length; i++) {
char cc = tempArray[i];
//to iterate for each char in the filter string!
for (int j = 0; j < tempArray1.length; j++) {
// if the value in the filter string matches the value in the temp array then increment the counter by one!
if(tempArray1[j] == cc){
count++;
contains=true;
}
}
}
System.out.println("the characters of the String ["+filter+"] has been found in the forworded string ["+query+"] exactly "+count+" times!" );
System.out.println("the boolean value : "+ contains);
in.close();
}
}
SECOND APPROACH
- But here too I violated the rules of the task quite brutally :(
- First, I used void and did not use the tostring method.
- Second, I did not use a constructor.
- I did not add comments because that's just the same principal as my first attempt.
public class filter2 {
public static void main(String[] args) {
Scanner in = new Scanner (System.in);
System.out.println("enter the filter string:");
String filterStr=in.next();
System.out.println("enter the query string:");
String querystr =in.next();
Filter(filterStr, querystr);
in.close();
}
public static void Filter(String filterstr , String querystr){
char [] tempArray1 = filterstr.toCharArray();
contains(tempArray1, querystr);
}
public static void contains(char[]tempArray1, String querystr){
boolean isThere= false ;
int counter=0;
char [] tempArray = querystr.toCharArray();
for (int i = 0; i < tempArray.length; i++) {
char cc = tempArray[i];
for (int j = 0; j < tempArray1.length; j++) {
if(tempArray1[j] == cc){
counter++;
isThere=true;
}
}
}
System.out.println("the letters of the filter string has been found in the query string exactly "+counter+" times!\nthus the boolean value is "+isThere);
}
/*
* sadly enough i still have no clue what is meant with this one nor whatshall i do
* public String toString (){
* return null;
* }
*
*/
}
Few hints and advice would be very useful to me but please demonstrate your suggestions in code because sometimes it can be difficult for me to understand what you mean by the given advice. ;)
Thank you in advance.
(sorry for the gramatical and the type mistakes; english is not my native language)
As already mentioned, it is important to learn to solve those problems yourself. The homework is not for punishment, but to teach you how to learn new stuff on your own, which is an important trait of a computer scientist.
Nonetheless, because it seems like you really made some effort to solve it yourself already, here is my solution, followed by some explanation.
General concepts
The first thing that I feel like you didn't understand is the concept of classes and objects. A class is like a 'blueprint' of an object, and the object is once you instanciated it.
Compared with something like a car, the class would be the description how to build a car, and the object would be a car.
You describe what a class is with public class Car { ... }, and instanciate an object of it with Car myCar = new Car();.
A class can have methods(=functions) and member variables(=data).
I just repeat those concepts because the code that you wrote looks like you didn't fully understand that concept yet. Please ask some other student who understood it to help you with that.
The Filter class
public class Filter{
String letters;
public Filter(String letters) {
this.letters = letters;
}
public boolean contains (char character){
for(int i = 0; i < letters.length(); i++) {
if(letters.charAt(i) == character)
return true;
}
return false;
}
public String toString (){
return "Filter(" + letters + ")";
}
}
Ok, let's brake that down.
public class Filter{
...
}
I guess you already got that part. This is where you describe your class structure.
String letters;
This is a class member variable. It is unique for every object that you create of that class. Again, for details, ask other students that understood it.
public Filter(String letters) {
this.letters = letters;
}
This is the constructor. When you create your object, this is the function that gets called.
In this case, all it does is to take an argument letters and stores it in the class-variable letters. Because they have the same name, you need to explicitely tell java that the left one is the class variable. You do this by adding this..
public boolean contains (char character){
for(int i = 0; i < letters.length(); i++) {
if(letters.charAt(i) == character)
return true;
}
return false;
}
This takes a character and looks whether it is contained in this.letters or not.
Because there is no name collision here, you can ommit the this..
If I understood right, the missing static here was one of your problems. If you have static, the function is class-bound and not object-bound, meaning you can call it without having an object. Again, it is important that you understand the difference, and if you don't, ask someone. (To be precise, ask the difference between class, object, static and non-static) It would take too long to explain that in detail here.
But in a nutshell, if the function is not static, it needs to be called on an object to work. Look further down in the other class for details how that looks like.
public String toString (){
return "Filter(" + letters + ")";
}
This function is also non-static. It is used whenever the object needs to be converted to a String, like in a System.out.println() call. Again, it is important here that you understand the difference between class and object.
The QueryResolver class
public class QueryResolver {
Filter filter;
String query;
public QueryResolver where(String queryStr) {
this.query = queryStr;
return this;
}
public QueryResolver matches(String filterStr) {
this.filter = new Filter(filterStr);
return this;
}
public int count() {
int result = 0;
for(int i = 0; i < query.length(); i++) {
if(filter.contains(query.charAt(i))){
result++;
}
}
return result;
}
}
Again, let's break that down.
public class QueryResolver {
...
}
Our class body.
Note that we don't have a constructor here. It is advisable to have one, but in this case it would be an empty function with no arguments that does nothing, so we can just leave it and the compiler will auto-generate it.
public QueryResolver where(String queryStr) {
this.query = queryStr;
return this;
}
This is an interesting function. It returns a this pointer. Therefore you can use the result of the function to do another call, allowing you to 'chain' multiple function calls together, like resolver.where(query).matches(filter).count().
To understand how that works requires you to understand both the class-object difference and what exactly the this pointer does.
The short version is that the this pointer is the pointer to the object that our function currently lives in.
public QueryResolver matches(String filterStr) {
this.filter = new Filter(filterStr);
return this;
}
This is almost the same as the where function.
The interesting part is the new Filter(...). This creates the previously discussed Filter-object from the class description and puts it in the QueryResolver object's this.filter variable.
public int count() {
int result = 0;
for(int i = 0; i < query.length(); i++) {
if(filter.contains(query.charAt(i))){
result++;
}
}
return result;
}
Iterates through the object's query variable and checks for every letter if it is contained in filter. It keeps count of how many times this happens and returns the count.
This function requires that filter and query are set. Therefore it is important that before someone calls count(), they previously call where(..) and matches(..).
In our case, all of that happens in one line, resolver.where(query).matches(filter).count().
The main function
I wrote two different main functions. You want to test your code as much as possible during development, therefore the first one I wrote was a fixed one, where you don't have to enter something manually, just click run and it works:
public static void main(String[] args) {
String filter="kjasd";
String query="kjg4t";
QueryResolver resolver = new QueryResolver();
int count = resolver.where(query).matches(filter).count();
System.out.println(count);
}
Once you understand the class-object difference, this should be straight forward.
But to repeat:
QueryResolver resolver = new QueryResolver();
This creates your QueryResolver object and stores it in the variable resolver.
int count = resolver.where(query).matches(filter).count();
Then, this line uses the resolver object to first call where, matches, and finally count. Again, this chaining only works because we return this in the where and matches functions.
Now finally the interactive version that you created:
public static void main(String[] args) {
Scanner in =new Scanner(System.in);
System.out.println("please enter the query string! ");
String query= in.next();
System.out.println("please enter the filter stirng!");
String filter= in.next();
System.out.println("the query string is : [" + query+ "]");
System.out.println("the filter string is : [" + filter+ "]");
QueryResolver resolver = new QueryResolver();
int count = resolver.where(query).matches(filter).count();
System.out.println("the characters of the String ["+filter+"] has been found in the forworded string ["+query+"] exactly "+count+" times!" );
in.close();
}

Initializing a general HashMap with constant values for a class [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I am having problems instantiating a general HashMap with constant values. I intend to track inventory of various car types in a car rental service; with car type serving as key and num available to rent as the value.
I attempted using a method createAvailable cars which initializes the map to constants for max number of each car type. For further testing I included a setMaxCarsAvailable method as well. Despite all this I get a NullPointer Exception coming from my canReserveVehicle method enter image description hereon the line specifying that if there are 0 available cars then you can't reserve a vehicle. How do I properly handle inventory with my map of cars? Where should I place it? I tried using a static method and later including it in a constructor with no luck. See my code below.. (I have included a picture of the stack trace showing the errors in the testCase class. I hope all this extra info helps)
public class CarReservationController {
String phoneNumber;
long numDays = 0;
Vehicle vehicle;
VehicleType vType;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static final int MAX_ECONOMY = 10; //used this to track the amount of cars available to rent. This was applied in the canReserveVehicle and addReservation methods
public static final int MAX_PREMIUM = 10;
public static final int MAX_SUV = 5;
public CarReservationController()
{
availableCars = createAvailableCarsMap(); //this is my attempt at instantiating my availableCars map to contain (VehicleType.ECONOMY, 10), (VehicleType.PREMIUM, 10), map.put(VehicleType.SUV, 5); ;
}
Map<VehicleType, Integer> availableCars;
Map<VehicleType, PriorityQueue<Date>> reservedVehicleReturnDates = new HashMap<>(); // Map from vehicle type to reserved car end dates. This will hold all the current reservations end dates for each vehicle type
//was public static map
public HashMap<String, List<CarReservation>> reservationsMap = new HashMap<>();
//previously private static Map...
private Map<VehicleType, Integer> createAvailableCarsMap() {
Map<VehicleType, Integer> map = new EnumMap<VehicleType, Integer>(VehicleType.class);
map.put(VehicleType.ECONOMY, MAX_ECONOMY);
map.put(VehicleType.PREMIUM, MAX_PREMIUM);
map.put(VehicleType.SUV, MAX_SUV);
return map;
}
public void setMaxCarsAvailable(VehicleType v, int maxAvailable) {
availableCars.put(v, maxAvailable);
}
//I UPDATE carReservationsMap here..this adds an actual reservation but first it checks the boolean canReserveVehicle below
public void addReservation(CarReservation res) throws Exception //right here
{
Date sDate = res.getStartDate(); //HERE
Date eDate = res.getEndDate(); //HERE
String phoneNumber = res.getPhoneNumber();
if(canReserveVehicle(vType, phoneNumber, sDate, eDate)) {
if (reservationsMap.containsKey(phoneNumber)) {
List<CarReservation> currCustomerRes = reservationsMap.get(phoneNumber);
currCustomerRes.add(res);
reservationsMap.put(phoneNumber, currCustomerRes);
} else {
List<CarReservation> currCustomerRes = new ArrayList<CarReservation>(Arrays.asList(res));
reservationsMap.put(phoneNumber, currCustomerRes);
}
int countForVehicleType = availableCars.get(vType);
availableCars.put(vType, countForVehicleType - 1);
if (reservedVehicleReturnDates.containsKey(vType)) {
reservedVehicleReturnDates.get(vType).add(eDate);
} else {
PriorityQueue<Date> q = new PriorityQueue<Date>();
reservedVehicleReturnDates.put(vType, q);
}
}
}
//NULL POINTER EXCEPTION COMING UP HERE FROM JUNIT TESTS
public boolean canReserveVehicle(VehicleType v, String phoneNumber, Date startDate, Date endDate) throws ParseException
{
PriorityQueue<Date> reservedVehicleQueue = reservedVehicleReturnDates.get(v);
if(endDate.before(startDate))
return false; // check that the start date of the reservation is before the end date
if (availableCars.get(v) == 0) { /// SAYS THERE IS A NULL POINTER EXCEPTION from here... because availableCars is still 0..
Date nextCarReturnDate = reservedVehicleQueue.peek();
if(nextCarReturnDate.after(startDate))
return false; // return false if a reserved car is not going to be available before the new customer is requesting one.
}
else {
// If a car that will become available before the customer requests it, remove it from the queue and replace with the
//requesting customer's return date (as they now lay claim to the car)
reservedVehicleQueue.poll();
reservedVehicleQueue.add(endDate);
}
//these are comparing strings.
if (reservationsMap.containsKey(phoneNumber)) {
List<CarReservation> resByCustomer = reservationsMap.get(phoneNumber);
CarReservation lastResByCustomer = resByCustomer.get(resByCustomer.size() - 1);
Date lastResEndDate = sdf.parse(lastResByCustomer.endDate);
if (startDate.before(lastResEndDate)) { //1 customer can only have one rental at a time within the system.
return false;
}
}
return true;
}
}
Test case looks like this with "java.lang.NullPointerException" CarReservationController.canReserveCarVehicle"
import java.text.SimpleDateFormat;
import org.junit.Test;
public class CarReservationTest {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
#Test
public void testThatCustomerCanMakeReservation() throws Exception {
CarReservationController reservationSystem = new CarReservationController();
reservationSystem.setMaxCarsAvailable(VehicleType.PREMIUM, 2);
CarReservation firstRes = new CarReservation(VehicleType.PREMIUM, "Jon Snow", "1234567890", "2019-01-23", "2019-01-31");
reservationSystem.addReservation(firstRes);
//assertTrue(reservationSystem.reservationsMap.containsKey("1234567890"));
assertTrue(reservationSystem.reservationsMap.size() > 0);
assertEquals(firstRes, reservationSystem.reservationsMap.get("1234567890"));
}
}
There are several issues that make this complicated to debug.
Perhaps most important for the question you asked, without a full stacktrace, it isn't obvious whether the NPE you are seeing is from availbleCars.get(v) or from availableCars.get(v) == 0.
That issue is complicated by the fact that without knowing what the ReservationSystem::addReservation method does, I don't think it's possible to rule out either possibility.
Possibility 1
However, if the issue is from availableCars.get(v) == 0, then it might be from your choice to compare equality between an Integer and a numeric primitive using == instead of .equals(). Please see this previous answer for a more complete discussion: Why comparing Integer with int can throw NullPointerException in Java?
Possibility 2
If the issue is from availableCars.get(v) (that availableCars itself is null), then you may have an issue with how you are instantiating that availableCars map. The method you are using there doesn't need to be static, and also you don't need the setter you have created.
Next Steps
To solve this problem, I'd recommend using a breakpoint or breaking that comparison into two steps with debug statements - first check to see that availableCars is not null, then check that availableCars.get(v) is an Integer, and then use .equals() to check the equality with 0.
In addition, you might try unit testing your methods to instantiate the availableCars map and the ReservationSystem::addReservation method separately as well, to help narrow down where the bug might be.

Accessing an Objects values Java

Okay so I'm creating a simple flight booking system. I've spent a fair bit of time debugging and now even the simplest things are stumping me.
I have an interface which looks close to:
public class Flight implements IFlight {
String destination;
String departure;
int clubrows = 0;
int ecorows = 0;
public Flight(String dest, String dept, int clubrow, int ecorow) {
destination = dest;
departure = dept;
clubrows = clubrow;
ecorows = ecorow;
}
public String getDestination() {
return destination;
}
This class has many similar get methods.
Now i'm trying to write a for loop where every value that is put in is printed out. So i need to access all the 0 values then all the 1 values etc.
it looks kinda like this right now:
public void flightManifest() {
System.out.println("Available flights: ");
for(int i=0; i<flightCount ;i++){
System.out.println("Flight number: "+flightCount +", Destination: "+ +", Departure time: "+ );
}
So essentially whenever i try to access the variables i keep balls-ing it up, so how am i meant to access these values each time round?
So the way I store them is as such:
flightArr[flightCount] = new Flight (dest, dept, clubrow, ecorow);
flightCount++;
or at least thats how it is made.
Provide a toString() method to your Flight class, and then simply call it within your loop.
Within that toString() method, return the String concatenation of your class fields. That's all.

Java Input Output Logic

First of all, id like to thank this fourm, as I am finding myself quickly improving through all the material on this forum and all the help different members have been giving me. So this is just a big thank you for all of that. As for my question, I've been experimenting around with input out and wanted to see if this logic would work. I am trying to get the appropriate things in their appropriate array, and wanted to see if this logic would do it. Currently (and for a while) I wont be in a place where I can access any Virtual IDE effectively so all this was kinda done on the fly using notepad, word etc. *So don't be to hard on my syntax. What I am mostly concerned about is the logic (if it would work) and to a lesser mistake any major mistakes in code.*
Thanks alot.
So basically, the text file goes like this. Title, one line of space, then name, age and wage and the separator is the #. Then right below that, name, age and wage the separator bring # etc etc.
(pretend there was no line spaces between Bobby, Sandy, Roger, Eric and David..so pretend in the txt file they are right under each other, but there is a gap in between information and bobby.
Information
Bobby#24#5.75
Sandy #19#10.22
Roger #27#6.73
Eric#31#8.99
David#12#3.50**
Here is the logic i've come up with.
public class Practice {
public static void main(String[] args) throws Exception {
String Name [] = new String [5];
int Age [] = new int [5] ;
double Wage [] = new double [5];
String Blank [] = new String [5];
FileReader inputfile = new FileReader (new File(info.txt));
BufferedReader InputBuffer = new BufferedReader (inputfile);
String Title = InputBuffer.readline (); // to get the title
int count = 0;
while (InputBuffer.readline() = null) { // this while loop grabs the blank under the title
Blank [count] = count;
}
int i = 0;
while (InputBuffer.readline() !=null) {
String Getter = InputBuffer.readline (); // reads line
String splitup= Getter.split(#); // splits it
Name [i] = splitup[i]; // puts name in this array
Age [i] = splitup([i] + 1); // age in this array
Wage [i] = splitup([i] + 2); // wage in this array
}
InputBuffer.close();
}
}
Would this logic work for storing the title in the title String, the Blank line under the Blank Array, the name under the name array, age under the age array and the wage under the wage array??
Thanks alot.
P.S: Mostly concerned about the last while loop, I want to know if it will put the name in the name array, the age in the age array and the wage in the wage array.
First of all, you only need one while-loop. I don't understand why you have two, especially since the conditional in the first is nonsensical ( InputBuffer.readline() = null ).
Your loop would look something like this:
boolean isTitleParsed = false;
String title;
String line;
while ( (line = inputBuffer.readLine()) != null ) {
if (!isTitleParsed) {
// this is the title
title = line;
isTitleParsed = true;
} else if (line.isEmpty()) {
// this is a blank line; logic for dealing with blank lines here
...
} else {
// this is actual person data
String[] personData = line.split("#");
if (personData != null && personData.length == 3) {
String name = personData[0];
String age = personData[1];
String wage = personData[2];
...
}
...
}
}
Secondly, I think using arrays is entirely the wrong way to go. Like #AVD mentioned in his comment on the OP, List<T> and a POJO is probably a much better solution -- and much more extensible.
And finally: no, as you've written it, your second loop will not successfully save the name, age, and wage to the arrays. You never increment i and the syntax splitup([i] + 1) is just wrong. (You probably meant splitup[i+1].)
Using Arrays
If you're really stuck on using arrays to save your data, you'd have to do in something like this:
String[] names = new String[5];
String[] ages = new String[5];
String[] wages = new String[5];
...
int index = 0;
while ( (line = inputBuffer.readLine()) != null && index < 5) {
if (!isTitleParsed) {
...
} else if (line.isEmpty()) {
...
} else {
// this is actual person data
String[] personData = line.split("#");
if (personData != null && personData.length == 3) {
String name = personData[0];
String age = personData[1];
String wage = personData[2];
names[index] = name;
ages[index] = age;
wages[index] = wage;
index++;
} else {
System.err.println("Line " + line + " is malformed and was not saved.");
}
...
}
}
Notice that index is instantiated at 0, but is incremented every time we save something to the arrays. This way names[0] will hold the first name, names[1] will hold the second, and so on.
Notice also that we save a given record's name, age, and wage all at the same index. So we could expect names[0] to hold "Bobby", ages[0] to hold "24", and wages[0] to hold "5.75" -- all of which are related to the same record.
Finally, the condition in the while loop has been amended to be (line = inputBuffer.readLine()) != null && index < 5. This means we'll keep looping through the lines of the file until we either run out of lines (the file ends) or our index becomes greater than 5, which is the size at which we instantiated the array. This is one reason why arrays are such a bad structure to hold this data: you have to know exactly how many records you have in your file, and you may end up not filling them all the way (you allocated too much space) or not saving some records because you have no more room to store them.
Using POJOs
A much better way to save the data would be to use a POJO -- a Plain Old Java Object. This kind of object is pretty much a "data holder" object.
In your case, it would be something like this:
public class PersonData {
private String name;
private String wage;
private String age;
public PersonData() {
this(null, null, null);
}
public PersonData(String name, String wage, String age) {
this.name = name;
this.wage = wage;
this.age = age;
}
// ... getters and setters here
}
In your code, you'd replace your arrays with a List structure of PersonData objects:
List<PersonData> records = new ArrayList<PersonData>();
And in your while loop, you'd save into these objects instead of into the arrays:
// in the else in the while loop:
String[] data = line.split("#");
if (data != null && data.length == 3) {
PersonData record = new PersonData(data[0], data[1], data[2]);
records.add(record);
} else {
// error handling for malformed line
}
Now if you wanted to get data for a particular record, you'd just need to extract the PersonData object from your records list and query it:
// assuming the first record we scraped was "Bobby#24#5.75"
PersonData person = records.get(0);
person.getName(); // returns "Bobby"
person.getAge(); // returns 24
person.getWage(); // returns 5.75
Since we're using a List and not an array, we don't have to worry about knowing exactly how many records there are in the file, and we don't run the risk of losing information because we don't have anywhere to store it.
This way we can also know for certain that a name, age, and wage are all related to the same record, whereas before we were just hoping that, say, all records at index 0 in the arrays were related to the same person.
Also, if you add additional data to the records -- for example, name#age#wage#favorite food -- all you have to do is add a new field to the PersonData object and add a line in your parsing method to add that data to the object. If you were using arrays, you'd need to add a new array, and so on.
It's also much easier to create logic if, say, you have a row that only has a name or that missing a wage, and so on -- so that you're actually able to save the data in some meaningful fashion.
If you want to make good progress in Java or any OOP Language for that matter you should always approach a problem in a Object Oriented Manner.
For the problem at hand you should always consider a class to store the Person Info rather than using associative arrays.
class PersonInfo {
PersonInfo(String name,int age,float wage) {
this.name = name;
this.age = age;
this.wage = wage;
}
String name;
int age;
float wage;
}
The code is more or less the same from above...but it should give a List of PeopleInfo as output.
List<PersonInfo> peopleInfo = new ArrayList<String>();
boolean isTitleParsed = false;
while ( (line = inputBuffer.readLine()) != null ) {
if (!isTitleParsed) {
// this is the title
title = line;
isTitleParsed = true;
continue;
} else if (line.isEmpty()) {
// this is a blank line; logic for dealing with blank lines here
} else {
String[] personData = line.split("#");
if (personData != null && personData.length == 3) {
peopleInfo.add(new PersonInfo(personData[0],personData[1],personData[2]));
}
}

Categories