Refactoring a class using ArrayList to use HashMap (Java) - java

I was told to change everything to HashMap() instead of ArrayList() and for the most part everything worked perfect. However, I am having a problem getting this one method to work properly.
my HashMap() looks like
private HashMap critMap = new HashMap();
I have Room class and Creature class Room can have Creatures in it. The Creatures need to be able to react to certain commands which I already have methods for and should work as long as this method is right. I'm not certain to what is wrong.
This is the method with ArrayList()
public void critReactRoomStateChange2(String command, PC pc, String name) {
Creature temp = null;
for (int i = 0; i < critArr.size(); i++) {
if (!(getCreatures().get(i) instanceof PC) && !(getCreatures().get(i).getName().equals(name))) {
temp = getCreatures().get(i);
if (temp != null) {
getCreatures().get(i).reactStateChange(command, pc);
temp.checkNewRoom();
if (!temp.equals(getCreatures().get(i))) {
i--;
}
}
}
}
}
THIS IS THE METHOD AFTER I TIRED TO IMPLEMENT HashMap()
public void critReactRoomStateChange(String command, PC pc, String name) {
Creature temp = null;
if (!(getCreatures().get(name) instanceof PC)) {
temp = getCreatures().get(name);
if (temp != null) {
getCreatures().get(name).reactStateChange(command, pc);
temp.checkNewRoom();
}
}
}
the getCreatures().get(name) is taking the String name that is passed to it as a key of the hashMap to find the actual object it is referring to. As stated above my hashMap is thus the creatures name is the String(key) and the value Creature(contains other information other than name) is the value. When I call getCreature().get(name) I am looking for the Key String name and I want it to return the object Creature. If it cannot find it in the hashMap it should return null unless I'm mistaken.
I might just be missing something really simple. Any help would be greatly appreciated. If more code is needed I'd gladly edit this and put it in.
Thanks
Edit: Creature class is a is abstract and PC, Animal, NPC all extend it. Just so your not wondering what the random PC and NPC and Animals are doing. lol
Edit2: No error besides that I'm not getting the reactions. It does nothing so critReactRoomStateChange is not working now. The Creatures are not getting passed along so the other methods can act on it.
So the 2nd box of code isn't working properly. It does nothing essentially.

I see that when you were using an ArrayList you applied the method getCreatures().get(i). It could be that you didn't change the getCreatures() method after you switched to HashMap since after the change you dont need to loop and get(i).

Related

How do I store information in a method so I can use it in a different method later?

I am very new to Java, so sorry if this is stupid and obvious or worded poorly. I don't really know enough yet to know what I don't know.
So I decided that since I have to learn Java, I'd just jump in head first and try to figure it out as I go. So far, it's worked decently. I'm trying to reinforce some basic concepts I already know by writing small programs that do trivial stuff.
I decided I'd write a little text based adventure game and it's working well so far. I'm using Scanners and Switches to call methods that use Scanners and Switches to call other methods. That's all working fine.
So far it's a very linear straight line, like an old choose your own adventure book. But, I wanted to add a player inventory. I have a very vague idea of how to do it, but I have a pretty solid idea of what I want it to do.
So, basically I want to store a piece of information that says the player has a specific item. I want to be able to test for the presence of more than one item at once. And I want to be able to tell the player what items he has at any point in the game.
I don't really know how to ask the question better.
My best guess is doing something like
int key, potion;
key = 0
potion = 2
and then testing the values of each one
if (key = 0) {
System.out.println("you don't have the key ");
}
if (key > 0) {
System.out.prinln("You unlock the door");
}
I'm doing each new room as a separate method, so the whole game is just a big chain of methods. So my hope is that the information about items can be stored in a separate method that I can access through switches or if/else in the current room method the player is in. So, the player is unlocking a door in room2, which is its own method, and he picked up the key in room1, which is its own method, and the key is stored as an integer in the inventory method. But the key was one use, so the key integer is set to 0 and the method room3 starts. If that makes any sense.
Again, sorry if this is really stupid basic stuff. I'm very new to programming.
No problem and I applaud you for choosing to learn programming. This is basic data structures. If you want to hold a value, in most programming languages, you'll have an array. I think breaking your logic down is a good idea i.e., (store an item, test for > 1, list items). The first step is making this as simple as possible and than maybe adding getters/setters later through refactors. Ultimately, your goal is to make the most basic code work first (like this) and than refactoring towards an object oriented class with getters/setters and/or a HashMap.
1:
public class PlayerInventory
{
private String[] inventoryStr = new String[20]; // basic implementation
inventoryStr[0] = "Phone";
inventoryStr[0] = "Book";
}
2:
int arrayLength = inventoryStr.length;
3:
for(int i=0; i < inventoryStr.length; i++) {
System.out.println( inventoryStr[i] );
}
Refactor (after you write unit tests for this)
1*: (with a list)
import java.util.*;
import java.util.*;
public class CollectionGetterSetter {
private List<String> playerInventory;
public void setPlayerInventory(List<String> inv) {
this.playerInventory = inv;
}
public List<String> getPlayerInventory() {
return this.playerInventory;
}
public static void main(String[] args) {
CollectionGetterSetter app = new CollectionGetterSetter();
List<String> PlayerInventory = new ArrayList();
PlayerInventory.add("phone");
PlayerInventory.add("book");
PlayerInventory.add("glasses");
PlayerInventory.add("nav");
app.setPlayerInventory(PlayerInventory);
System.out.println("Player 1: " + PlayerInventory);
List<String> PlayerInventory2 = new ArrayList();
PlayerInventory2.add("cap");
PlayerInventory2.add("gown");
PlayerInventory2.add("foo");
PlayerInventory2.add("bar");
}
}

How to copy the contents of an ArrayList in another ArrayList

public boolean isConnectedTo(Suspect aSuspect){
boolean flag = false;
Registry tempRegistry = new Registry();
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
for(Communication comms : TempComms) {
System.out.println("here");
for(String PhoneNums : phoneNumbers){
if(PhoneNums.equals(comms.GetTransmitter())) {
for(String numbers : aSuspect.getNumbersList()) {
if(numbers.equals(comms.GetReceiver()))
flag = true;
}
}
}
}
return flag;
}
So I am trying to create a program that among other things, it will search two ArrayLists(TempComs and phoneNumbers) and it will return true or false whether a string in the first is the same with a string in the second or not. I create the new ArrayList TempComms with the method tempRegistry.GetComms(). GetComms() is a method in another class, (class Registry) and has just a return communications; command, communications is an ArrayList in the class Registry.(The ArrayList phoneNumbers is an arrayList of the class the code is into.) So normally with with
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
the ArrayList TempComms must be the same with ArrayList communication that exists in the other class. But I figured out that for some reason the problem is in TempComms, because the first for is never running(For that reason I used System.out.println("here"); but it never printed). I searched and tried a lot to find the solution of this problem of my own, but I didn't manage to make some progress, so I would be grateful if someone who knows where's the problem or what I do wrong tell me about it. Thanks anyway.
You are creating a new instance of the Registry which contains a list (comms).
Registry tempRegistry = new Registry();
Then you are trying to get that comm list by calling tempRegistry.GetComms() .
Unless you are populating this communication list in the constructor Registry() (not only instantiating, you should add some entries as well),
that list will be empty when for loop is called.
(Because you are clearly NOT populating it after creating the instance tempRegistry and before calling the for loop.
ArrayList<Communication> TempComms = new ArrayList<Communication>(tempRegistry.GetComms());
for(Communication comms : TempComms) {
Therefore, the TempComms list is also an empty list. Which is why the inside code of the for loop is not executing.

How to adding two method returns together

Ok, So I have a method
public static int getTotalLegCountDog (ArrayList<Dog> dogList)
{
int temp = 0;
for (int i = 0; i < dogList.size(); i++)
{
temp = dogList.get(i).getNumLegs();
totalLegsDogs += temp;
}
return totalLegsDogs;
}
It adds up the total legs of dogs and returns them as totalLegsDogs and there is another that totals the legs for cats.
Now I'd like a method that would take both the returned totalLegsDogs and returned totalLegsCats and add them together. My try is below (It returns 0), any help would be great!
public int getTotalLegCount ()
{
totalLegs = totalLegsDogs + totalLegsCats;
return totalLegs;
}
Was not calling the Method correctly. The math in the Problem was solid. The problem was the Method output call.
As far as I can tell, there's nothing wrong with the methods themselves - likely you're calling getTotalLegCount before actually counting the legs.
Fix 1 (preferred): Have getTotalLegCount call the methods.
public int getTotalLegCount (ArrayList<Dog> dogList, ArrayList<Cat> catList) {
totalLegs = getTotalLegCountDog(dogList) + getTotalLegCountCat;
return totalLegs;
}
Fix 2: Make it very clear that the leg-counting methods are to be called first. This is the inferior solution, as it requires more effort on the future programmer's part (and that might be future-you!).
I don't think you've shown us enough of your code to do any troubleshooting. It looks like you must have a global static count for dog legs and cat legs? I can't figure out your use case, but any rate, you need to make sure both your counting methods are called before you do anything with the member variables or else they will not be initialized. Example:
DogCatCounter.getTotalLegDogCount(...);
DogCatCounter.getTotalLegCatCount(...);
new DogCatCounter().getTotalLegCount();
The result from that third line should be correct as long as no other instances of DogCatCounter have modified your static variables. In other words, if you have multiple instances of DogCatCounter, any calls to your counting methods are going to modify your global static members.

I fail junit tests because of return type (I think)

So I have a class full of junit tests and a class full of methods that perform binary operations. The tests are checking to see if I have the right values at certain points.
I am failing a lot of tests because of what I believe to be is the return type. For example I get the message
junit.framework.ComparisonFailure: null expected:<[000]> but was <[BinaryNumber#4896b555]>
If I'm understanding this it's saying that it was looking for an array containing 000 but it got a BinaryNumber (which is the required return type). To help clarify here is one of the methods.
public BinaryADT and(BinaryADT y) {
int[] homeArr = pad(((BinaryNumber) y).getNumber());
int[] awayArr = ((BinaryNumber) y).pad(getNumber());
int[] solution = new int[awayArr.length];
int i = 0;
String empty = "";
while(i < solution.length){
solution[i] = homeArr[i] & awayArr[i];
i++;
}
for(int indexF = 0; indexF < solution.length; indexF++){
empty = empty + solution[indexF];
}
System.out.println(empty);
return new BinaryNumber(empty);
}
Am I understanding this right? If not could someone please explain? I'd also like to point out that this is for my homework but I'm not asking for answers/someone to do it for me. Just a point in the right direction at most.
I will gladly clarify more if it is needed (I didn't want to bog everything down).
Also this is my first post on here. I tried to keep to the formatting suggestions but I apologize if anything is sub-par.
As suggested here is the test method
public void testAnd1()
{
BinaryADT x = new BinaryNumber("111");
BinaryADT y = new BinaryNumber("000");
BinaryADT z = x.and(y);
assertNotSame(x,z);
assertNotSame(y,z);
assertEquals("000",z.toString());
}
Whenever you see the output of "toString()" like ClassName#SomeNumber, then you can be sure that toString() method is not implemented for that class (unless toString() method implementation itself is not like this).
In your case, expected value is [000], but you are getting [BinaryNumber#4896b555].
Try to implement toString() method in BinaryNumber class and return the value from this method as per assertEquals() expects. This should solve the problem.
Can you show me your test code?
1.Your expected type is different from the actual type.
2.BinaryADT class didn't overide toString method.

How to refactor to avoid passing "special values" into a Java method?

I'm sure there must be a standard way to do this, but my attempts to search Stackoverflow have failed.
I have a method like:
public void processSomeWidgetsForUser(int userItemId) {
Iterator<Widgets> iter = allWidgets.values().iterator();
while(iter.hasNext()) {
Widget thisWidget = iter.next();
if (userItemId == -1 || thisWidget.getUsersItemId() == userItemId) {
widget.process();
}
}
}
As you can see -1 is a "special value" meaning process all. Doing this saves repeating the loop code in another method called processSomeWidgetsForAllUsers.
But I dislike special values like this because they are easy to misuse or misunderstand, which is exactly the situation what I'm having to fix now (where someone thought -1 meant something else).
I can only think of two ways to improve this.
have a constant, containing -1 called something like
Widget.ALLWIDGETS which at least is self-documenting, but doesn't
stop code from using a -1 (if someone integrates old code in, for
example)
change the method to take a list of all user ids to
process, which can be empty, but that doesn't seem great
performance-wise (would need to retrieve all user ids first and then loop through
removing. Also what happens if the number of widgets in the list changes between
retreiving the ids and removing
Is there a better way? I'm sure I'm missing something obvious.
The above code has been changed slightly, so may not compile, but you should get the gist.
Although somewhat redundant, a fairly neat self-documenting approach could be to have 3 methods rather than one;
Make your original method private, and make one small change which would be to add your static final int EXECUTE_ALL = -1 and use that in your original method, then add the two new methods;
public void processWidget(int wID) throws IllegalArgumentException {
if(wID == EXECUTE_ALL) throw new IllegalArgumentException();
originalMethod(wID);
}
public void processAllWidgets() {
originalMethod(EXECUTE_ALL);
}
It makes your class a little more cluttered, but as far as the exposed methods go, it is clearer and hopefully foolproof. You could alter it not to throw an exception and just ignore any invalid ids, that just depends on your situation.
This approach of course has the major downside that it changes how the class appears to other classes, breaking everything that currently uses the, now private, originalMethod().
Number 1 would work very nicely. Be sure to document what the variable is though, so future coders (possibly yourself) know what it means.
/**This is the explanation for the below variable*/
public final static int ALL_WIDGETS = -1;
Have an external method like so:
static boolean idRepresentsAll(int id) {
return id == -1;
}
In this case, if you decide to replace it with a different mechanism, you only replace your magic number one place in your code.
At the very least, you would want to do something like this:
public static final int ID_REPRESENTING_ALL = -1;
You can change the method signature to accept a boolean for when you want to process them all.
public void processSomeWidgets(boolean doAll, int userItemId) {
Iterator<Widgets> iter = allWidgets.values().iterator();
while(iter.hasNext()) {
Widget thisWidget = iter.next();
if (doAll || thisWidget.getUsersItemId() == userItemId) {
widget.process();
}
}
}
This makes it more explicit, and easier to read in my opinion as there are no special values.

Categories

Resources