I am rather new in Java and I can't seem to get around the error message
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:371)
at java.util.ArrayList.get(ArrayList.java:384)
at djurfarm.Animals.huntCatMouse(Animals.java:213)
at djurfarm.Djurfarm.main(Djurfarm.java:24)
Java Result: 1
I know what it means, that the index somewhere is below or above what it should be, but I can't for the life of me figure out why this is happening. Maybe it's because I've stared myself blind and won't see where the logic fails. Any help would be greatly appreciated. Here is the code for the method:
public void huntCatMouse() {
while (!CatList.isEmpty()) {
for (int i = 0 ; i < CatList.size(); i++) {
try {
TimeUnit.MILLISECONDS.sleep(500);
int slump = MouseList.size() - 1;
int num = CatList.size() - 1;
Cat CatRemover = CatList.get(num);
Mouse aMouse = MouseList.get(slump);
if (aMouse.getStrength().equals(false)) {
System.out.println("En katt fångar en mus.");
CatList.remove(CatRemover);
MouseList.remove(aMouse);
} else if (aMouse.getStrength().equals(true)) {
System.out.println("En mus lyckas fly från en katt.");
CatList.remove(CatRemover);
MouseList.remove(aMouse);
}
} catch (InterruptedException e) {
System.out.println("Fel i CatMouse");
}
if (MouseList.isEmpty()) {
System.out.println("Empty list");
break;
}
}
}
}
int slump = MouseList.size()-1;
It seems MouseList is a empty list and size method return 0 and slump become -1 and
MouseList.remove(aMouse); // MouseList.remove(-1)
causing ArrayIndexOutOfBoundsException at -1 index.
you have put condition !CatList.isEmpty(), It might be !CatList.isEmpty() && !MouseList.isEmpty()
The error may be because of this:
int slump = MouseList.size()-1;
int num = CatList.size()-1;
Cat CatRemover = CatList.get(num);
Mouse aMouse = MouseList.get(slump);
Here you are not checking whether MouseList or CatList size is greater than 0.
So if MouseList.size() returns 0,
so int slump = MouseList.size()-1; = int slump = -1;
Now when you do MouseList.get(slump); it means you are calling MouseList.get(-1);
So it throws that exception.
So first check whether the size of the list is greater than 0 (that is not empty).
As others have pointed out, the problem is that slump is -1 when you attempt to get(slump).
The reason it gets into that state is that you are not stopping when the mouse list becomes empty. In particular, the if (...) { break; } at the end only breaks out of the inner loop. So you try the condition for the outer loop, start the inner loop again and ... OOOPs!
The obvious fix would be to test both of the lists sizes in the outer loop's condition.
But a better fix would be to get rid of the inner loop entirely. You can implement this more simply with just one level of looping.
while (!CatList.isEmpty() && !MouseList.isEmpty()) {
try {
TimeUnit.MILLISECONDS.sleep(500);
int slump = MouseList.size() - 1;
int num = CatList.size() - 1;
Cat CatRemover = CatList.get(num);
Mouse aMouse = MouseList.get(slump);
if (aMouse.getStrength().equals(false)) {
System.out.println("En katt fångar en mus.");
CatList.remove(CatRemover);
MouseList.remove(aMouse);
} else if (aMouse.getStrength().equals(true)) {
System.out.println("En mus lyckas fly från en katt.");
CatList.remove(CatRemover);
MouseList.remove(aMouse);
}
} catch (InterruptedException e) {
System.out.println("Fel i CatMouse");
}
}
While I have your attention, you need to fix the names of your local variables. Java variable names should always start with a lowercase letter ... according to the Java style guide. And try to get the indentation right. It makes your code so much easier to read.
Finally, this is really peculiar: aMouse.getStrength().equals(true).
I would infer that getStrength() returns a boolean.
Assuming that, the simple way to test if it is true is simply aMouse.getStrength().
But "strength" is not a yes/no concept in English. It is something that you quantify.
But if "strength" really is a boolean, then the JavaBeans convention says that the method should be called isStrength() not getStrength().
Related
I am doing a project for school where i need to make a game about guessing the number from the computer. The problem I have is that my code won't print out the sentence "Het is fout" Which means that they are wrong. It also wont print the sentence that they tried to many times even tho it stops when they are over the limit. My teacher won't help me so I am desperate for some help. This is the code I wrote:
while(leesinvoer() != toeval)
{
aantalkeer = aantalkeer + 1;
if(leesinvoer() == toeval)
{
System.out.println("Het is goed het goede nummer was:"+ toeval);
}
else
{
System.out.println("Het is fout");
}
if(aantalkeer > pogingen)
{
System.out.println("U heeft te vaak beprobeerd");
}
}
System.out.println(toevalsgetalmaken(grens));
}
public static int toevalsgetalmaken(int grens)
{
Random toeval = new Random();
int toevalsgetal = toeval.nextInt(grens);
return toevalsgetal;
}
public static int leesinvoer()
{
String tekst = JOptionPane.showInputDialog(null,"Doe een gok","GOKJE",3);
int getal = Integer.parseInt(tekst);
return getal;
}
Would appreciate any help
You have to invoke leesinvoer() once for each time you check it in your if() statement.
But your code is invoking leesinvoer() twice in each loop: once from while statement, and once from the if statement.
So, instead of while(leesinvoer() != toeval) do while(true), but better yet, (since this should give you a compiler warning saying "condition is always true",) do for(;;) which essentially loops forever.
Then, after each System.out() statement, (which essentially signifies a decision, which should end the loop,) do break; to exit the loop.
Goedenavond! C-:=
I am passing some parameters in the URL and then I add them in a list. My list has a limit of 5 elements. So if someone adds 6th element in the URL the list would simply ignore it. So I am trying to use a counter but the logic is not working as desired. I am using While loop to achieve this. So if list size is smaller than 5 set the agencyCds otherwise just return the list.
private List<IUiIntegrationDto> generateViewIntegrationReportData(ESignatureIntegrationConfig eSignConfig) throws Exception {
int counter = 1;
if(eSignConfig.getAdditionalAgencyCds() != null ) {
List<String> combinedAgencyCds = new ArrayList<String>();
for(String agencyCd : eSignConfig.getAgencyCd()) {
combinedAgencyCds.add(agencyCd);
}
StringTokenizer token = new StringTokenizer(eSignConfig.getAdditionalAgencyCds().toString(), StringConstants.COMMA);
while(token.hasMoreTokens()) {
combinedAgencyCds.add(token.nextToken());
}
while(combinedAgencyCds.size() < 5) {
counter = counter + 1;
eSignConfig.setAgencyCd(combinedAgencyCds);
}
// eSignConfig.setAgencyCd(combinedAgencyCds);
}
List<IUiIntegrationDto> intgList = getUiIntegrationManager().retrieveUiIntegrationReportData(eSignConfig.getAgencyCd(), eSignConfig.getCreatedDays(),
eSignConfig.getLob(), eSignConfig.getTransactionStatus(), eSignConfig.getAccounts(), eSignConfig.getSortKey(), eSignConfig.getSortOrder());
return intgList;
}
I am not completely sure about this logic if it is correct or if there is nay better approach.
Thanks
Try this instead of the last while in your code:
if(combinedAgencyCds.size() <= 5) {
eSignConfig.setAgencyCd(combinedAgencyCds);
} else {
eSignConfig.setAgencyCd(combinedAgencyCds.subList(0, 5));
}
The full combined list will then be used if it is less than 5 in size. Otherwise, only the first 5 elements are used.
Edit: Or even better:
eSignConfig.setAgencyCd(combinedAgencyCds.subList(0, Math.min(5, combinedAgencyCds.size())));
Ok so let's break down what your code is currently doing.
int counter = 1;
while(combinedAgencyCds.size() < 5) {
counter = counter + 1;
eSignConfig.setAgencyCd(combinedAgencyCds);
}
This snippet of code has a couple things wrong best I can tell. First, this loop has the possibility of running forever or not at all. Because combinedAgencyCds is never being manipulated, the size won't ever change and the logic being checked in the while loop never does anything. Second, there's a more efficient loop for doing this, assuming you don't need the counter variable outside of its usage in the while loop and that is using for loops.
Example syntax is as follows:
for (int i = 0; i < combinedAgencyCds.size(); i++) {
if (i < 5) {
// Do your logic here.
}
else {
break; // Or handle extra values however you want.
}
}
Notice there is no need for the explicit declaration for a counter variable as "i" counts for you.
Now in your actual logic in the loop, I'm not sure what the setAgencyCd method does, but if it simply sets a list variable in the eSignConfig like it appears to, repeating it over and over isn't going to do anything. From what I can see in your code, you are setting a variable with the same value 5 times. If you need any more explanation just let me know and I will be happy to revise the answer.
This is a small part of my code. Here the break statement doesn't work. The if condition is executed but the break statement takes the control to the start of the while loop. "assign" and "clsAssign" are two array list. "clustersRefGlobal()" is a function and I don't want to pass "assign" when it is empty. However due to break not working it is called even when "assign" is empty. I am not sure why break statement doesn't stop the while loop
Wh:while (i < n) {
System.out.println("Start");
get = clustersRefGlobal(assign);
clsAssign.add(get.get(0));
assign = get.get(1);
if(assign.isEmpty()){
System.out.println("Inside");
break Wh;
}
System.out.println("End");
i++;
}
Here is the output
Start
End
Start
Inside
Start
Exception in thread "main" java.lang.NullPointerException
at softwareClustering.DominantSetClustering.clustersRefGlobal(DominantSetClustering.java:54)
at softwareClustering.DominantSetClustering.buildDominatSetClustering(DominantSetClustering.java:76)
at trees.PrototypeSelectionTree.clustersRefLocal(PrototypeSelectionTree.java:214)
at trees.PrototypeSelectionTree.clustersRefGlobal(PrototypeSelectionTree.java:180)
at trees.PrototypeSelectionTree.buildTree(PrototypeSelectionTree.java:59)
at trees.PrototypeSelectionTree.buildClassifier(PrototypeSelectionTree.java:235)
at weka.classifiers.Evaluation.crossValidateModel(Evaluation.java:617)
at trees.TestClassifier.main(TestClassifier.java:45)
Java Result: 1
The exception is because the "clustersRefLocal()" function is called with empty "assign" parameter. If any one knows whats the problem or what I am missing?
public double[] buildDominatSetClustering(int n) throws Exception {
int i = 1;
ArrayList<ArrayList<Integer>> clsAssign = new ArrayList<>();
ArrayList<Integer> assign = new ArrayList<>();
ArrayList<ArrayList<Integer>> get;
for (int j = 0; j < data.numInstances(); j++) {
assign.add(j);
}
Wh:
while (i < n) {
System.out.println("hello");
get = clustersRefGlobal(assign);
clsAssign.add(get.get(0));
assign = get.get(1);
if(assign.isEmpty()){
System.out.println("inside "+assign.size());
break Wh;
}
System.out.println(assign.size());
i++;
}
if(!assign.isEmpty())
clsAssign.add(assign);
double[] indexAssToClus = new double[data.numInstances()];
int count = 0;
for (ArrayList<Integer> a : clsAssign) {
for (int k = 0; k < a.size(); k++) {
indexAssToClus[a.get(k)] = count;
}
count++;
}
return indexAssToClus;
}
This is the function in which the code exist
The simple explanation to what you are seeing is that in fact the break is stopping the loop ... but the code around the snippet you have shown us is starting it again.
This will be apparent if you add a traceprint immediately before the labelled while statement.
The exception is because the "clustersRefLocal()" function is called with empty "assign" parameter.
I suspect that you are confusing "empty" with null. An empty string is a non-null String that has zero length. If you try to test if a null String is empty by calling String.isEmpty() you will get an NPE. The correct test for a non-null, non-empty String is this:
if (assign == null || assign.isEmpty()) {
// null or empty ... bail out
break;
}
I recommend you simply reverse the logic:
if(! assign.isEmpty()){
i++;
}
But failing that, check what is happening to your variable i:
Your check is for: while (i < n)
But the only place i is ever changed, it is incremented.
labeling your loops and using break label is discouraged. (its like the goto and causes spaghetti code.)
Besides, it's not making sense here, since you don't have nested loops. You can just change break Wh; to break;
I'm trying to make a tetris game for android to help learn game programming for android. My goLeft/Rights break right when the button is pressed, the code for going left is in a class separate of the fields int array, and the list parts array. The fields array is accessed by a referenced variable (TetrisWorld tetrisworld;). While part list array is public so accessed through a variable(part) code for which is in the goLeft() code. It breaks at: if(tetrisworld.fields[x][part.y] != 0) Code for left:
public void goLeft() {
int x = 0;
for(int i = 0; i < 4; i++) {
TetrisParts part = parts.get(i);
x = part.x - 1;
if(tetrisworld.fields[x][part.y] != 0) {
noleft = true;
break;
}
}
if(noleft == false) {
for(int i = 0; i < 4; i++) {
TetrisParts part = parts.get(i);
part.x--;
}
}
}
The code for the fields int array:
int fields[][] = new int[WORLD_WIDTH][WORLD_HEIGHT];
WORLD_WIDTH and WORLD_HEIGHT are both static final ints, width being 9 and height being 19
I've tried putting if(tetrisworld.fields[0][0] == 0) and it still crashes so I don't think it has to do with the variables. Also It doesn't go out of bound even if I haven't added the code to check for that yet because I have the teroid spawning around x = 5 and since I can't go left/right once there's not a chance of that happening
I've tried moving the goLeft/Right methods to the gamescreen class which has a "world = TetrisWorld();" and it still bugs out at the same spot
UPDATE:
Ok just adding:
tetrisworld != null
to the first if statement fixed it, my question now is, why did it fix it? Why can't I move without this check? It clearly isn't null cause as far as I know; it's fully responsive now.
But an easier way to have solved this which is SOOOO easy is changing fields to static... then access it lika so: TetrisWorld.fields so my updated code is:
public void goLeft()
{
noleft = false;
for (int i = 0; i < 4; i++)
{
part = parts.get(i);
if (part.x - 1 < 0 || TetrisWorld.fields[part.x - 1][part.y] != 0)
{
noleft = true;
break;
}
}
if (noleft == false)
{
for (int i = 0; i < 4; i++)
{
part = parts.get(i);
part.x--;
}
}
}
Looks like you are hitting IndexOutOfBoundsException.
When you are doing x = part.x - 1;, your x variable can become lesser tan zero, thus your code will act like if(tetrisworld.fields[-1][part.y] != 0
It looks like you're getting a java.lang.NullPointerException when trying to access the array in tetrisworld. In the line you mention there are several ways that this could occur:
if(tetrisworld.fields[x][part.y] != 0) {
tetrisworld could be null.
The fields member of tetrisworld could be null.
The second array that you're looking up by using tetrisworld.fields[x].
The value of part could be null.
Having a quick look through your source code it looks to me like you never initialise tetrisworld, either at declaration using:
TetrisWorld tetrisworld = new TetrisWorld();
Or at some other point which is certain to have happened before your goLeft() method is called.
Ok I believe I found the answer, referencing: http://en.wikipedia.org/wiki/Null_Object_pattern
Apparently java will throw an NPE if you don't check for it first if you have a null reference? Is there any way to initialize it without doing a TetrisWorld tetrisworld = new TetrisWorld(); because it's already created in a different class so i get a thousand errors, an actual stack overflow! lul... Still not 100% positive. Please comment to verify and possibly suggest a better way to go about this.
How do I create a mutator method that adds two numbers but if the added number that is entered is negative, it will display an error message and not change the first number. Suggestions please.
public void restock(int newStockQuantity)
{
if(newStockQuantity < 0)
{
stockQ = stockQ;
}
{
system.out.println("Error not negative numbers");
}
else
{
stockQ = stockQ + newStockQuantity;
}
}
Well, for one thing you don't need the
stockQ = stockQ;
statement - that doesn't do anything.
Next is the problem of having multiple blocks in the "if" statement. If you did want to keep the no-op assignment, you could change your method to:
public void restock(int newStockQuantity)
{
if(newStockQuantity < 0)
{
stockQ = stockQ;
System.out.println("Error not negative numbers");
}
else
{
stockQ = stockQ + newStockQuantity;
}
}
With the no-op assignment removed, it's just:
public void restock(int newStockQuantity)
{
if(newStockQuantity < 0)
{
System.out.println("Error not negative numbers");
}
else
{
stockQ = stockQ + newStockQuantity;
}
}
Note the change from "system" to "System" as well - Java is case-sensitive.
That should compile and work.
Personally I would suggest throwing an exception if the method has an invalid argument instead of printing out a message to the console, but obviously it depends on the situation.
If you don't understand my first comment about having multiple blocks for the if statement, then I'd suggest going back to a good introductory Java book, and look at the syntax of if statements. It's slightly unclear which point you were having trouble with.
IMHO the best approach is the exception. Another point is to output the offending value, so a user of the method knows what the error is about. It also reveals errors in your check ;). Third point is to check for invariants first, bailing out with an exception or some appliable return-statement.
public void restock(int newStockQuantity) {
if(newStockQuantity < 0) {
throw new IllegalArgumentException("new stock " + newStockQuantity " must not be negative");
}
if (newStockQuantity == 0)
{
// nothing necessary, probably worth another exception?
return;
}
stockQ = stockQ + newStockQuantity;
}