ArrayList is being overwritten - java

I am trying to add a new train to my arraylist but upon adding the train, the existing content of the arraylist gets overwritten by the new input. This results in having only one item in the arraylist without being able to add more without overwriting the other. As I do not quite know what the source of this problem in the code is, I came looking for help here.
Within this class the train is being made:
public class RCommand extends RBaseListener {
Company mycompany = new Company("traincompany");
#Override
public void enterNewtraincommand(RParser.NewtraincommandContext ctx) {
System.out.println("Now creating new train " + ctx.getText());
mycompany.addTrainTo(new Train(ctx.getChild(2).toString()));
System.out.println(mycompany.getTrains().size());
}
}
In this class the train is supposed to be added to the list.
public class Company{
private String name;
List<Train>trains = new ArrayList<Train>();
public void addTrainTo(Train train) {
trains.add(train);
for (Train t :trains) {
System.out.println(t.getName());
}
}
}

Simply test for your class Company to see if if work
public class Test {
Company company = new Company();
public static void main(String[] args) {
Test test = new Test();
test.start();
}
private void start() {
System.out.println("IT work");
company.addTrainTo(new Train("One"));
System.out.println("End first add");
company.addTrainTo(new Train("two"));
System.out.println("End second add\n");
System.out.println("Follow example will not work");
company = new Company();
company.addTrainTo(new Train("One"));
System.out.println("End first add");
company = new Company(); // <--- create the ERROR
company.addTrainTo(new Train("two"));
System.out.println("End second add");
}
}
Suppose we have train as is:
public class Train {
private String name;
public Train(String name) {
this.name = "Train" + name;
}
public String getName() {
return name;
}
}
Output is:
IT work
Train One
End first add
Train One
Train two
End second add (it work fine)
Follow example will not work
Train One
End first add
Train two
End second add<- we miss the first train because we recreate the company instance
So it work.
So the error is not in this class Company.
Check if the caller of Company recreate the class Company before adding new train
Check class train if it has something strange (static attribute for name or similar)

Looks like new "trains" object is being created for each addition. After adding, try to print the address of "trains" object to find out for sure. You can print the address by System.out.println("trains address is: " + trains)

You did't pass for us all your code required but I think, you should create a Company constructor with your train List.
Something like that:
public class Company{
private String name;
List<Train>trains;
public Company(String name, List<Train> trains){
this.name = name;
this.trains = trains;
}
...
}
Then in your RCommand class use your new Constructor
Company mycompany = new Company(new ArrayList<Train> ,"traincompany");
And it will be fine. Your mistake in code is creating new trains list every time by calling new operator.

Related

Is there a better way of accessing ArrayList object elements?

Took me a bit to figure this out but Im just wondering if there is a cleaner way to do this
this is the gist of my main
public class Main {
private static Bank Chase = new Bank();
//This is the function in main to add a transaction to a specified customer of a branch
public static void addTransaction() {
System.out.println("Enter the name of the branch");
String branch = scanner.nextLine();
System.out.println("Enter the name of the person");
String name = scanner.nextLine();
System.out.println("Enter the amount you would like to add");
double amount = scanner.nextDouble();
scanner.nextLine();
Chase.getBranchList().get(Chase.branchIndex(branch)).getCustomerList().get(Chase.getBranchList().get(Chase.branchIndex(branch)).customerIndex(name)).addTransaction(amount);
}
}
This last line is really long and confusing to others this is what it does
//gets the branchlist -> gets the specified branch -> gets the customerlist -> finds the specified customer -> adds transaction
these are the other relevant parts of the classes the function references
public class Bank {
private ArrayList<Branch> branchList = new ArrayList<Branch>();
public ArrayList<Branch> getBranchList() {
return branchList;
}
public int branchIndex(String name){
for(Branch branch: branchList){
if(branch.getName().equals(name)){
return branchList.indexOf(branch);
}
}
return -1;
}
}
public class Branch {
private String branchName;
private ArrayList<Customer> customerList;
public ArrayList<Customer> getCustomerList() {
return customerList;
}
public int customerIndex(String name){
for(Customer customer: customerList){
if(customer.getName().equals(name)){
return customerList.indexOf(customer);
}
}
return -1;
}
public class Customer {
private String customerName;
private ArrayList<Double> transactions = new ArrayList<Double>();
public Customer(String customerName, double amount) {
this.customerName = customerName;
this.transactions = new ArrayList<Double>();
transactions.add(amount);
}
public String getName() {
return customerName;
}
public void addTransaction(double transaction){
transactions.add(transaction);
}
}
So is there any more readable way of accessing these elements that are in object ArrayLists? I think the last line in addTransaction() looks a bit redundant.
Rather than one long line you could
a) split the code into multiple lines
Chase.getBranchList().get(Chase.branchIndex(branch))
.getCustomerList()
.get(Chase.getBranchList()
.get(Chase.branchIndex(branch))
.customerIndex(name))
.addTransaction(amount);
b) stored the returned values of each get into a local variable, especially the code that it re-calling the same methods e.g. Chase.branchIndex(branch) and Chase.getBranchList()
At the moment you are assuming unique customer/branch names, and then cycling through your array list to find the customer by name. This assumption is fine, if it's a valid assumption but could mean that there are more optimal solutions. I would recommend a refactor of your code to utilise a java hash map:
https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
Basically, this will mean that you can access the customer/bank directly by name and will simplify your code greatly! It will also have performance benefits.
For your scenario this refactor would look similar to this:
public class Branch
{
private HashMap<String, Customer> _customers;
private String _branchName;
public Branch(String branchName)
{
_branchName = branchName;
_customers = new HashMap<String, Customer>();
}
public Customer getCustomer(String customerName)
{
return _customers.get(customerName);
}
}
If you follow the same for Bank, you should be able to access a Customer and add a transaction as follows:
Chase.getBranch(branch).getCustomer(name).addTransaction(transaction);
Let me know if you need help converting Bank :)
You are on the right track, but you've got some minor design flaws.
Step 1: Add a method called getBranchByName(String branchName) to your Bank class that returns a Branch object and get rid of your branchIndex() method:
public Branch getBranchByName(String branchName) {
return branchList.stream()
.filter(branch -> branch.getBranchName().equals(branchName))
.findAny()
.get();
}
Step 2: Add a method called getCustomerByName(String name) to your Customer class that returns a Customer object and get rid of your customerIndex() method:
public Customer getCustomerByName(String name) {
return customerList.stream()
.filter(customer -> customer.getCustomerName().equals(name))
.findAny()
.get();
}
Step 3: Now, method call in your main() method becomes more compact, simple and easy to read:
Chase.getBranchByName(branchName).getCustomerByName(customerName).addTransaction(amount);
Note: I've used Java 8 streams as you can observe. If you are not allowed to use Java 8 streams, you can just stick with classic imperative style of programming by writing for() loops as you have done earlier. As a quick example, if you want to write getBranchByName(String branchName) in old fashioned Java 7 style, your loop looks like this:
for(Branch branch : branchList) {
if(branch.getBranchName().equals(branchName)){
return branch;
}
}

I am trying to implement OOP concepts with java

When i try to compile an aggregation program , i receive an error saying "class,interface,enum expected". Here is my code. please help me solve this issue.
class employee
{
private String name;
private String address;
private float salary;
public employee(String na, String add,float sal)
{
name = na;
address = add;
salary = sal;
}
public void showEmpDetails()
{
System.out.println("Name " + name);
System.out.println("Address " + address);
System.out.println("Salary " + salary );
System.out.println();
}
}
import java.util.vector;
class company
{
private String comname;
private vector vt;
public company(String na)
{
comname = na;
vt = new vector();
}
public void addEmployee(employee e)
{
vt.addElement(e);
}
public void showComDetails()
{
System.out.println("Company Name " + comname);
int x = vt.size();
int y = 0;
while(y<x)
{
object e = vt.elementAt(y);
e.showEmpDetails();
y++;
}
}
}
public class demo
{
public static void main(String[] args)
{
employee e1 = new employee("Ashan","Kandy",2000.0f);
employee e2 = new employee("Steve","California",2500.0f);
employee e3 = new employee("Elon","South Africa",2500.0f);
company c1 = new company("Apple");
c1.addEmployee(e1);
c1.addEmployee(e2);
c1.addEmployee(e3);
c1.showComDetails();
}
}
Note:- i receive only one error. and also can anybody tell me why can't i have more than one public class in java.
Well, your code has more than one error actually. The reason for your specific error is that import should be at beginning of the file, not in the middle.
And my understanding of why only one public class is allowed for each file is:
It makes things clearer.
By reading the class name and document to this class, you could quickly know what the whole file is used for. If we allow multiple public classes in one file, like C++, then we have to jump inside of the file to understand it.
Notice Java is a strong object-oriented language, i.e. everything in Java is Object. So when importing, you are importing a file. It would be more complicated if one file contains multiple public classes.
It simplify testing.
Each public class could have a main function. And you could run any main function of a file Demo.java simply by java Demo. This is really nice, so that you could write test code, or example of usage in main function to show other contributor how this class should be used.
There have to be other more in-depth reason for single public class in Java. But these are my perspective.

Infinite loop when trying to populate a list of no more than two Hospitals

In this project the user must enter 1 or 2 hospitals but not 3 or more. So the program starts and I display a menu. If the user presses 1 he must enter a hospital(name and department). After this the program displays the menu again and the user can choose to insert another hospital.
But after that, if I choose to insert another one (which is not permitted) the program accepts it. It seems that every time InsertHospitals() is called from the main class, the value of numberofhospitals (which is a counter counting how many hospitals I entered) equals 0.
public class Hospital {
private String Name, Departments;
private char flag;
private int numberofhospitals;
private Hospital[] ListOfHospitals;
//private Patient[] ListOfPatiens;
//private Doctor[] ListOfDoctors;
//private Examination[] ListOfExaminations;
//private Folder[] ListOfFolders;
public Hospital(String Name, String Departments)
{
this.Name=Name;
this.Departments=Departments;
}
public Hospital()
{
ListOfHospitals = new Hospital[2];
//ListOfPatiens = new Patient[100];
//ListOfDoctors = new Doctor[100];
//ListOfExaminations = new Examination[100];
//ListOfFolders = new Folder[100];
}
public String getName()
{
return Name;
}
public void setname(String Name)
{
this.Name=Name;
}
public String getDepartments()
{
return Departments;
}
public void setdepartments(String Departments)
{
this.Departments=Departments;
}
public void InsertHospitals()
{
if(numberofhospitals==2)
{
System.out.println("You can give only two hospitals!");
}
else
{
String temp = sir.readString("Hospital's Name:");
Name=temp;
String temp1 = sir.readString("Hospital's departments:");
Departments=temp1;
Hospital hospital = new Hospital(Name, Departments);
ListOfHospitals[numberofhospitals]=hospital;
numberofhospitals=numberofhospitals+1;
}
}
}
Your misunderstanding something, the list of hospitals (as mentioned) should not be inside your hospital class. You have to consider your hospital class as a blueprint you are using in your application.
Which means that you need to have a list of hospitals, as a list inside your other application class (which runs the application) and the InsertHospitals method should not be in your hospital class either obviously.
As you add a new hospital in your program, you create a new hospital object and add it to the list of hospitals (fx an arraylist) your keeping as a field value.
Also posssibly make a new constructor with parameters in the hospital class so you can insert the values outside of the class.
Something like this fx.
public class MainApp {
private ArrayList<Hospital> hospitalList;
public static void main(String[] args) {
// Initialize or load it from a file or whatever here.
hospitalList = new ArrayList<Hospital>();
// your code here...
}
public void insertHospital(<insert parameters here to create a hospital>) {
Hospital newHospital = new Hospital(<insert params with new constructor>);
hospitalList.add(newHospital);
}
}
Whatever your problem, your program completely wrong. In insertHospital() your changing Name and Departments fields, and creating new Hospital with those values. When you print Hospital information all hospitals will have the same value.

Stuck on a Homework using ArrayDeque and Threads in Java?

This is my Question
A health center has employed two doctors that examine and treat at most 25 patients in a day.
A patient is examined and treated by any one of the two doctors. Each patient has to register his name so that the doctors can examine and treat the patient on first-come-first-serve bases.
Exercise 2
Part a: For the scenario2 mentioned above, develop a program that creates patients and doctors (both are threads). Patients register in a queue and the doctors pick patient from the same queue on first-come-first-serve bases and examine and treat them. Use the queue that is not thread safe (For example ArrayDeque). Make sure your program has no synchronization issues.
Part b: Use the queue that is thread safe (For example, ArrayBlockedQueue) and check if your solution has synchronization issues. (Make sure that you solution does not provide synchronized methods or synchronized blocks)
This is my CODE
package lab8;
import java.util.ArrayDeque;
public class LAB8 {
class Doctor implements Runnable {
private String name;
private Patient patient;
Doctor (String n){
name = n;
}
public void examine (){
System.out.println("Doctor is now examining the patient");
}
public void treat(){
System.out.println("Doctor is now treating the patient");
}
#Override
public void run (){
}
}
static class Patient implements Runnable {
private String name;
Patient (String n){
name = n;
}
public void register(String name){
System.out.println(name + " is registering in Queue");
}
#Override
public void run(){
ArrayDeque<Patient> Patients = new ArrayDeque(25);
for(int i = 0;i<25;i++){
Patients.add(new Patient("Patient No " + i));
Patients.removeFirst().register("Patient No " + i);
}
}
}
public static void main(String[] args) {
ArrayDeque<Patient> Patients = new ArrayDeque(25);
for(int i = 0;i<25;i++){
(new Thread (Patients.removeFirst())).start();
}
}
}
This is the error I am getting when I run it.
Exception in thread "main" java.util.NoSuchElementException
at java.util.ArrayDeque.removeFirst(ArrayDeque.java:278)
at lab8.LAB8.main(LAB8.java:50)
Java Result: 1
I am only trying Part A right now.
In your main function, the Patients ArrayDeque object has no Patient objects. Rather it is empty, so there is nothing to remove from the queue. You need to add some Patients first.
ArrayDeque<Patient> Patients = new ArrayDeque(25);
for(int i = 0;i<25;i++){
(new Thread (Patients.removeFirst())).start();
}
You would need to add new Patients to the Patients ArrayDeque first like you do here.
Patients.add(new Patient("Patient No " + i));
So you have have something like this...
public static void main(String[] args) {
ArrayDeque<Patient> Patients = new ArrayDeque(25);
for(int i = 0;i<25;i++){
Patient p = new Patient("Patient No " + i);
(new Thread (p)).start();
Patients.add(p);
}
}

Deep Copy of Object Array Instance, Java

I have an object made in my main Recipe recipeOne = new Recipe("Pepperoni Pizza");
This object is an instance of this Object Array defined and constructed here!
public class Recipe implements Cloneable{
String Name;
final int INGREDIENT_ARRAY_MAX = 10;
Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];
public Recipe(String name){
Name = name;
}
So I am looking to make a deep copy of this object with the line Recipe ressippi = (Recipe) recipe.clone(); and it sends me here!
public Object clone(){
Recipe cloneRec = new Recipe(Name);
return cloneRec;
}
I know this is currently a shallow copy because the method only passes references, so if I was to attempt a name change on my new Object that was a clone of recipeOne...it would change both of their names. Obviously I do not want that, I'm fairly lost on this, can anyone help?
EDIT:#Rohit Jain
Both my Recipe class as well as my Ingredient class (the objects the recipe array holds) have toString methods and recipes calls on ingredients in order to print it all out in a nice little format. When I call it on my "recipeOne" object (the one called pepperoni pizza) i get "Pepperoni Pizza: 1.0 Pounds of Dough, 8.0 Ounces of Sauce, 10.0 Ounces of Cheese"
Then I proceed to make the object ressippi and set that to the clone of recipeOne, so all good from here...then I change ressippi's name to "Pineapple Pizza" and that prints out fine but it doesnt print the 3 ingredient objects that recipeOne stored, which it is suppose to do!
Add a copy constructor to the recipe class, which creates a new instance of recipe and copies all of the fields from an original recipe.
Recipe.java
public class Recipe implements Cloneable {
String name;
final int INGREDIENT_ARRAY_MAX = 10;
Ingredient[] ingredients = new Ingredient[INGREDIENT_ARRAY_MAX];
public Recipe(String name) {
this.name = name;
}
//Copy Constructor
private Recipe(Recipe recipe){
this.name = recipe.name;
for(int x = 0; x < recipe.ingredients.length; x++){
this.ingredients[x] = recipe.ingredients[x];
}
}
public static Recipe newInstance(Recipe recipe){
return new Recipe(recipe);
}
//Debug Method
public static void printRecipe(Recipe recipe){
System.out.println("Recipe: " + recipe.name);
for(Ingredient i:recipe.ingredients){
if(i != null && i.getName() != null){
System.out.println("Ingredient: " + i.getName());
}
}
}
//Test Method
public static void main(String[] args) {
Recipe recipe = new Recipe("Chicken Soup");
recipe.ingredients[0] = new Ingredient("Chicken");
recipe.ingredients[1] = new Ingredient("Broth");
Recipe copy = new Recipe(recipe);
copy.ingredients[2] = new Ingredient("Rice");
copy.name = "Chicken Rice Soup";
printRecipe(recipe);
printRecipe(copy);
System.out.println(recipe == copy);
System.out.println(recipe.ingredients == copy.ingredients);
}
}
Ingredient.java
public class Ingredient {
private String name;
public Ingredient(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
As you have found out, implementing the Cloneable doesn't actually clone the object. You'll have to implement the clone() method sensibly, and if you want a deep copy, that's what you should implement.
Now, creating a new Recipe object with the same Name attribute is quite OK. And changing the name for the new object afterwards is also quite okay, it won't change the name of the first object as java String's are immutable.
You may want to have a look at the commons-beanutils package, which provides handy code for cloning objects.
Finally, as for "...only passes references..." you should read eg. this and this thread.
Cheers,
Serialize it! Take a look at the deepClone function as exampled here: http://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html
The other replies on Strings being immutable are true of course, but the problem you tried to describe with the String example was just a bad example; complexer objects like the Ingredients array still is copied-by-reference.
Also: change the name of your array so that it doesn't match the class name (=confusing):
Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];

Categories

Resources