Reputation: 1
I am kind of new to programming in Java, but am currently working on a simulator for some production process. In doing so, I found something very strange which I cannot seem to figure out and cannot find on the internet or in any other question on here.
As part of a production factory, I need a certain component to figure out if it can send items to any of its machines based on a recipe for the item. To do so, I found that using a LinkedHashMap is a nice implementation for such problems. This next piece of code describes the setup of the machines and creates the initial HashMap. It uses a list of machine configurations that each have a list of recipes that they are compatible with. The HashMap will be of the form <Recipe, List<Machine>>
so that I can find available machines by searching for the recipes of the items that arrive.
public void setupMachines(List<Config> configurationList) {
for (int i = 0; i<configurationList.size(); i++) {
Config config = configurationList.get(i);
Machine machine = new Machine(config, config.getName());
for (int j = 0; j<config.getCompatibleRecipes().size(); j++){
Recipe key = config.getCompatibleRecipes().get(j);
if (!recipeInfo.containsKey(key)) {
recipeInfo.put(key, new ArrayList<Machine>());
}
recipeInfo.get(key).add();
}
}
}
In the class of the group of machines the following piece of code is used to find a suitable machine for an item based on the recipe it got from the simulator, and sends that item from a queue to that machine.
public void checkAvailableMachinesAndRedirectItems() {
int i = 0;
while (i<queue.size()) {
Lot lot = queue.get(i);
Recipe key = lot.getRecipe();
if (recipeInfo.containsKey(key)) {
if (!recipeInfo.get(key).isEmpty()) {
Machine machine = recipeInfo.get(key).get(0);
lot.setReservedMachine(machine);
removeFromRecipeInfo(machine);
queue.remove(lot);
machine.take(lot);
}
else { i++; }
}
else { i++; }
}
}
In a test file of the simulator I have to following piece of code to build two simple recipes and the group of machines that are needed to run the simulation.
MachineGroup machineGroup = new MachineGroup();
ArrayList<Config> configurationList = new ArrayList<Config>();
//create two recipes:
Recipe recipeA = model.getSimFactory().createRecipe("RecipeA");
Recipe recipeB = model.getSimFactory().createRecipe("RecipeB");
//both recipes need to have the process step of passing through a machine
recipeA.add( new ProcessStep("MachineStep", machineGroup, ...with a bunch of variables... ) );
recipeB.add( new ProcessStep("MachineStep", machineGroup, ...with a bunch of variables... ) );
//Create two machine configurations:
Config configA = new Config(...bunch of variables...);
Config configB = new Config(...bunch of variables...);
//For this example both configs have just one compatible recipe:
configA.addCompatibleRecipe(recipeA);
configB.addCompatibleRecipe(recipeB);
//add both configs tho a list:
configurationList.add(configA);
configurationList.add(configB);
// -- THIS IS THE IMPORTANT STATEMENT -- \\
machineGroup.setupMachines(configurationList);
// *** ------- **** \\
//create a sink for deleted items that are completed:
model.getSimFactory().createProcessStepAndAddToRecipe("sinkStep", sink, recipeA);
model.getSimFactory().createProcessStepAndAddToRecipe("sinkStep", sink, recipeB);
//create a source for items with different recipes and inter arrival times:
Source sourceA = model.getSimFactory().createSource("SourceA", recipeA, 10L);
Source sourceB = model.getSimFactory().createSource("SourceB", recipeB, 8L);
engine.init(model);
model.addComponent(machineGroup);
engine.runSimulation(50L);
Which initializes a simulation (this stuff was already working properly) and using the machineGroup.setupMachines()
function to create the factory setup with initial HashMap to look something like this: {RecipeA=[MachineConfigA], RecipeB=[MachineConfigB]}
. However, the first IF-statement in the second piece of code (asking if the recipeInfo contains the recipe belonging to the lot) never returns true, even thought the HashCodes for the recipe of the lot and the recipe that is currently acting as a key value in the HashMap are identical.
Now for some reason unknown to myself I also tried this with the machineGroup.setupMachines()
function just above the engine.runSimulation()
function, and the strange thing is that the IF-statement now seems to work fine. I first thought this had something to do with adding some steps to the recipes after building the initial HashMap (source and sink), but from browsing the internet I mostly came to the conclusion that even thought the Object itself might have changed, the key value in the HashMap is only a pointer which is still pointing at the Object right? Again they have identical HashCodes.
My superior could also not figure out this behavior, but since he uses the LinkedHashMap a lot he and I would really like some more info on this topic. Does anybody know what is going on here?
I would like to repeat that I am not a javaguru yet, so simplifications and examples in your answers is much appreciated :).
Upvotes: 0
Views: 192
Reputation: 2155
Usually, this problem is related to the object you store in the Key of the HashMap. Either the class does not override hashCode()
or/and it does not override equals()
.
You should verify that the objects stored and tested are equal.
The inner comparison code may help you to understand why. (simplified Java source of HashMap.getNode()
)
do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null);
Upvotes: 1