Issues Serializing an ArrayList object containing other ArrayList objects - java

So I'm Serializing an ArrayList of ArrayLists essentially but I'm running into an issue. To be honest I'm still pretty new to Java, I've tried so many different methods to fix this as well as searched relentlessly on this site and have not been successful. I know that the way I word things may be hard to follow along or is confusing so I'll post my code here to see. Sorry in advance for all the code. SuperUsers has an arraylist of LoginInfo, PasswordKeeper has an Arraylist of SuperUsers, and the SuperUser arraylist gets serialized in PasswordKeeper. but any changes made to the LoginInfo arraylist do not save and i cannot figure out why. If anyone can help I would really Appreciate it. Thanks
public class PasswordKeeper{
private ArrayList<SuperUser> users;
private static Scanner keyboard = new Scanner(System.in);
public PasswordKeeper() {
users = new ArrayList();
}
public void login() {
try {
// reads in SuperUser arraylist
get();
} catch (EOFException a) {
System.out.println("You are the First User!");
} catch (IOException b) {
System.out.println(b);
} catch (ClassNotFoundException c) {
System.out.println(c);
}
boolean loopDisplay = true;
while (loopDisplay) {
existingUser = keyboard.next();
existingPass = keyboard.next();
SuperUser temp = new SuperUser(existingUser, existingPass);
System.out.println();
if (users.contains(temp)) {
// viewing superUser method
temp.display();
//saves after method call is over
try {
System.out.println("Saving.");
save(users);
} catch (IOException e) {
System.out.println(e);
}
}
}
//This happens if there is a new user
if(answer == 2){
SuperUser tempNew = null;
boolean cont = true;
String newUser;
String pass;
while(cont){
newUser = keyboard.nextLine();
System.out.println();
//System.out.println(users.size());
tempNew = new SuperUser(newUser, pass);
if(passValid(pass) == true){
if(makeSure(tempNew) == true){
System.out.println("Login Created!");
tempNew = new SuperUser(newUser, pass);
//actually being added to the arraylist
users.add(tempNew);
cont = false;
}
}
}
//SuperUser.display method
tempNew.display();
try{
System.out.println("Saving.");
save(users);
}catch(IOException e){
System.out.println(e);
}
}
}
}
//makeSure and passValid methods
public boolean makeSure(SuperUser user){
if(users.contains(user)){
return false;
}
return true;
}
public boolean passValid(String pass){
boolean passes = false;
String upper = "(.*[A-Z].*)";
String lower = "(.*[a-z].*)";
String numbers = "(.*[0-9].*)";
String special = "(.*[,~,!,#,#,$,%,^,&,*,(,),-,_,=,+,[,{,],},|,;,:,<,>,/,?].*$)";
if((pass.length()>15) || (pass.length() < 8)){
System.out.println("Entry must contain over 8 characters\n" +
"and less than 15.");
passes = false;
}if(!pass.matches(upper) || !pass.matches(lower)){
System.out.println("Entry must contain at least one uppercase and lowercase");
passes = false;
}if(!pass.matches(numbers)){
System.out.println("Password should contain atleast one number.");
passes = false;
}if(!pass.matches(special)){
System.out.println("Password should contain atleast one special character");
passes = false;
}else{
passes = true;
}
return passes;
//serializable methods
public void save(ArrayList<SuperUser> obj) throws IOException {
File file = new File("userInformation.dat");
FileOutputStream fileOut = new FileOutputStream(file, false);
BufferedOutputStream buffedOutput = new BufferedOutputStream(fileOut);
ObjectOutputStream out = new ObjectOutputStream(buffedOutput);
out.writeObject(obj);
out.close();
fileOut.close();
}
public ArrayList<SuperUser> get() throws IOException, ClassNotFoundException {
FileInputStream fileIn = new FileInputStream("userInformation.dat");
BufferedInputStream buffedInput = new BufferedInputStream(fileIn);
ObjectInputStream in = new ObjectInputStream(buffedInput);
users = (ArrayList<SuperUser>) in.readObject();
in.close();
fileIn.close();
return users;
}
public class SuperUser implements Serializable {
private String userName;
private String password;
private static Scanner keyboard = new Scanner(System.in);
private ArrayList<LoginInfo> info = new ArrayList();
public SuperUser(String name, String pass) {
userName = name;
password = pass;
}
public String getUser() {
return userName;
}
public void display() {
String next = keyboard.next();
//want to add data to LoginInfo arraylist
if (next.equalsIgnoreCase("add")) {
add();
} else if (next.equalsIgnoreCase("delete")) {
delete();
} else if (numberCheck(next)) {
int choice = (int) Integer.parseInt(next) - 1;
edit(choice);
//!!!! this: after doing this i lose whatever data i added
//to the LoginInfo arraylist, right after this the
//SuperUser arraylist gets saved. but the added data to
//loginInfo does not
} else if (next.equalsIgnoreCase("logout")) {
System.out.println(info.size());
}
}
public boolean numberCheck(String in) {
try {
Integer.parseInt(in);
} catch (NumberFormatException e) {
return false;
}
return true;
}
//method to add to the Arraylist
public void add() {
System.out.println("What is the website name?:");
String trash = keyboard.nextLine();
String webName = keyboard.nextLine();
System.out.println("The Username?:");
String webUsername = keyboard.nextLine();
System.out.println("The Password?:");
String webPass = keyboard.nextLine();
info.add(new LoginInfo(webUsername, webPass, webName));
System.out.println(info.size());
//method goes back to display
display();
}
}
}

Your problem is here
SuperUser temp = new SuperUser(existingUser, existingPass);
System.out.println();
if (users.contains(temp)) {
// viewing superUser method
temp.display();
You create a temporary object which with the username and password.
Your 'users.contains()' method returns true because '.equals()' is based on the username, however the 'temp' object is a different instance to that in the list.
So when you call 'temp.display()' it is not calling on an object in the list, so no data changes will save.
You need to find the existing object from the list for that user. I would suggest that you swap your list for a map keyed on username.

You have a list named users. Once you created new SuperUser instance (temp), you are checking that it belongs to this list (users.contains(temp), which is false of course - from where it will occur there?). If it have belonged, the method display would be called, which in turn would add LoginInfo to that SuperUser (add() call), but I bet in reality it doesn't happened.
Also, I see where you read from users (check whether new SuperUser instances belong there), I see where you overwrite it (during desealization) but I don't see adding any instance to there, which makes me think that it is always empty.
Are you sure that SuperUser contains any LoginInfo in its array list?

Related

Java - parsing a 2nd csv file to override a value

I have two csv files. One shows all crime data including City, State, Population etc. The other shows State and Abbreviation. I want to have the state set as the abbreviation, currently I have some very long code and I'm thinking there is definitely a better way at setting it based on the abbreviation csv file.
My main class:
public class StartApp {
public static ArrayList<CityCrime> crimes = new ArrayList<CityCrime>();
public static ArrayList<String> cities = new ArrayList<String>();
/**
* Start point for app. Directs the reads from file and shows the menu
* #param args
*/
public static void main(String[] args) {
try {
readCrimeData("crimeUSA.csv");
System.out.println("Total cities read: " + getTotalCities());
showMenu();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Reads the crime data for each city from entered file
* Adds the CityCrime objects to the crimes ArrayList
*/
public static void readCrimeData(String fromFile) {
File file = new File(fromFile);
FileReader fileReader;
BufferedReader bufferedReader;
String crimeInfo;
String[] stats;
try {
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
crimeInfo = bufferedReader.readLine();
crimeInfo = bufferedReader.readLine();
do {
CityCrime crime = new CityCrime(); // Default constructor
stats = crimeInfo.split(",");
{
if (stats[0] != null) {
crime.setCity(stats[0]);
}
if (stats[1] != null) {
crime.setState(stats[1]);
}
if (stats[2] != null) {
if (Integer.parseInt(stats[2]) >= 0) {
crime.setPopulation(Integer.parseInt(stats[2]));
}
}
if (stats[3] != null) {
if (Integer.parseInt(stats[3]) >= 0) {
crime.setMurder(Integer.parseInt(stats[3]));
}
}
if (stats[4] != null) {
if (Integer.parseInt(stats[4]) >= 0) {
crime.setRobbery(Integer.parseInt(stats[4]));
}
}
if (stats[5] != null) {
if (Integer.parseInt(stats[5]) >= 0) {
crime.setAssault(Integer.parseInt(stats[5]));
}
}
if (stats[6] != null) {
if (Integer.parseInt(stats[6]) >= 0) {
crime.setBurglary(Integer.parseInt(stats[6]));
}
}
if (stats[7] != null) {
if (Integer.parseInt(stats[7]) >= 0) {
crime.setLarceny(Integer.parseInt(stats[7]));
}
}
if (stats[8] != null) {
if (Integer.parseInt(stats[8]) >= 0) {
crime.setMotorTheft(Integer.parseInt(stats[8]));
}
}
crime.setTotalCrimes(Integer.parseInt(stats[3]), Integer.parseInt(stats[4]), Integer.parseInt(stats[5]), Integer.parseInt(stats[6]), Integer.parseInt(stats[7]), Integer.parseInt(stats[8]));
}
crimes.add(crime);
System.out.println(crime);
crimeInfo = bufferedReader.readLine();
} while (crimeInfo != null);
fileReader.close();
bufferedReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* For each crime, add the city to the cities ArrayList and return the count
*/
public static int getTotalCities() {
for(CityCrime crime : crimes) {
cities.add(crime.getCity());
}
int cityCount = cities.size();
return cityCount;
}
/**
* Displays the menu
* User can select which function they want to run
* #throws IOException
*/
#SuppressWarnings("unlikely-arg-type")
public static void showMenu() throws IOException {
#SuppressWarnings("resource")
Scanner menuSelect = new java.util.Scanner(System.in);
System.out.println("1. Display all crime stats by city");
System.out.println("2. Display all crime stats by selected city");
System.out.println("3. Display the murder stats by selected state ");
System.out.println("4. Display highest crime city - all crimes");
System.out.println("5. Display each state (in alphabetical order with the number of car thefts ");
System.out.println("6. Write / export all cities in descending order of Robbery rate ");
System.out.println("7. Quit");
System.out.println("Enter option 1-7");
#SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
int option = Integer.parseInt(menuSelect.next());
if(option<1 || option>7 ) {
System.out.println("Invalid input.");
return;
}
switch (option) {
case 1:
displayAllCityCrimeStats();
break;
case 2:
System.out.println("Enter city");
String cityOption = menuSelect.next();
displayCrimeStatsByCity(cityOption);
break;
case 3:
System.out.println("Enter state");
String stateOption = menuSelect.next();
displayMurdersByState(stateOption);
break;
case 4:
displayHighestCrimeStats();
break;
case 5:
displayStateCarThefts();
break;
case 6:
writeToFile("Robbery.csv");
break;
case 7:
return;
default:
option = Integer.parseInt(scanner.next());
}
}
My CityCrime file. It is a mess right now as I don't know what the right direction to go in is. I have cut down the setStates, there are 52 in reality so it's pretty long:
public class CityCrime {
//Instance variables
private String city;
private String state;
private int population;
private int murder;
private int robbery;
private int assault;
private int burglary;
private int larceny;
private int motorTheft;
public int totalCrimes;
public static ArrayList<CityState> abbreviations = new ArrayList<CityState>();
public String fromFile = ("C:/Users/ebeck/Downloads/StateAbbreviations.csv");
public static void main(String[] args) {
}
public static void readAbbrevData(String fromFile) {
File file = new File(fromFile);
FileReader fileReader;
BufferedReader bufferedReader;
String abbrevInfo;
String[] stats;
try {
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
abbrevInfo = bufferedReader.readLine();
abbrevInfo = bufferedReader.readLine();
do {
CityState abbrev = new CityState(); // Default constructor
stats = abbrevInfo.split(",");
{
if (stats[0] != null) {
abbrev.setState(stats[0]);
}
if (stats[1] != null) {
abbrev.setAbbreviation(stats[1]);
}
}
abbreviations.add(abbrev);
System.out.println(abbrev);
abbrevInfo = bufferedReader.readLine();
} while (abbrevInfo != null);
fileReader.close();
bufferedReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
if(state.equalsIgnoreCase("ALABAMA")) {
this.state = "AL";
}
else if(state.equalsIgnoreCase("ALASKA")) {
this.state = "AK";
}
else if(state.equalsIgnoreCase("ARIZONA")) {
this.state = "AR";
}
else if(state.equalsIgnoreCase("ARKANSAS")) {
this.state = "AR";
}
else if(state.equalsIgnoreCase("CALIFORNIA")) {
this.state = "CA";
}
else if(state.equalsIgnoreCase("COLORADO")) {
this.state = "CO";
}
else if(state.equalsIgnoreCase("CONNECTICUT")) {
this.state = "CT";
}
//etc
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
public int getMurder() {
return murder;
}
//etc
}
I created a CityState file, however may be unnecessary:
public class CityState {
private String state;
private String abbreviation;
public static void main(String[] args) {
}
public String getState() {
return state;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
public void setState(String state) {
this.state = state;
}
}
A couple reasons I want to change how I've set up the get state is 1. for my Junit test for state:
#Test
public void testValidState() {
CityCrime crimes = new CityCrime();
crimes.setState(state);
assertEquals(crimes.getState(), state);
}
I was getting the error:
expected: <A[K] but was: <A[LASKA]> if I set the state to "Alaska"
Then if I set it to "AK" I got the error:
expected: but was:
and 2. it doesn't look great either and I want to learn a better way
Thankyou for your help I appreciate it
Edit:
For each crime, if the state in CityCrimes csv file is equal to the state in the StatesAbbreviations file, then set the state as the abbreviation in the StatesAbbreviations file and return
Okay, first of all, I think it's better to split the data from the data parsing.
One class = one representation. Here CityCrime has two goals: represent quantity of crimes in a City (the goal indicated by the class name) and parse the abbreviation list. So I think it's better to create a new class whose goal is the parsing of your abbreviations.
Next, there is a consistency problem: you have a function that parse your abbreviation CSV, but you have also a list of if to "convert" a state name to a state abbreviation (setState function). There is, according to me, two ways to do this:
Define State as a type
Define State as resource
State as a type
The advantage of this method is to benefit from a strong typing. Indeed, with your setState solution, you define a State as a String, and you have to check if the passed value is correct (succession of if). Moreover, as it remains a String, you have no guarantee that the value returned by getState is formatted well (you have to trust all the functions that write on state variable).
So the solution here is to defined State as a type, using, for example, Enumeration.
public enum State {
ALABAMA("AL"),
ALASKA("AK"),
ARIZONA("AR"),
ARKANSAS("AR"),
CALIFORNIA("CA"),
COLORADO("CO"),
CONNECTICUT("CT");
private String abbreviation;
State(String abbreviation) {
this.abbreviation = abbreviation;
}
public String getAbbreviation() {
return abbreviation;
}
}
An enum is a particular type of class. Indeed, this one is not direclty instanciable (you can't do new State("foo")). The accepted instances for this type are defined as an enumeration, at the start of the class (ALABAMA, ALASKA...). So State.ALABAMA has for type State and State.ALABAMA.getAbbrevation() returns AL.
This solution works only if the set of all your states is closed, so if your have a fixed number of state.
In this situation, your state variable would have for type State, and your setState function would take a State variable. This is strong typed, because you can't pass a value that is not valid to the function (except null).
How to convert a State name to a State variable ?
Enumeration classes have a valueOf(String name) function. The parameter is the identifier of the enum constant (ALABAMA, ALASKA) as a String, and the returned value is the enum constant as State. If any enum constant was found, an IllegalArgumentException is throwed. This solution works well, but the string must correspond exactly to the identifier (case included).
If you want to do a similar function, but ignoring case, you can use values function that returns an array of all State values (State[]). For example:
public static State valueOfIgnoreCase(String name) {
for(var state: State.values())
if(state.name.equals(name)) // name function return the exact identifier of the state
return state;
return null; // Or throw IllegalArgumentException
}
This function can be create in the State class.
State as a resource
Another solution is to define State as a resource, that is, in an external file (or resource file). The advantage is you can add new State dynamically, without having to modify the program code. It's the solution you use with your parser.
For this solution, the parser is in a separated class.
Instead of put all your State in an List, you can put in a Map:
public class AbbreviationParser {
public static Map<String, State> parseState(InputStream stream) throws IOException { // InputStream is better than String or File, because it abstract the type of input (can works with a simple file, a network stream, a text downloaded from Internet...)
final var map = new HashMap<String, State>();
final var reader = new BufferedReader(new InputStreamReader(stream)); // Define a reader on the stream then bufferize it for better performance
reader.readLine();
String line;
while((line = reader.readLine()) != null) { // As long as there is an unread line
var array = line.split(",");
if(array.length == 2) {// Important, because if your line does not contain a comma, your actual code will crash at "array[1]"
var state = new State();
state.setState(array[0]);
state.setAbbreviation(array[1]);
map.put(state.getState(), state);
} else {
//TODO define a behavior if the line is not valid
}
}
reader.close();
stream.close();
return map;
}
To call this function for a File:
parseState(new FileInputStream(fromFile)); // FileInputStream is an implementation of InputStream for File
To secure your State from external instantiation, you can put the State constructor in package-only scope, and place this class and AbbreviationParser in the same package. Like this, only the class on the same package (so AbbreviationParser) can instantiate State, and you are thus sure not to have an incorrect value passed to your setState(State state):
public class State {
private String state;
private String abbreviation;
State() {}
public String getState() {
return state;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
public void setState(String state) {
this.state = state;
}
}
Even if you prefer the first method for your State, I recommend you to take inspiration from my parser for your first CSV parser and to isolate it in a separated class.
You want to replace certain values in the first CSV file with corresponding values in the second CSV file. The code will be extremely long if you use Java to perform the association.
But it is easy to do the coding job using Java’s open-source package SPL. One line of code is enough:
+
1
=file("crimeUSA.csv").import#ct().switch(State,file("StateAbbreviations.csv").import#ct():State).new(City,State.Abbreviation: StateAbbreviation,Population,Murder,Robbery,Assault,Burglary,Larceny,MotorTheft,TotalCrimes)
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as abbr.splx and invoke it in Java as you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st=con.prepareCall("call abbr()");
st.execute();
…
Or execute the SPL string within a Java program as we execute a SQL statement:
…
st = con.prepareStatement("==file(\"crimeUSA.csv\").import#ct().
switch(State,file(\"StateAbbreviations.csv\").import#ct():State)
.new(City,State.Abbreviation,Population,Murder,Robbery,Assault
,Burglary,Larceny,MotorTheft,TotalCrimes)");
st.execute();
…

Variable cannot be resolved error in Java

I know this is a very very common error but I am stuck on this one and I totally don't understand why is it happening.
Here is a part of my code
import java.util.ArrayList;
import java.util.Scanner;
public class Manager {
private static Scanner sc = new Scanner(System.in);
protected static ArrayList<String> identifications = new ArrayList<String>();
protected static String[] signIn() {
System.out.println("Hi !");
System.out.println("Welcome to School Management System");
System.out.print("Please enter your ID number : ");
boolean idValid = false;
String providedID = null;
int idListPosition = -1;
do {
try {
providedID = sc.nextLine();
} catch (Exception e) {
System.out.println("Sorry there was an error. Please try again");
System.out.print("Please enter your ID number : ");
}
} while (providedID == null);
while (idValid != true) {
for (String element : identifications) {
if (element.equals(providedID)) {
idValid = true;
idListPosition = identifications.indexOf(element);
break;
}
}
if (idValid && idListPosition != -1) {
System.out.println("Welcome !");
String[] returnValue = {"true", identifications.get(idListPosition), identifications.get(idListPosition + 1), identifications.get(idListPosition + 2)};
return (returnValue);
} else {
System.out.println("Error : the ID you entered does not exist. Please try again");
providedID = null;
do {
try {
providedID = sc.nextLine();
} catch (Exception e) {
System.out.println("Sorry there was an error. Please try again");
System.out.print("Please enter your ID number : ");
}
} while (providedID == null);
}
}
}
public static void main(String[] args) {
init();
String[] response = signIn();
if (response[2].equals("teacher")) {
Teacher user = new Teacher(response[1], response[2], response[3]);
}
if (response[2].equals("student")) {
Student user = new Student(response[1], response[2], response[3]);
}
System.out.println(user);
while(true) {
System.out.println("For help type in help");
System.out.print("Enter a command : ");
String commandWanted = sc.nextLine();
if (commandWanted.equals("info")) user.showInfos();
}
}
protected static void init() {
identifications.add("056789");
identifications.add("teacher");
identifications.add("Temperson");
}
}
The Teacher and Student classes are empty for now. I just made them use the super constructor of their parent class Person :
public class Person {
String type;
String name;
String idNumber;
public Person(String idnumber, String newType, String providedName) {
this.idNumber = idnumber;
this.type = newType;
this.name = providedName;
}
protected String[] showInfos() {
String[] returnValue = {this.type, this.name, this.idNumber};
return returnValue;
}
}
But I get user cannot be resolved to a variable and user cannot be resolved error.
Normally the code that needs user will never run unless sign in has completed. And since sign in never ends before a correct ID is entered, the user variable will always be assigned to a a value.
Thanks for helping !
The scope of the user object is limited to the if condition, hence you are getting this error.
If Teacher and Student extends Person then you can try this piece of code:
public static void main(String[] args) {
init();
String[] response = signIn();
Person user = null;
if (response[2].equals("teacher")) {
user = new Teacher(response[1], response[2], response[3]);
}
if (response[2].equals("student")) {
user = new Student(response[1], response[2], response[3]);
}
System.out.println(user);
while(true) {
System.out.println("For help type in help");
System.out.print("Enter a command : ");
String commandWanted = sc.nextLine();
if (commandWanted.equals("info")) user.showInfos();
}
}
You're having a Scope problem here:
if (response[2].equals("teacher")) {
Teacher user = new Teacher(response[1], response[2], response[3]);
}
if (response[2].equals("student")) {
Student user = new Student(response[1], response[2], response[3]);
}
System.out.println(user);
Variables declared in a if block are local to that if block. You can see this in it's simplest form with an example like this:
if(true) {
String value = "Out of Scope";
}
System.out.println(value); //value cannot be seen outside the if block
You will need to declare your Teacher and/or Student variable outside the if block if you wish to use them after the block (this is where using your inheritance class would come in handy). Using the previous example:
boolean someCondition = true;
String value;
if(someCondition) {
value = "In Scope - True";
} else {
value = "In Scope - False";
}
System.out.println(value); //value can now be seen
You have declared 2 different versions of user, so the print statement can't know which you mean. Or it couldn't if it could see either, but since each is declared inside of its own block, the print doesn't see either of them.

ArrayList and BufferedReader Note Taking Program

I have created a simple program that takes a title and a note which you enter then you have a choice to export the notes to txt file using BufferedWriter however because each note is a object which is stored in a ArrayList when storing them I iterate through a for enhanced loop it keeps duplicating each note as I iterate through all the object.
Note Class
import java.util.*;
public class Notes
{
private String notes;
private String titleOfNotes;
Scanner input = new Scanner(System.in);
public Notes()
{
titleOfNote(input);
takeNotes(input);
}
public void takeNotes(Scanner x)
{
System.out.println("Please Enter Your Note");
notes = x.nextLine();
}
public void titleOfNote(Scanner y)
{
System.out.println("Please Enter Title");
titleOfNotes = y.nextLine();
}
public String toString()
{
return "Title: " + titleOfNotes + "\t" + notes;
}
}
App Class //Does mostof the Work
import java.util.*;
import java.io.*;
public class App
{
private int exit = 0;
private int createANote;
private int displayTheNotes;
private int inputFromUser;
public boolean haveFileBeenWritten = true;
File file = new File("Notes.txt");
Scanner input = new Scanner(System.in);
ArrayList<Notes> arrayOfNotes = new ArrayList<Notes>();
public void makeNoteObject()
{
arrayOfNotes.add(new Notes());
}
public void displayAllTheNote(ArrayList<Notes> n)
{
for(Notes singleObjectOfNote : n)
{
System.out.println(singleObjectOfNote);
}
}
public void programUI(){
while(exit != 1)
{
System.out.println("1. Create A Note");
System.out.println("2. Display The Notes");
System.out.println("3. Exit");
System.out.println("4. Export to text file");
System.out.println("Enter Your Operation");
inputFromUser = input.nextInt();
if(inputFromUser == 1)
{
makeNoteObject();
}
else if(inputFromUser == 2)
{
displayAllTheNote(arrayOfNotes);
}
else if(inputFromUser == 3)
{
System.out.println("Exited");
exit = 1;
}
else if(inputFromUser == 4)
{
makeATxtFileFromNotes(arrayOfNotes);
System.out.println("Textfile created filename: " + file.toString());
}
else
{
System.out.println("You Select A Invalid Command");
}
}
}
public void makeATxtFileFromNotes(ArrayList<Notes> x)
{
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file,haveFileBeenWritten)))
{
//Problem here!
for(Notes singleObjectOfNotes : x)
{
bw.write(singleObjectOfNotes.toString());
bw.newLine();
}
}catch(IOException e)
{
System.out.println("Cant Write File: " + file.toString());
haveFileBeenWritten = false;
}
}
public App()
{
programUI();
}
public static void main(String[]args)
{
App objectOfApp = new App();
}
}
I am new to Java so my code my not be the best!
If your problem is that you only need to see current list's Notes excluding the previous', it's because of this line:
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file,haveFileBeenWritten)))
By default, haveFileBeenWritten is true so based on the FileWriter API it will APPEND on the existing file Notes.txt so if you don't want that, change it to false.
Parameters:
file - a File object to write to
append - if true, then bytes will be
written to the end of the file rather than the beginning
EDIT: To access List<> elements, use get().
Example:
int size = myList.size();
for (int i = 0 ; i < size ; i++) {
//...
Notes note = myList.get(i);
//...
}

Using Command pattern for undo and redo in ArrayLists

So I have a program where you can log in and add/remove friends to and from the friends arraylist. Also I can like a certain thing and that thing will be stored into the likes arraylist. I'm asked to make undo and redo options for whichever action I do.
So I want to add apple as a friend. After that when I select the undo option, I can undo that action so apple wouldn't be my friend. How I can approach this with a Command Pattern when the input is whatever name or word I inputted to store into the friends arraylist?
I did some research and found that using a command pattern could be my best bet since this has to be done under the Facebook Class I already have. I'm assuming I'll have to use two different stacks, but I'm getting a bit lost in the topic.
I decided to add parts of what I have so that I can get a bit more help on what I need to do and what my program does.
In the driver program
Facebook facebook1 = new Facebook();
if (userInput == 6)
{
System.out.println("Login");
String operand1 = getOperand("What is the Username? ");
String operand2 = getOperand("What is the Password? ");
System.out.println("Enter a friend to be added. ");
String operand3 = getOperand("What is the Username? ");
facebook1.friend(operand3);
}
if (userInput == 7)
{
System.out.println("Login");
String operand1 = getOperand("What is the Username? ");
String operand2 = getOperand("What is the Password? ");
System.out.println("Enter a friend to be removed. ");
String operand3 = getOperand("What is the Username? ");
facebook1.defriend(operand3);
}
if (userInput == 12)
{
System.out.println("Login");
String operand1 = getOperand("What is the Password? ");
facebook1.undo();
}
if (userInput == 13)
{
System.out.println("Login");
String operand1 = getOperand("What is the Password? ");
facebook1.redo();
}
In the Facebook Class
ArrayList<FacebookUser> recommendedFriends = new ArrayList<FacebookUser>();
void friend(String newFriend)
{
boolean positiveChecker = false;
for (int i = 0; i < recommendedFriends.size(); i++)
{
if (recommendedFriends.get(i).toString().equalsIgnoreCase(newFriend))
{
System.out.println("Error: This friend already exists.");
positiveChecker = true;
}
}
if (positiveChecker == false)
{
FacebookUser friend = new FacebookUser(newFriend, newFriend );
recommendedFriends.add(friend);
System.out.println(friend + " is now your friend.");
}
positiveChecker = false;
}
void defriend(String formerFriend)
{
boolean positiveChecker = false;
for (int i = 0; i < recommendedFriends.size(); i++)
{
if (recommendedFriends.get(i).toString().equalsIgnoreCase(formerFriend))
{
recommendedFriends.remove(i);
System.out.println(formerFriend + " has been removed from your friends list.");
positiveChecker = true;
}
if (recommendedFriends.size() == (i + 1) && recommendedFriends.get(i).toString() != formerFriend
&& positiveChecker == false)
{
System.out.println("Error: There is no friend with this username.");
}
}
positiveChecker = false;
}
public interface Command
{
public void undo();
public void redo();
}
When you undo 2 things then do a completely new action, you need to "forget" the "redo history" and replace it with the new command, right?
For example...
Add Friend Jim
Add Friend Bill
Add Friend Jill
Remove Jim
Undo
Undo
State should be "Jim" and "Bill".
So you only really need one list and a pointer to the current "command", for example...
// Note: NOT thread safe!
public class CommandStack {
private List<Command> commands = Collections.emptyList();
private int nextPointer = 0;
public void doCommand(Command command) {
List<Command> newList = new ArrayList<>(nextPointer + 1)
for(int k = 0; k < nextPointer; k++) {
newList.add(commands.get(k));
}
newList.add(command);
commands = newList;
nextPointer++;
// Do the command here, or return it to whatever called this to be done, or maybe it has already been done by now or something
// (I can only guess on what your code currently looks like...)
command.execute();
}
public boolean canUndo() {
return nextPointer > 0;
}
public void undo() {
if(canUndo()) {
nextPointer--;
Command commandToUndo = commands.get(nextPointer);
// Undo the command, or return it to whatever called this to be undone, or something
command.undo();
} else {
throw new IllegalStateExcpetion("Cannot undo");
}
}
public boolean canRedo() {
return nextPointer < commands.size();
}
public void redo() {
if(canRedo()) {
commandToDo = commands.get(nextPointer);
nextPointer++;
// Do the command, or return it to whatever called this to be re-done, or something
commandToDo.execute();
} else {
throw new IllegalStateException("Cannot redo");
}
}
}
If I had...
interface Command { /* execute / undo etc */ }
public class AddFriendCommand implements Command {
private String friendName;
// ... other fields, constructor / getters etc ...
public void execute() {
// Actually do it...
System.out.println("Added friend " + name);
}
public void undo() {
// Undo it...
System.out.println("Removed friend " + name);
}
}
public class RemoveFriendCommand implements Command {
private String friendName;
// ... other fields, constructor / getters etc ...
public void execute() {
// Actually do it, maybe throw exception if friend does not exist?
// (that would have to be a runtime exception unless you want the interface's method to throw stuff);
System.out.println("Removed friend " + name);
}
public void undo() {
// Undo it...
System.out.println("Added friend " + name);
}
}
You could repeat the sequence above using...
CommandStack stack = new CommandStack();
stack.doCommand(new AddFriendCommand("Jim"));
stack.doCommand(new AddFriendCommand("Bill"));
stack.doCommand(new AddFriendCommand("Jill"));
stack.doCommand(new RemoveFreindCommand("Jim"));
stack.undo();
stack.undo();
If you now did a new command (via doCommand) it would forget that you ever added "Jill" or removed "Jim", but instead would now remember the new command and the rest of the command history that was not undone.
Hope this helps.
You are misunderstanding how the command pattern works. You want to have a separate List of your Commands, where each instance of Command represents an action.
So you would want to have something like:
List<Command> actionStack;
and then have stuff like
public class AddCommand implements Command {
private final void List<FacebookUser> userList;
private final void FacebookUser newUser;
public AddCommand(List<FacebookUser> userList, FacebookUser newUser) {
this.userList = userList;
this.newUser = newUser;
}
#Override
public void undo() {
userList.remove(newUser);
}
#Override
public void redo() {
userList.add(newUser);
}
}

How do I store information from methods to be used in another session?

So I'm making a program that will store the meetings I've had with some kids I'm tutoring. It'll keep tabs on the meeting times, discussions, and how many hours I've done. I know how to write all the methods to do that, but my issue is that the program will only hold that information for the session that the program is open... how would I go about storing this information and accessing it after the program is closed and opened again?
This is some excerpts from a test score keeper program I did in java class that has this same issue...
public class Student {
private String name;
private int test1;
private int test2;
private int test3;
public Student() {
name = "";
test1 = 0;
test2 = 0;
test3 = 0;
}
public Student(String nm, int t1, int t2, int t3){
name = nm;
test1 = t1;
test2 = t2;
test3 = t3;
}
public Student(Student s){
name = s.name;
test1 = s.test1;
test2 = s.test2;
test3 = s.test3;
}
public void setName(String nm){
name = nm;
}
public String getName (){
return name;
}
public void setScore (int i, int score){
if (i == 1) test1 = score;
else if (i == 2) test2 = score;
else test3 = score;
}
public int getScore (int i){
if (i == 1) return test1;
else if (i == 2) return test2;
else return test3;
}
public int getAverage(){
int average;
average = (int) Math.round((test1 + test2 + test3) / 3.0);
return average;
}
public int getHighScore(){
int highScore;
highScore = test1;
if (test2 > highScore) highScore = test2;
if (test3 > highScore) highScore = test3;
return highScore;
}
public String toString(){
String str;
str = "Name: " + name + "\n" + //\n makes a newline
"Test 1: " + test1 + "\n" +
"Test 2: " + test2 + "\n" +
"Test 3: " + test3 + "\n" +
"Average: " + getAverage();
return str;
}
}
If your data is not too big or complicated - something that you could save in a Rolodex in days gone by - you can save it to a file. Add methods to your class that will format the data properly and write it to a given OutputStream or Writer or whatever. And a method that will read it back.
To write to the file, add an option "save" in your program menu, and when it's chosen, open a file, iterate through your data, and call the saving method for each of your object.
To read from the file, add an option "load" in your program menu, and when it's chosen, open a file, and use your method of reading for each object.
The method for reading can be a static method in the class, that will first see if there are any data in the file and if it can read them properly, and only if it did, will create an object and return it (otherwise return null). There are other options, but this is the one that most encapsulates the needs of the object.
There is also an option to serialize and deserialize each object and put it in an object stream.
If the data is complicated, and there are many objects with various relations between them, you should use a database. This will require learning some database design and SQL.
To demonstrate the file reading/writing idea, add to your Student class:
public void save(PrintWriter outfile) {
outfile.format("%s|%d|%d|%d%n", name, test1, test2, test3);
}
This will write a line with the fields separated by "|" (vertical bar). Of course, you'll have to make sure none of the student names has a vertical bar in it. So you'll need to modify your 4-parameter constructor and your setter:
public Student(String nm, int t1, int t2, int t3) {
name = nm.replaceAll("\\|", "");
test1 = t1;
test2 = t2;
test3 = t3;
}
public void setName(String nm) {
name = nm.replaceAll("\\|", "");
}
Now, to read the file, we add a static method:
public static Student load(BufferedReader infile) throws IOException {
String line;
line = infile.readLine();
// Check if we reached end of file
if (line == null) {
return null;
}
// Split the fields by the "|", and check that we have no less than 4
// fields.
String[] fields = line.split("\\|");
if (fields.length < 4) {
return null;
}
// Parse the test scores
int[] tests = new int[3];
for (int i = 0; i < 3; i++) {
try {
tests[i] = Integer.parseInt(fields[i + 1]);
} catch (NumberFormatException e) {
// The field is not a number. Return null as we cannot parse
// this line.
return null;
}
}
// All checks done, data ready, create a new student record and return
// it
return new Student(fields[0], tests[0], tests[1], tests[2]);
}
You can see that this is more complicated, because you need to check that everything is OK at every step. In any case when things are not OK, we return null but of course, you can decide to just display a warning and read the next line. You'll have to return null when there are no more lines, though.
So, assuming we have a List<Student> students, here is how we write it to a file. I just chose "students.txt" but you can specify a full path leading where you want it. Note how I'm making a backup of the old file before I open the new file. If something goes wrong, at least you have the previous version of the file.
File f = new File("students.txt");
if (f.exists()) {
File backup = new File("students.bak");
if ( ! f.renameTo(backup) ) {
System.err.println( "Could not create backup.");
return;
}
f = new File("students.txt");
}
try ( PrintWriter outFile = new PrintWriter(f);) {
for (Student student : students) {
student.save(outFile);
}
} catch (FileNotFoundException e) {
System.err.println("Could not open file for writing.");
return;
}
After you do this, if you look for the file "students.txt", you will see the records you wrote in it.
How about reading it? Assume we have an empty students list (not null!):
try ( BufferedReader inFile = new BufferedReader(new FileReader(f))) {
Student student;
while ( ( student = Student.load(inFile)) != null) {
students.add(student);
}
} catch (FileNotFoundException e) {
System.err.println( "Could not open file for reading.");
return;
} catch (IOException e) {
System.err.println( "An error occured while reading from the file.");
}
Having done this, you can check your students list, and unless there were errors in the file, all your records will be there.
This is a demonstration, of course. You may want to read into some other collection or instead of printing an error and returning do something else. But it should give you the idea.
You could use db4o for persisting your data. Its an object-database with a spimple api to use. You can store java object read or delete them..
Download it here DB4O
And use the snippets of this tutorial (GER):Tutorial in German
Here is an example:
and Code:
package db4o.example;
public class Student {
String name;
public Student(String name) {
this.name = name;
}
#Override
public String toString() {
return "Student Name: " + name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package db4o.example;
import java.util.List;
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
public class Main {
public static void main(String[] args) {
ObjectContainer db = Db4oEmbedded.openFile("F:\\studentDB");
saveExample(db);
readAllExample(db);
readExample(db);
deleteAllExample(db);
db.close();
}
private static void deleteAllExample(ObjectContainer db) {
System.out.println("DeleteAllExample Example:");
List<Student> allStudents =readAllExample(db);
for (Student student : allStudents) {
db.delete(student);
}
db.commit();
}
private static List<Student> readAllExample(ObjectContainer db) {
System.out.println("ReadAllExample Example:");
List<Student> allStudents = db.query(Student.class);
System.out.println("Count: " + allStudents.size());
for (Student student : allStudents) {
System.out.println(student);
}
return allStudents;
}
private static void readExample(ObjectContainer db) {
System.out.println("ReadExample Example:");
Student queryStudent = new Student("Max Mustermann");
// Gets all Students named Max Mustermann
List<Student> students = db.queryByExample(queryStudent);
System.out.println("Count: " + students.size());
for (Student student : students) {
System.out.println(student);
}
}
private static void saveExample(ObjectContainer db) {
System.out.println("Save Example:");
Student myStudent = new Student("Max Mustermann");
db.store(myStudent);
db.commit();
}
}

Categories