A private data member changes (become empty) mysteriously somewhere - java

I have a public class named "InvertedIndex" which has two private data members:
private HashMap<String, ArrayList<Integer>> invertedList;
private ArrayList<String> documents;
I have generated getter and setter functions for them. I have a function named "buildFromTextFile" which fills both of the data members, and I have another function called "processQuery". I wrote a test unit in class "InvertedIndexTest" for processQuery which is as follows:
#Test
public void testProcessQuery() throws IOException{
InvertedIndex invertedIndex = new InvertedIndex();
String query = "ryerson award";
ArrayList<String> expectedResult = new ArrayList<String>();
expectedResult.add("ryerson award ??..23847");
invertedIndex.buildFromTextFile("input.tsv");
ArrayList<String> result = processQuery(query, 5);
Assert.assertEquals(expectedResult, result);
}
In this function, in debugging mode, when the function "buildFromTextFile" is called, the code will go to the class "InvertedIndex" and fill the data members, so at the end of this function the data members has correct data in them. When the running comes back to this unit test function again if I watch invertedIndex.getInvertedList().ToString(), I can see that the data is still correct. Then the function processQuery is called, and when the running goes to the "InvertedIndex" class, and inside this function, the invertedList().ToString() is empty. It seems that all the data is lost somewhere, but I don't know where. I would appreciate your help.
This is the processQuery method:
public ArrayList<String> processQuery(String query, int k){
ArrayList<String> result = new ArrayList<String>();
ArrayList<Integer> resultIds;
String[] queryWords = query.split("\\W+");
ArrayList<Integer> list1;
resultIds = invertedList.get(queryWords[0]);
for (int i = 1; i < queryWords.length; i++) {
list1 = invertedList.get(queryWords[i]);
resultIds = intersect(list1, resultIds);
}
Collections.sort(resultIds);
for (Integer item : resultIds) {
result.add(documents.get(item));
}
return result;
}
resultIds is null when this line runs:
resultIds = invertedList.get(queryWords[0]);
I put a breaking point at the very first line of queryProcess function, and both data members are empty.

More problems with your invertedList, I see. :-)
This is actually being caused by the exact same problem you had previously:
Hashmap get function returns null
Line
ArrayList<String> result = processQuery(query, 5);
Should read
ArrayList<String> result = invertedIndex.processQuery(query, 5);
Recommend moving all your tests to a completely separate file. That would save you these field reference headaches.

Related

Creating ArrayList of objects containing ArrayLists as parameters - my code does not seem to create individual ArrayLists?

I am running into problem with a code for a text-based game. My class Locations is meant to load parameters from a "config" text file to create objects.
My current approach is:
I have created a public class with a constructor that will take the parameters of the object (location). It assigns them as this.xxx to private variables.
I have also created a public static class that parses the file, and once it has the necessary amount of parameters to create an object, it creates one by passing them to the constructor. Next, it adds that object to an ArrayList locations_list. Once all location objects were generated, the class returns the ArrayList locations_list
My static class parses the text file OK. However, when I run a test which iterates through locations_list and calls the getters for each element, the ArrayList parameters of objects are not individualized. All of the ArrayList elements return the same locations_characters.
The location_characters of all objects will have the same content, which is a list containing "characters" of all locations.
For example, if location 1 has characters 2 and 3 and location 2 has 6 and 7, my location_characters will print [2,3,6,7].
If I put a location_characters.clear(); after adding to location_list, the location_characters becomes empty for all objects.
Sample code snippets:
Public class with a constructor:
public class Locations {
private final int location_id;
private final String location_name;
private final String location_description;
private ArrayList <Integer> location_characters;
private ArrayList <Integer> location_items;
private final ArrayList <Integer> location_enter_from;
private final ArrayList <Integer> location_exit_to;
private String location_stage_name;
private final int location_stages;
private final ArrayList <String> location_stage_descriptions;
public Locations(int location_id,
String location_name,
String location_description,
ArrayList <Integer> location_characters,
ArrayList <Integer> location_items,
ArrayList <Integer> location_enter_from,
ArrayList <Integer> location_exit_to,
String location_stage_name,
int location_stages,
ArrayList <String> location_stage_descriptions) {
this.location_id = location_id;
this.location_name = location_name;
this.location_description = location_description;
this.location_characters = location_characters;
this.location_items = location_items;
this.location_enter_from = location_enter_from;
this.location_exit_to = location_exit_to;
this.location_stages = location_stages;
this.location_stage_descriptions = location_stage_descriptions;
}
... below are getters/setters....
Public static class for the loader:
public static ArrayList <Locations> load_locations() {
//These are used for parsing the text file
String line;
ArrayList <String> lines = new ArrayList<>();
//These are used to initialize local variables
int location_id = 0;
String location_name = null;
String location_description = null;
ArrayList<Integer> location_characters = new ArrayList<>();
ArrayList<Integer> location_items = new ArrayList<>();
ArrayList<Integer> location_enter_from = new ArrayList<>();
ArrayList<Integer> location_exit_to = new ArrayList<>();
String location_stage_name = null;
int location_stages = 0;
ArrayList<String> location_stage_descriptions = new ArrayList<>();
//This is used to initialize ArrayList of objects
ArrayList <Locations> location_list = new ArrayList<>();
//here goes the code for parsing the text files....
//below is a sample portion that loads i.e 2,3,4 split into ints,
//into the ArrayList location_characters....
case "location_characters":
String[] characters = values[1].split(",");
for (String character : characters) {
location_characters.add(Integer.parseInt(character));
}
i++;
break;
//continued...
//below I am passing the parameters into constructor,
//then adding the object to ArrayList location_list
}
Locations location = new Locations(location_id,
location_name,
location_description,
location_characters,
location_items,
location_enter_from,
location_exit_to,
location_stage_name,
location_stages,
location_stage_descriptions);
location_list.add(location);
i = 0;
}
}
reader.close();
}
catch (IOException e){
System.out.println("Problem reading file.");
}
return location_list;
}
I will appreciate insight and pointers to solution
Your code is incomplete, and the problem is in the code you're not showing: You're passing the same lists to all constructor calls, so all Locations objects are using the same lists for their fields.
This can be fixed by initializing Locations fields at their declarations, eg:
private List<Integer> location_characters = new ArrayList<>();
// repeat this pattern for all List fields
and not passing them lists through the constructor.
If you need to add to the list:
locationsInstance.getlocation_characters().add(foo);

How to change a array to a arraylist effectively

I have array variable declared like this:
public class carshop {
int numofcars = 0;
int maxcars = 10;
ACar[] allCars;
private CarShop;
public CarShop() { //Car Constructor
maxcars = maxE;
allCars = new ACar[maxcars];
}
}
In my coding example, every time a user adds a new car (via string input), it will increase the numofcars by 1. I have tried changing the array type into a arraylist
ArrayList<ACar> allCars = new ArrayList<ACar>(Arrays.asList());
I changed the allCars = new ACar[maxcars]; line into this: allCars = ACar.add(maxcars);
However now eclipse is giving me errors saying "The method add(int) is undefined for the type ACar".
Can you tell me what I have done wrong? Sorry if I have explained this poorly.
ACar is an array so it doesn't have the add() method and you need to insert values by doing ACar[x] = value;
If you want to easily convert an array to a List you can just do:
List<ACar> carList = Arrays.asList(allCars);
or for ArrayList specifically:
ArrayList<ACar> carList = new ArrayList<ACar>(Arrays.asList(allCars));
However you should also think about why you have both an array and an ArrayList. You could instead just be doing:
List<ACar> carList = new ArrayList<ACar>(maxCars);
The maxCars variable is optional, you don't need to set the initial size of an ArrayList unless you are trying to optimise the code.

Why am I unable to assign an embedded ArrayList<Integer> to a locally declared ArrayList<Integer>?

Sorry if the title is not clear, I'm not very good with programming jargon.
I have 2 string ArrayLists and an integer ArrayList obtained from one method which is passed to a separate method through the collection LinkedHashMap< String, List< String>>. However, when I try to set the integer ArrayList into a empty ArrayList declared in the receiving method, it shows the syntax error: "incompatible types: List< String> cannot be converted to List< Integer>".
Starter Method:
public static void main(String[] args) {
try{
LinkedHashMap lhm = new LinkedHashMap();
List<String> listEPC = new ArrayList<String>();
List<String> listTimeStamp = new ArrayList<String>();
List<Integer> listAntenna = new ArrayList<Integer>();
String tagID = "EQ5237";
String TimeStampStr = "12:23:22";
int tagAntenna = 2;
listEPC.add(tagID);
listTimeStamp.add(TimeStampStr);
listAntenna.add(tagAntenna);
lhm.put("epcs", listEPC);
lhm.put("timestamps", listTimeStamp);
lhm.put("antennas", listAntenna);
insertData insert = new insertData();
insert.insertData(lhm); //send map with values to new method
}catch(Exception e){
e.printStackTrace();
}
}
Receiving Method:
public class insertData {
public void insertData(LinkedHashMap<String, List<String>> readMap) {
List<String> listEPC = new ArrayList<String>();
List<String> listTimeStamp = new ArrayList<String>();
List<Integer> listAntenna = new ArrayList<Integer>();
String EPC = null;
String TimeStamp = null;
Integer Antenna = null;
listEPC = readMap.get("epcs");
listTimeStamp = readMap.get("timestamps");
listAntenna = readMap.get("antennas"); //error message here
for(int i=0; i<readMap.size(); i++){
EPC = listEPC.get(i);
TimeStamp = listTimeStamp.get(i);
Antenna = listAntenna.get(i);
System.out.println("Entry " + i );
System.out.println("Values: " + EPC + TimeStamp + Antenna);
}
}
}
This code works only if I change all instances of integers to strings, which is not what I would like in my actual code. Why is it so and how do I work around it?
You can't assign a List<String> to a List<Integer>. The elements are fundamentally different types.
You would need to construct a new List:
List<Integer> listOfIntegers = new ArrayList<>();
for (String entry : listOfStrings) {
listOfIntegers.add(Integer.valueOf(entry);
}
Of course, you also need to handle the possibility that elements of the list cannot be parsed as integers.
However, you are just throwing away type information by stuffing everything into a single map. It would be better to pass the three lists separately:
insertData(listEPC, listTimestamp, listAntenna);
and then you can have different list types in the method signature:
void insertData(
List<String> listEPC,
List<String> listTimestamp,
List<Integer> listAntenna) { ... }
I am going to include the proper answer at the bottom, but in regards to your question title, you'll have to change your method signature to:
LinkedHashmap<String, List<?>> readMap;
Then either cast the lists, which will cause an unsafe cast. eg.
List<String> listEPC = (List<String>)readMap.get("epcs");
Or cast the object.
List<?> listEPC = readMap.get("epcs");
Then in the loop cast.
EPC = (String)listEPC.get(i);
Note, these are not good solutions.
What you should have is one List that contains an object with all of the data's you need.
I can imagine the thought process went something along these lines, "I have these things, and they contain two strings and an integer. I will create a variable for each." Then you ask the question, "How do I create a collection of these things?"
The wrong answer to this question is, "I will make a list for each value, and match associated values by index." The correct answer is, "I will create a class to represent my data, and store that in a list." This is the basic essence of object orient programming (welcome to java).
First we design the class:
class EPCThing{
String EPC;
String timeStamp;
int Antennas;
public EPCThing(String tagId, String timeStamp, int antennas){
EPC=tagId;
this.timeStamp = timeStamp;
Antennas = antennas;
}
#Override
public String toString(){
return "Values: " + EPC + TimeStamp + Antenna
}
}
Now your program's main method will be something like.
List<EPCThing> things = new ArrayList<>();
String tagID = "EQ5237";
String TimeStampStr = "12:23:22";
int tagAntenna = 2;
EPCThing thing = new EPCThing(tagID, TimeStampStr, tagAntenna);
things.add(thing);
insertData insert = new insertData();
insert.insertData(things);
Then we can fix your insertData method
public void insertData(List<EPCThing> things) {
for(int i=0; i<things.size(); i++){
System.out.println("Entry " + i );
System.out.println("Values: " + things.get(i));
}
}

how to get value from 2d arraylist

i have arraylists named sub and main,
ArrayList main = new ArrayList();
ArrayList sub=new ArrayList();
i add value to sub and then add sub to main.
example;
sub.add(1);
sub.add(2);
main.add(sub);
now i want to get all values inside sub
so i used following one but .get(j) gives me the error get >> canot find symbol
for (int i=0;i<main.size();i++) {
System.out.println();
for (int j=0;j<sub().size();j++) {
System.out.print(main.get(i).get(j));//error line
}
}
how can i get all values inside subarray of main arraylist
When you declare a variable as
ArrayList main;
This list holds Objects. This means that main.get(i) will only return an Object, even if you add ArrayLists. That's why you get a compiler error: Object doesn't have a method named get().
To fix the problem, you need to use generics:
ArrayList<List<Integer>> main = new ArrayList<>();
ArrayList<Integer> sub=new ArrayList<>();
Now get() will return a List<Integer> which has a get() method, so the compiler error will disappear.
Generics could be your friend here:
ArrayList<ArrayList<Object>> main = new ArrayList<ArrayList<Object>>(); // or new ArrayList<>(); in Java 7+
ArrayList<Object> sub = new ArrayList<Object>(); // or new ArrayList<>();
If you can't or don't want to use generics, the solution is to cast the expression main.get(i) to an ArrayList first:
System.out.println(((ArrayList) main.get(i)).get(j));
Go through the following code
public class ArrayListDemo {
public static void main(String[] args) {
List<List<Integer>> main = new ArrayList<>();
List<Integer> sub = new ArrayList<>();
sub.add(1);
sub.add(2);
main.add(sub);
//If you want to get values in sub array list
for(int i = 0; i < 1; i++){
List<Integer> arr = main.get(i);
for(Integer val : arr) System.out.println(val + "");
}
//If you want to print all values
for(List<Integer> list : main){
for(Integer val : list) System.out.println(val + "");
}
}
}
In the above code, I had declared an ArrayList (main) to keep all Array which are having Integer values. Also i had declared an another ArrayList (sub) to keep all Integer values.
I had used ArrayList data structure because of length of the List will be changing the
run time.
Good Luck !!!

Appending my sessionId to an arrayList

Each time a new session id is created i need to save them in an array or a list, to have it as a reference.
Correct me where am i wrong
public static void main(String args[]) {
//creating an arrayList
ArrayList<String> myList = new ArrayList<String>();
try {
// calculate the sessionId
String sessionId = "b03c0-000-5h6-" + uuid.substring(0,4) + "-000000000";
myList.add(sessionId);
} catch(Exception e){
e.printStackTrace();
}
}
the elements in my arrayList are getting replaced and not appended.
Where am i wrong
You are wrong.
The List interface is designed store the values with duplicates. So you will append. If you want only unique results use Set instead.
Collection<String> myList = new HashSet<String>();
Note that List and Set are math concepts that both represent collections. In Java Collection Framework those concepts ware reproduces as classes and interfaces.
The Collection<T> is the super interfaces of Set and List. This allow you to change the behavior of your program depending on implementation.
You should also avoid using class names in variables, to have that flexibility.
If you want to "tell" other developers that the session ids storage store only unique values use
Set<String> sessionsIDs = new HashSet<String>();
If you want to "tell", that storage is in form of list (that allow repetitions) use
List<String> sessionsIDs = new ArrayList<String>();
If you want to keep that detail of implementation hidden, use collection
Collection<String> sessionsID = crateSessionStorage();
private Collection<String> crateSessionStorage() {
boolean useUniqueStorage = isUniqueStorage();
if(UseUniqueStorage) {
return new HashSet<String>();
}
return new ArrayList<String>();
}
The creation/initialization of myList in your code results to undesired behavior.
Your ArrayList can be a static instance attribute of your class instead of getting created everytime the method is invoked.
String sessionId = "b03c0-000-5h6-" + uuid.substring(0,4) + "-000000000"; myList.add(sessionId); this put in loop other when you call main() it replace full arraylis
It is happening because you are creating every time new object
ArrayList<String> myList = new ArrayList<String>(); // creates an object evrytime whem main will be called.
try {
String sessionId = "b03c0-000-5h6-" + uuid.substring(0,4)
/* from where uuid is comming?? */
+ "-000000000";
myList.add(sessionId);
// thiss will add inside new arraylist not in previous,
// because everytime it is getting new object reference
} catch(Exception e){
e.printStackTrace();
}
}

Categories