I'm trying to read in player data from an array list, but after 2 hours of searching and experimenting, I'm lost.
Here's the deserializing code. It's commented, but basically there should be a file with a Serialized ArrayList of Player objects. I want to deserialize that data and store it in savedPlayers, and then use savedPlayers for a few things.
What did I do wrong?
import java.io.*;
import java.util.*;
public class RoofRunnerApp {
private Scanner in; // Scanner to take playerName input.
private RoofRunnerGame gameTime;
private String filename = "gameData.txt";
public static void main (String[] args) {
System.out.println("WELCOME TO *ROOF RUNNER* \n"); // Welcomes user with game title.
RoofRunnerApp myGame = new RoofRunnerApp();
}
public RoofRunnerApp() {
// 1) Read in name from user.
in = new Scanner(System.in);
System.out.print("Please enter your name: ");
String playerName = in.next();
// 2) Create Player arrayList.
ArrayList<Player> savedPlayers = new ArrayList<Player>();
// 3) Read in Serialized Data from file.
try {
ObjectInputStream input = new ObjectInputStream(new FileInputStream(filename)); // Add file name.
savedPlayers = (ArrayList<Player>)input.readObject();
input.close();
} catch( Exception e ) {
e.printStackTrace();
return;
}
Player thisPlayer; //thisPlayer is passed to Game class.
// 4) if arraylist != empty -> Check for playerName and inputName match.
////// If there's a match -> Set thisPlayer equal to the savedPlayer, using the Player constructor.
if(savedPlayers.length() != 0)
for(int i = 0; i < savedPlayers.length(); i++)
if(playerName.equals(savedPlayers.getName())){
thisPlayer = new Player(savedPlayers[i]);
break;
}
}
else
thisPlayer = new Player(playerName); // If no match -> Set thisPlayer to new player with playerName.
RoofRunnerGame gameTime = new RoofRunnerGame(thisPlayer);
}
I know I'm not supposed to answer, but it's not letting me edit.
UPDATE/QUESTIONS
I haven't serialized any data, yet. Right now I'm just trying to set up the deserialization (and I was going to add in serialization after). But, in Eclipse, when I try the above I get several error messages saying that savedPlayers is not an arrayList and that length() doesn't work on it.
Here's the class code. (The code near the bottom is still in the works. My errors happen in lines 33-37:
import java.io.*;
import java.util.*;
public class RoofRunnerApp {
private Scanner in; // Scanner to take playerName input.
private RoofRunnerGame gameTime;
private String filename = "gameData.txt"; // File to hold Serialized Player data.
public static void main (String[] args) {
System.out.println("WELCOME TO *ROOF RUNNER* \n"); // Welcomes user with game title.
RoofRunnerApp myGame = new RoofRunnerApp();
}
public RoofRunnerApp() {
// 1) Read in name from user.
in = new Scanner(System.in);
System.out.print("Please enter your name: ");
String playerName = in.next();
// 2) Create Player arrayList.
ArrayList<Player> savedPlayers = new ArrayList<Player>();
// 3) Read in Serialized Data from file.
try {
ObjectInputStream input = new ObjectInputStream(new FileInputStream(filename)); // Add file name.
savedPlayers = (ArrayList<Player>)input.readObject();
input.close();
} catch( Exception e ) {
e.printStackTrace();
return;
}
Player thisPlayer; //thisPlayer is passed to Game class.
// 4) if arraylist != empty -> Check for playerName and inputName match.
////// If there's a match -> Set thisPlayer equal to the savedPlayer, using the Player constructor.
if(savedPlayers.length() != 0)
for(int i = 0; i < savedPlayers.length(); i++)
if(playerName.equals(savedPlayers[i].getName())){
thisPlayer = new Player(savedPlayers[i]);
break;
}
}
else
thisPlayer = new Player(playerName); // If no match -> Set thisPlayer to new player with playerName.
RoofRunnerGame gameTime = new RoofRunnerGame(thisPlayer);
// After:
// Exit code in RRG
// 1) Add current Player to current ArrayList.
/*
// Create/Return player objects.
Player p = new Player(playerObject)
savedPlayers.add(p);
///// Save data to file.
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream( new FileOutputStream( "myfile") ); // Add filename.
out.writeObject( savedPlayer ); //write the entire ArrayList
out.close();
} catch( IOException e ) {
e.printStackTrace();
return;
}
*/
}
}
You have to serialize out the object first before you can read it. The format used by ObjectInputStream/ObjectOutputStream is not something you can type out. As such you should with the saving of the objects first into a file, then read them in. So write a class that does the writing and reading of the List first in a class of its own and test that out to get a feel for object serialisation and some of the problems. Test things like no file present, empty file, file with corrupt data, files with a valid list with zero entries etc.
As to your current implementation where you are catching the IOException for the reading you should not printStackTrace and return, its a normal valid case as the file does not currently contain a valid list. So instead you should do nothing in the catch so that the program continues on.
You may also find that the ObjectInputStream is returning null for the savedPlayers variable and you'll want to check that case before you assign the value to the savePlayers variable in that same reading code.
I fixed the code formatting. I assume you're a bit new to java. The error you get about savedPlayers is not that it is not an ArrayList but that it is not an array. You can't index it like savedPlayers[i] but must use savedPlayers.get(i), where i is the index. Your main problem seems to be the difference between an ArrayList and an array. An array is a primitive construct, while an ArrayList is a type built on top of an array. An actual array would have a length property (note: not a method!), while ArrayList has a size() method. Look up arrays in the java tutorial.
It's considered best practice to refer to types using the most general interface that still supports what you do, in this case that would be List. If you're new to java it really helps to have the API documentation handy. Look up List and ArrayList in there. You might even use Collection if you don't really care that order is preserved here, i.e. when you output a list to disk initialise it as:
Collection<Player> players = new ArrayList<Player>();
Collection doesn't have positional access though, so stick to List if you need that.
Another tip, you're using a for-loop to iterate over all the players, but collections such as List have iterators for this. It's generally more efficient when not using an ArrayList. There is a for-loop construct that you can use to iterate over all objects in a collection:
for (Player player : players) {
// do something with each Player
}
Sorry for not editing again. I'm changing computers constantly. Anyways...
Why do you say you have to serialize the objects first? I'm trying to do this:
Have user enter his playername.
Check the gameData file to see if any data with that player's name has been saved.
If player name matches one in file -> create a Player object (thisPlayer) with that data.
If player name has no matches || file is empty -> create a Player object (this Player) with just that name and new data.
Then it would run the game.
THEENNN it would serialize the data and save it to the file.
It seems to me you have to deserialize the input at the beginning when loading data, and then serialize at the end when saving data, yeah?
Here's the code now. There's one error in the whole file. It says that thisPlayer may not have been initialized in line 46. Any ideas?
import java.io.*;
import java.util.*;
public class RoofRunnerApp {
private Scanner in; // Scanner to take playerName input.
private RoofRunnerGame gameTime;
private String filename = "gameData.txt"; // File to hold Serialized Player data.
public static void main (String[] args) {
System.out.println("WELCOME TO *ROOF RUNNER* \n"); // Welcomes user with game title.
RoofRunnerApp myGame = new RoofRunnerApp();
}
public RoofRunnerApp() {
// 1) Read in name from user.
in = new Scanner(System.in);
System.out.print("Please enter your name: ");
String playerName = in.next();
// 2) Create Player arrayList.
ArrayList<Player> savedPlayers = new ArrayList<Player>();
// 3) Read in Serialized Data from file.
try {
ObjectInputStream input = new ObjectInputStream(new FileInputStream(filename)); // Add file name.
savedPlayers = (ArrayList<Player>)input.readObject();
input.close();
} catch( Exception e ) {
e.printStackTrace();
return;
}
boolean notFound = true;
Player thisPlayer; //thisPlayer is passed to Game class.
// 4) if arraylist != empty -> Check for playerName and inputName match.
////// If there's a match -> Set thisPlayer equal to the savedPlayer, using the Player constructor.
if(savedPlayers.size() != 0){
for(int i = 0; i < savedPlayers.size(); i++){
if(playerName.equals(savedPlayers.get(i).getName())){
thisPlayer = new Player(savedPlayers.get(i));
notFound = false;
break;
}
}
}
if(savedPlayers.size() == 0 || notFound)
thisPlayer = new Player(playerName); // If no match -> Set thisPlayer to new player with playerName.
RoofRunnerGame gameTime = new RoofRunnerGame(thisPlayer);
}
Related
I'm making a guess the movie game in which i take a list of movies from a text file. I have two classes for it Game for getting a random movie and Main for the rest of the game. Now i thought of adding a choice for hollywood or bollywood movies by changing the text files in Game. I take 'h' or 'b' respectively as inputs. I call the constructor of Game with parameters to choose file accordingly but it doesn't work and ALWAYS the file is null and showing NullPointerException.
This image showing what happens during debugging. It skips the setMovieList and constructor and comes to the next line
EDIT: I am new to OOPs so please bear with me. I just saw during debugging that the debugger first goes to the class fields and THEN to the constructor, I was actually trying to use file(which is inside the constructor) for the initialization of other fields because of which its value was null and was showing NullPointerException.
Now my question really remains how to use file and noOfMovies to initialize other fields in Game.
//showing the setter method that i tried
//Main class
/*only showing the part having Game class*/
//making an object of Game class to get a random movie from the file
System.out.println("Enter 'h' for hollywood and 'b' for bollywood ");
Scanner input = new Scanner(System.in);
char genre = input.next().charAt(0);
Game newGame = new Game(genre);
//Game class
public class Game
{
public Game(char genre)
{
setMovieList(genre);
}
File file;
int noOfMovies;
public void setMovieList(char genre)
{
if(genre == 'h')
{
this.file = new File("C:\\Users\\Rashim\\Desktop\\java\\GuessTheMovie\\src\\hollywoodMovies.txt");
this.noOfMovies = 30;
}
else if(genre == 'b')
{
this.file = new File("C:\\Users\\Rashim\\Desktop\\java\\GuessTheMovie\\src\\bollywoodMovies.txt");
this.noOfMovies = 20;
}
// EDIT ------> I want to initialize the below fields <-------
private Scanner scan = new Scanner(this.file);
private int lineCount = 0;
int random = (int)(Math.random()*noOfMovies)+1;
//array for storing the movie titles
private String[] movieArray = new String[noOfMovies];
}
I'm not sure.. maybe you want to get a result like this:
GAME CLASS
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Game {
private File file = null;
//private int noOfMovies = 0;
private List<String> movies= null;
FileInputStream read = null;
public Game(char genre) {
movies = getMovieList();
System.out.println(movies);
}
public void setMovieList(char genre) {
if (genre == 'h') {
this.file = new File("C:\\Users\\Rashim\\Desktop\\java\\GuessTheMovie\\src\\hollywoodMovies.txt");
// this.noOfMovies = 30;
} else if (genre == 'b') {
this.file = new File("C:\\Users\\Rashim\\Desktop\\java\\GuessTheMovie\\src\\bollywoodMovies.txt");
// this.noOfMovies = 20;
}
}
public List<String> getList() {
List<String> movieList = new ArrayList<>();
String[] values = null;
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
values = line.split(";");
movieList.add(values[0]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return movieList;
}
public String getMovie(){
System.out.println(movies.size());
int min = 1;
int max = movies.size();
int random = min + (int) (Math.random() * (max - min));
System.out.println(random);
String title = movies.get(random);
return title;
}
}
MAIN CLASS
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
System.out.println("Enter 'h' for hollywood and 'b' for bollywood ");
Scanner input = new Scanner(System.in);
char genre = input.next().charAt(0);
Game newGame = new Game(genre);
String randomMovie = newGame.getMovie();
System.out.println(randomMovie);
}
}
Note i've used List data structure in place of array but it is obviously up to you... let me know if this may look like what you are trying to do... some other improvements can certainly be made but should work.
Also it assumes you have a txt file with movie titles separated by semicolon...otherwise you have to adjust the split method in the getList one..
Furthermore this way you no longer need the noOfMovies field cause it takes automatically the list size.
Hope it helps...
The problem is that the fields are initialised before the constructor is called.
There are a number of things you should do:
Don't call getters and setters from a constructor. See this question: Should I use getters and setters in constructors?
If you are doing complex initialisation logic, do it all in the constructor. Only initialise fields directly with very basic values (not ones that depend other fields). In your case, it will be easier just to do everything in the constructor. This avoids the problem that you change your code to modify a value in the constructor and some field initialisation stops working.
I am writing a command line app whereby my main function creates an array list, populates it by user input, and then proceeds to add that content into a txt file. However, every time I run the main function the Array List naturally starts out empty and the data is lost from it.
The user should be able to filter their content by a specific detail(e.g all first names "jane") and have it printed to the terminal/command line. I'd like to keep the data within the file and array list constantly since I am using my getter methods to do this.
My train of thought has been to take the data stored in the file and parse it back into the array list every time the main function has been run. Given that it's a personalized list, I've had trouble doing this. Any help on an approach to help me with this task would be appreciated.
public void writeToFile(String fileName, List<Student> students) {
try {
BufferedWriter printToFile = new BufferedWriter(new FileWriter(fileName, true));
for (Student student: students) {
printToFile.write(student.toString() + "\n");
}
System.out.println("Successfully Written To File!");
printToFile.close();
}
catch (IOException Exception) {
System.out.println("Error: File Not Found");
}
}
public void openFile(String fileName) {
try{
BufferedReader reader = new BufferedReader(new FileReader(fileName));
String line;
while ((line=reader.readLine())!=null)
{
System.out.println(lin);
}
}
catch (IOException fileNotFound) {
System.out.println("File Not Found.");
}
}
What would have been quite helpful is if you also provided the Students Class code within your Posted Question but in any case.....
Apparently, earlier in your main() method you took User input to fill a List Interface of Student and then I presume you successfully wrote the contents of that List to a Text file. Keep this thought.....
The application closes. Now you restart it and now you want to refill the the List. Well, basically you just need to do pretty much exactly what you did within the main() method.
How you might do this (Not Tested!):
Make sure List<Student> students; is declared as a Class Member variable within the very same Class your main() method is located. This will make the students variable global to the entire Class (among all other things possible). Now add the following method to your main class. This method will fill the students List:
public static int loadStudentData(String fileName) {
// Create a List to hold file data;
List<String> dataList = new ArrayList<>();
// Fill The Data List.
// Use 'Try With Resources' to auto-close the BufferedReader.
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line;
while ((line = reader.readLine()) != null) {
// Skip blank lines (if any);
if (line.trim().equals("")) {
continue;
}
dataList.add(line);
}
}
catch (IOException fileNotFound) {
System.out.println("File Not Found.");
}
/*
Now that you have all the Student Data from file you can
Fill in Student instance objects and add them to the students
List Object
Keep in mind, I have no idea what constructor(s) or
what Getters and Setters you have in your Student
Class OR what is contained within the data file so
we'll keep this real basic.
*/
// Declare an instance of Student.
Student student;
// Number of students to process
int studentCount = dataList.size();
// Just in case...clear the students List if it contains anything.
if (students != null || students.size() > 0) {
students.clear();
}
// Iterate through the list holding file data (dataList)
for (int i = 0; i < studentCount; i++) {
student = new Student(); // initialize a new Student
// Assuming each data line is a comma delimited string of Student data
String[] studentData = dataList.get(i).split(",|,\\s+");
student.setStudentID(studentData[0]); // String
student.setStudentName(studentData[1]); // String
student.setStudentAge(Integer.parseInt(studentData[2])); // Integer
student.setStudentGrade(studentData[3]); // String
// Add this instance of Student to the students List.
students.add(student);
}
// Return the number of students processed (just in case you want it).
return studentCount;
// DONE.
}
Note: Don't forget to close your BufferedWriter in your other *writeToFile()** method.
Ok, not sure if the title worded that correctly but say I have three objects with two strings of data each(Lets say a stateName and a cityName) stored into an arraylist. Is it possible to enter in a state name in as a string variable(call it searchStateName), then have a method search through the objects in the list and compare searchStateName to the stateName inside each object in the arraylist, and when a match is found have it return the cityName that is inside the same object as the matching stateName?
I am trying to do something similar currently and would like to figure it out myself, but I have been working on this for the past hour and am completely lost. Could anyone point me in the right direction?
This is the approach. Say you have a class called SC and you have two instance variables in it and getters and setters for them. You need to initialize 3 objects of them inside your main:
SC a = new SC("Illinois ","Chicago ");
SC b = new SC("Michigan ","Detroit");
SC c = new SC("New York"," New York");
And then create an ArrayList of object SC and add those 3 objects of SC to that ArrayList.
ArrayList<SC> list = new ArrayList<SC>();
list.add(a);
list.add(b);
list.add(c);
Now call the method that search for a state name and returns the city name if it finds it:
this.searchStateName("Illinois");
The actual implementation of this method with for-each loop:
public String searchStateName(String stateName){
String result = "No city found.";
for (SC sc : list )
if (sc.getStateName().equalsIgnoreCase(stateName)){
result = sc.getCityName();
break;
}
}
return result;
}
If you are not comfortable with for-each loop then you can use the regular for loop below. I commented out on purpose. But it will work correctly and give you the correct city name.
//public String searchStateName(String stateName){
// String result = null;
// for (int i = 0; i < list.size(); i++){
// if (list.get(i).getStateName() .equalsIgnoreCase(stateName)){
// result = list.get(i).getCityName();
// break;
// }
// }
// return result;
//}
And thats it. Let me know if you need help further.
I am working on an assignment and I'm trying to add an element to a LinkedList. The first block of code is given and should not be changed. The second block is written according to the UML given to us by the professor and is located in another class.
import java.io.*;
import java.util.LinkedList;
public class Assignment10
{
public static void main(String[] args)
{
char input1;
String inputInfo = new String();
int operation2;
String line = new String();
//create a linked list to be used in this method.
LinkedList list1 = new LinkedList();
try
{
// print out the menu
printMenu();
// create a BufferedReader object to read input from a keyboard
InputStreamReader isr = new InputStreamReader (System.in);
BufferedReader stdin = new BufferedReader (isr);
do
{
System.out.print("What action would you like to perform?\n");
line = stdin.readLine().trim(); //read a line
input1 = line.charAt(0);
input1 = Character.toUpperCase(input1);
if (line.length() == 1) // check if a user entered only one character
{
switch (input1)
{
case 'A': //Add String
System.out.print("Please enter a string to add:\n");
String str1 = stdin.readLine().trim();
System.out.print("Please enter an index to add:\n");
inputInfo = stdin.readLine().trim();
int addIndex = Integer.parseInt(inputInfo);
list1.addElement(addIndex, str1);
break;
public void addElement(int index, Object element)
{
if(index < 0)
{
IndexOutOfBoundsException ex = new IndexOutOfBoundsException();
throw ex;
}
LinkedListIterator iterator = new LinkedListIterator();
for(int i = 0; i < index; i++)
{
if(iterator.hasNext()) // check if the iterator has a next value before
iterator.next(); // moving to next element
else
{
NoSuchElementException exception = new NoSuchElementException();
throw exception;
}
}
iterator.add(element);
} // end of addElement
Here is what Eclipse is telling me:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method addElement(int, String) is undefined for the type LinkedList.
Again, I am not supposed to change the first block of code so there must be something wrong with my addElement method. Any ideas? Sorry this isn't compilable, but this is really more of a conceptual question, I think.
I think that the problem is that someone is confused.
On the one hand, you appear to be implementing a method called addElement on what appears to be a custom list implementation. (You don't show us the entire class ...)
On the other hand, you appear to be trying to call a nonexistent addElement on the standard java.util.LinkedList class.
One of these things is clearly wrong. Either you have misunderstood what you are supposed to do, or your lecturer has given you a test harness class (Assignment10) that is incorrect. (Yes lecturers do make mistakes. They are only human.)
I suggest you ask your lecturer or your tutor for clarification. (And please be polite and deferential. There is nothing more annoying for a lecturer than a student who is "in his face" about errors, especially imaginary ones.)
I'm implementing a Graph which holds "Book" objects as its nodes. The nodes are connected if the books share a keyword. The keywords for each book are held in a Vector within the Book class. To do this, I've created 3 classes.
1) Books 2) Vertex 3) Graph
The Vertex class holds the Book object and also has a Vector containing all the other Vertex objects (other books which share a keyword). In the Driver, I create the book, pass it to a Graph which then inserts it into a Vertex and finally the Vertex into a Vector named "bookGraph".
public final class Graph {
private Vector<Vertex> bookGraph = new Vector<Vertex>();
private int bookCounter = 0;
public Graph() {
}
public void addBook(Book bk) {
Vertex vtx = new Vertex(bk);
bookGraph.add(vtx);
bookCounter++;
System.out.println("Book #1 has " + bookGraph.get(0).getBook().getKeywords().size() + " keywords");
// addAdjVertices();
}
public void showKeywords() {
System.out.println("Book #1 is " + bookGraph.get(0).getBook().getKeywords().size() + " keywords");
}
The information from the books are read from a file in the Driver and inserted into a book object. I'm trying to make sure that this information is read in correctly and properly inserted into the Graph. My problem occurs when trying to get the size of the keyword Vector within the "showKeywords()" method in the Graph class. bookGraph.get(0).getBook().getKeywords().size() returns 0 when the exact same command in the addBook() method returns the correct size. I've implemented accessor methods such as getTitle() or getAuthor() in the Book class and those work correctly within the showKeywords() method. The keyword vector seems to be the only issue within the showKeywords() method. What am I doing wrong here?
Here is my Driver class....
boolean fileopen = false;
String title, author, keys;
long isbn_number;
Vector<String> keywords = new Vector<String>();
String filename = "books.txt";
String[] keywordTokens;
Scanner fin = null;
Scanner input = new Scanner (System.in);
Graph books = new Graph();
try {
fin = new Scanner (new FileReader(filename));
String fline;
fileopen = true;
System.out.println("Reading books.txt...");
while (fin.hasNextLine()) {
fline = fin.nextLine();
title = fline;
fline = fin.nextLine();
author = fline;
fline = fin.nextLine();
isbn_number = Long.parseLong(fline);
fline = fin.nextLine();
keywordTokens = fline.split(",");
for (int x = 0; x < keywordTokens.length; x++) {
keywords.add(keywordTokens[x]);
}
Book tempBook = new Book(title,author,isbn_number,keywords);
books.addBook(tempBook);
keywords.clear();
if (fin.hasNextLine()) fline = fin.nextLine();
}
books.showKeywords();
System.out.println("Ready.");
}
catch (FileNotFoundException e) {
System.out.println("FILE NOT FOUND!");
}
Looks to me like it should work - there's nothing obviously wrong (like accidentally using static variables). Can you provide a short but complete program which demonstrates the problem? The error is likely to be somewhere else - are you calling setKeywords(new Vector<String>()) somewhere, for example?
Any reason for using Vector rather than the more common ArrayList by the way? I would also suggest that setKeywords(String key) should probably be called addKeyword instead...
EDIT: Okay, now that you've posted the code it's obvious: you're only ever creating a single instance of Vector. You're then reusing that instance for every line, and clearing it at the end.
Just declare your keywords variable inside the loop, create a new instance on every iteration, and don't clear it afterwards.
To make your code as readable as possible (and avoid this sort of thing) I would suggest you declare every variable at the point of first use wherever possible, with the narrowest possible scope.
Could you try this snippet and check whether the error is still there:
public void test() {
Vector<String> keywords = new Vector<String>();
keywords.add("keyword");
Book bk = new Book("Author", "Title", 12345, keywords);
Graph bookGraph = new Graph();
bookGraph.addBook(bk);
bookGraph.showKeywords();
}
I think you got lost in your graph of objects :) I suggest to use unit tests to determine how your code should behave and to make sure it actually does behave the way you expect. The tests can build small examples and then check the various getters to see whether they return the correct results.
For what do you need the copy constructor Book(Book)? Perhaps you put copies of the books instead of the books itself into your collection?