Java Programming Logic Bug with ArrayList

JC0133

Senior member
Nov 2, 2010
201
1
76
I am trying to write a program where I read in data from a file and print it to the screen. While I am trying to do A LOT more then that but I write test cases every step of the way.

I was able to pull the code in from the file. I use a function to do that.

In the same function I pass in an arraylist of a object that I am using to store the data. I test that the data is getting put into the arraylist in the function and in the main function where I call it.

I see that in the function it is working correctly but in the main function it is printing out the same line over and over again. It would seem that I copied in the last line every single time I read in a line from the file but that is not the case in the function I am using to get the data.

Not sure what is going on here?

Also what is the difference between a List and a ArrayList, I noticed I can use the inter changeably.

Code:
import java.io.*;
import java.util.*;


public class LottoCalculations {

   public static void main(String[] args)   {
       // TODO Auto-generated method stub

       // create ArrayList to store the lottoNumbers objects
       List<LottoNumbers> lPowerNumbers = new ArrayList<>();
       ArrayList<LottoNumbers> lMNumbers = new ArrayList<>();
     
     

     
        new LottoCalculations().storePowerNumbers(lPowerNumbers);
   
       //test case
       /*
       for(int i=0; i<lPowerNumbers.size();i++) {
           System.out.println(lPowerNumbers.get(i).firstNum + " " + lPowerNumbers.get(i).secondNum  + " " + lPowerNumbers.get(i).thirdNum  + " " +
       lPowerNumbers.get(i).fourthNum  + " " + lPowerNumbers.get(i).fifthNum  + " " + lPowerNumbers.get(i).megaBallpowerBall);
       }
      doesn't work */
     
//Test Case
       System.out.println(lPowerNumbers.get(0).firstNum + " " + lPowerNumbers.get(0).secondNum  + " " + lPowerNumbers.get(0).thirdNum  + " " +
               lPowerNumbers.get(0).fourthNum  + " " + lPowerNumbers.get(0).fifthNum  + " " + lPowerNumbers.get(0).megaBallpowerBall);
  //Test Case     
       System.out.println(lPowerNumbers.get(1).firstNum + " " + lPowerNumbers.get(1).secondNum  + " " + lPowerNumbers.get(1).thirdNum  + " " +
               lPowerNumbers.get(1).fourthNum  + " " + lPowerNumbers.get(1).fifthNum  + " " + lPowerNumbers.get(1).megaBallpowerBall);
     

   }//end of main
   
   public void storePowerNumbers(List<LottoNumbers> lPowerNumbers) {
     
       //CoffeeCup cup1 = new CoffeeCup();
       LottoNumbers storeValues = new LottoNumbers();
       try {
           // create a Buffered Reader object instance with a FileReader
           BufferedReader br = new BufferedReader(new FileReader("Numbers.txt"));

           // read the first line from the text file
           String fileRead = br.readLine();
           int i = 0;
         
           while(fileRead != null) {
               // use string.split to load a string array with the values from each line of
               // the file, using a comma as the delimiter
               String[] eachNumber = fileRead.split("    ");
             
               storeValues.firstNum = Integer.parseInt(eachNumber[0]);
               storeValues.secondNum = Integer.parseInt(eachNumber[1]);
               storeValues.thirdNum = Integer.parseInt(eachNumber[2]);
               storeValues.fourthNum = Integer.parseInt(eachNumber[3]);
               storeValues.fifthNum = Integer.parseInt(eachNumber[4]);
               storeValues.megaBallpowerBall = Integer.parseInt(eachNumber[5]);
             
               lPowerNumbers.add(storeValues);
             
//TEST CASE THAT WORKS
               System.out.println(lPowerNumbers.get(i).firstNum + " " + lPowerNumbers.get(i).secondNum  + " " + lPowerNumbers.get(i).thirdNum  + " " +
                       lPowerNumbers.get(i).fourthNum  + " " + lPowerNumbers.get(i).fifthNum  + " " + lPowerNumbers.get(i).megaBallpowerBall);

             
            // read next line before looping
               // if end of file reached
               fileRead = br.readLine();
               i++;
             
           }
       }//end of try statement block
    // handle exceptions
       catch (FileNotFoundException ex)
       {
           System.out.println("file not found");
       }

       catch (IOException ioe)
       {
           ioe.printStackTrace();
       }
     
     
   }//end of storePowerNumbers function
   
}//end of main class
 
  • Like
Reactions: Edward_01S

purbeast0

No Lifer
Sep 13, 2001
53,764
6,645
126
It's been a while since I've done Java but I didn't think everything was passed around by reference.

Why don't you make the storePowerNumbers method take no parameters and just return the list, instead of passing in an empty list that you fill out?

As for your List vs. ArrayList question, List is an interface that ArrayList implements. They also aren't interchangeable. You can refer to an ArrayList as a List, but you can't refer to a List as an ArrayList.
 

Mr Evil

Senior member
Jul 24, 2015
464
187
116
mrevil.asvachin.com
The problem is that you create one LottoNumbers object, then you repeatedly mutate it and add it to the list. At the end, every entry in the list refers to that one object, which will contain the last numbers that were assigned to it.

If I was writing this, I would make the LottoNumbers class immutable so that the compiler would prevent you from making this mistake in the first place.

It's been a while since I've done Java but I didn't think everything was passed around by reference...
Java passes references to objects, so lPowerNumbers refers to the same object in both main and storePowerNumbers.
 

purbeast0

No Lifer
Sep 13, 2001
53,764
6,645
126
Gotcha.

And yeah I see what you are saying, makes total sense now.

Moving

Code:
LottoNumbers storeValues = new LottoNumbers();

Into the while loop should fix the bug, although that's still not the only change I would make to this algorithm.
 
  • Like
Reactions: Edward_01S

dmcshane784

Junior Member
Oct 11, 2020
1
0
6
My own problem is very similar. I'm working with a ResultSet extracted from a Derby database. Having put blocks of test code at various points, it seems the issue is with adding the new object to the list each time. When I output my final list it shows 5 copies of the same object instead of 5 different objects. Immutability isn't an option as I want those objects to be mutable, and declaring and initialising the variable on the same line inside the while loop doesn't seem to cut it. Can anyone help me get to the bottom of this?

-----------------------------------------------

package quizprojectds;

import java.util.*; // Lists
import java.sql.*; // SQL

/**
* @author dmcshane784
*/
public abstract class PlayerDAL {

public static List<Player> readAllPlayers() {

String selectSQL = "SELECT * FROM PLAYERS";

List<Player> allPlayers = new ArrayList<Player>();

try {
Connection conn = DriverManager.getConnection("jdbc:derby://localhost:1527/ACCOUNTS", "dmcshane784", "---------");
Statement stat = conn.createStatement();
ResultSet result = stat.executeQuery(selectSQL);

// Declare 6 variables to be used in a loop
int userID;
String forename;
String surname;
String gender;
String password;
int highScore;

Player newPlayer;

while (result.next()) {
// NB: SQL doesn't use zero-based indexing
userID = result.getInt("UserID");
forename = result.getString("Forename"); // test // System.out.println("FORE: " + forename);
surname = result.getString("Surname");
gender = result.getString("Gender");
password = result.getString("Password");
highScore = result.getInt("HighScore");

newPlayer = new Player(userID, forename, surname, gender, password, highScore);
// test // System.out.println(newPlayer.toString());

/*
// test:
System.out.print("######");
System.out.println(newPlayer.toString());
System.out.print("######\n\n");
*/
//object added to list
allPlayers.add(newPlayer);

// test // System.out.println("SIZE OF LIST: " + allPlayers.size());
// test // System.out.println("JUST ADDED: " + newPlayer.getForename() + "\n");
// test // System.out.println("length of list: " + allPlayers.size());
/*
// test:
System.out.println("CURRENT LIST SIZE = " + allPlayers.size());
for (int i = 0; i < allPlayers.size(); i++) {
System.out.println("i=" + i + "\n" + allPlayers.get(i).toString());
}
*/
}

result.close();
conn.close(); // V IMPORTANT

} catch (SQLException sqlEx) {
System.err.println("SQL ERROR in readAllPlayers()");
sqlEx.printStackTrace();
allPlayers = null;
} catch (Exception e) {
System.err.println("NON-SQL ERROR in readAllPlayers()");
e.printStackTrace();
allPlayers = null;
}

// System.out.println("RETURNING LIST OF " + allPlayers.size() + "\n");
for (int i = 0; i < allPlayers.size(); i++) {
System.out.println("i=" + i + "\n" + allPlayers.get(i).getForename());
}

return allPlayers;
}

public static void createPlayer(Player player) {

// Create the SQL statement for INSERT
String insertSQL = "INSERT INTO PLAYERS(Forename,Surname,Gender,Password) VALUES('"
+ player.getForename() + "','"
+ player.getSurname() + "','"
+ player.getGender() + "','"
+ player.getPassword()
+ "')";

// Execute the INSERT
try {
// Create a variable to hold the newly-generated Player ID
int newPlayerID = -999;

Connection conn = DriverManager.getConnection("jdbc:derby://localhost:1527/ACCOUNTS", "dmcshane784", "Password1");
Statement stat = conn.createStatement();
stat.executeUpdate(insertSQL, Statement.RETURN_GENERATED_KEYS); // 2nd parameter turns on the ID returning function
ResultSet returnedKeys = stat.getGeneratedKeys();
System.out.println("Player successfully added");

if (returnedKeys.next()) {
newPlayerID = returnedKeys.getInt(1);
}

System.out.println("The new Player ID = " + newPlayerID);
returnedKeys.close();
conn.close(); // V IMPORTANT

} catch (SQLException sqlEx) {
System.err.println("SQL ERROR in createPlayer()");
sqlEx.printStackTrace();
} catch (Exception e) {
System.err.println("NON-SQL ERROR in createPlayer()");
e.printStackTrace();
}
}
}

-----------------------------------------------

package quizprojectds;

/**
* @author dmcshane784
*/
public class Player {

// ATTRIBUTES //////////////////////////////////////////////////////////////
private static int userID;
private static String forename;
private static String surname;
private static String gender;
private static String password;
private static int highScore;

// CONSTRUCTORS ////////////////////////////////////////////////////////////

// When enough values are known for instantiation
public Player(String fore, String sur, String gdr, String pwd) {
userID = -1;
forename = fore;
surname = sur;
gender = gdr;
password = pwd;
highScore = 0;
}

// When all values are known
public Player(int id, String fore, String sur, String gdr, String pwd, int hSco) {
userID = id;
forename = fore;
surname = sur;
gender = gdr;
password = pwd;
highScore = hSco;
}

// METHODS /////////////////////////////////////////////////////////////////

// ACCESSOR METHODS //

public int getUserID() {
return userID;
}

public String getForename() {
return forename;
}

public String getSurname() {
return surname;
}

public String getGender() {
return gender;
}

public String getPassword() {
return password;
}

public int getHighScore() {
return highScore;
}

// MUTATOR METHODS //

public void setUserID(int newUserID) {
userID = newUserID;
}

public void setForename(String newForename) {
forename = newForename;
}

public void setSurname(String newSurname) {
surname = newSurname;
}

public void setGender(String newGender) {
gender = newGender;
}

public void setPassword(String newPassword) {
password = newPassword;
}

public void setHighScore(int newHighScore) {
highScore = newHighScore;
}

// TO STRING //

public String toString() {
// Hide the password's characters
String hiddenPassword = "";
for (int i = 0; i < password.length(); i++) {
hiddenPassword = hiddenPassword + "*";
}

// Construct a single string representation of the player
return "\n====(" + userID + ")====" + forename.toUpperCase() + " " + surname.toUpperCase() + "================"
+ "\nUser ID:\t" + userID
+ "\nForename:\t" + forename
+ "\nSurname:\t" + surname
+ "\nGender:\t\t" + gender
+ "\nPassword:\t" + hiddenPassword
+ "\nHigh Score:\t" + highScore
+ "\n\n";
}

}
 

Aikouka

Lifer
Nov 27, 2001
30,383
912
126
My own problem is very similar. I'm working with a ResultSet extracted from a Derby database. Having put blocks of test code at various points, it seems the issue is with adding the new object to the list each time. When I output my final list it shows 5 copies of the same object instead of 5 different objects. Immutability isn't an option as I want those objects to be mutable, and declaring and initialising the variable on the same line inside the while loop doesn't seem to cut it. Can anyone help me get to the bottom of this?

May sound like an odd question, but is your source data (the database) correct?

Also, you should make sure to close things like files or database connections in a finally block, or if possible, consider using a Try with Resources instead.
 
Sep 29, 2004
18,656
68
91
Seems that you got your answer .... Try using a debugger ..... you'll learn better that way. You'll see an array full of objects with the same memory location. That's the issue essentially.