Looping through LinkedLinkst in two places gives error - java

So I am making a little game in Java, and in the game you have Entities which are stored in a LinkedList. In the tick method I iterate through the Entities' LinkedList like this:
#Override
public void tick(float delta) {
for (Entity e : entities) {
e.tick(delta);
}
player.tick(delta);
}
And the same for the render method
#Override
public void render(Graphics g) {
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, Game.WIDTH, Game.HEIGHT);
for(Entity e : entities) {
e.render(g);
}
player.render(g);
}
One of the Entities is a class called Block. And in the Block class there is a function which returns if a block is near, in this function I also iterate through the Entities' LinkedList and it's called from the following tick method in Block:
#Override
public void tick(float delta) {
if (color == Color.WHITE) {
if (getSurrounding(-32, -32) != null && getSurrounding(-32, -32).getColor() == Color.BLACK) {
if (getSurrounding(-32, -32).getStrength() < strength) {
getSurrounding(-32, -32).setStrength(-50);
}
}
}
if (!inGame.entities.isEmpty() && strength <= 0) {
inGame.entities.remove(this); // <------ REMOVING AN ELEMENT
}
}
public Block getSurrounding(int xOffset, int yOffset) {
for (Entity e : inGame.entities) {
if (e instanceof Block) {
if (x + xOffset == e.getX() && y + yOffset == e.getY()) {
return (Block) e;
}
}
}
return null;
}
(This function is called and used in the tick method of the block by the way)
Now everytime I run the game, the game starts and runs normal for a couple milliseconds and then it throws this exception:
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(Unknown Source)
at java.util.LinkedList$ListItr.next(Unknown Source)
at _47b3n.game.engine.gamestate.gamestates.InGame.tick(InGame.java:36)
at _47b3n.game.engine.Handler.tick(Handler.java:17)
at _47b3n.game.engine.Game.tick(Game.java:70)
at _47b3n.game.engine.Game.run(Game.java:52)
at java.lang.Thread.run(Unknown Source)
(The first two code samples are in the InGame.java file, and line 36 is the for-loop in the tick method)
Now how do I stop this error?

ConcurrentModificationException usually relates to modifying the list while iterating through it within a loop.
My assumption is that you are removing an element while you are iterating through.
In order to stop this from happening, i would recommend saving the object you want to delete in a variable while it is in the loop (and has met some condition), then removing it from the list after the loop has completed.
Edit: based on the updated question, you are removing an element within the tick method. I would not do this here, but return the element that you would like to remove and remove it only when you are no longer iterating the list you are removing from.
Possible solution:
I would create another method to check the strength of the Entity and calling that from the tick method (this is to save the tick method having to return an object to delete) as so:
#Override
public void tick(float delta) {
Entity removeEntity = null;
for (Entity e : entities) {
e.tick(delta);
if(e.checkStrength()){
removeEntity = e;
break;
}
}
if(removeEntity != null){
entities.remove(removeEntity);
}
player.tick(delta);
}
In the entity class:
public boolean checkStrength(){
if (!inGame.entities.isEmpty() && strength <= 0) {
return true;
}
return false;
}
Just so you know this is not the best solution by far, but should get you through the problem you have now. Be sure to clean your code up when you have time.

You are removing entities in the tick() method... while in the method, you are still iterating over the entities in the outer tick method... because you're modifying the list inside e.tick(), the list is changing, which causes the next iteration to fail... replacing the method call to e.tick() with the inline method demonstrates the problem more clearly:
#Override
public void tick(float delta) {
for (Entity e : entities) {
//e.tick(delta); --inline below
if (color == Color.WHITE) {
if (getSurrounding(-32, -32) != null && getSurrounding(-32, -32).getColor() == Color.BLACK) {
if (getSurrounding(-32, -32).getStrength() < strength) {
getSurrounding(-32, -32).setStrength(-50);
}
}
}
if (!inGame.entities.isEmpty() && strength <= 0) {
inGame.entities.remove(this); // <------ REMOVING AN ELEMENT
}
}
}
Note that where you have remarked you are "REMOVING AN ELEMENT" is inside the outer-most loop, that's the cause of your issue.
Edit: Suggested solution as others have advised, try something like this (just showing the removal block):
List toRemove = new ArrayList() //somewhere earlier in the code
if (!inGame.entities.isEmpty() && strength <= 0) {
//inGame.entities.remove(this); // <------ REMOVING AN ELEMENT
toRemove.add(this);
}
return toRemove;
Then in the calling function, after you've finished all your iterating
entities.removeAll(toRemove);

A solution using an Iterator:
Replace the first code-block with the following:
public void tick(float delta) {
for (Iterator<Entity> iterator = entities.iterator(); iterator.hasNext();) {
boolean remove = e.tick(delta);
if(remove) {
iterator.remove();
}
}
player.tick(delta);
}
then replace the other tick method with this:
public boolean tick(float delta) {
if (color == Color.WHITE) {
if (getSurrounding(-32, -32) != null && getSurrounding(-32, -32).getColor() == Color.BLACK) {
if (getSurrounding(-32, -32).getStrength() < strength) {
getSurrounding(-32, -32).setStrength(-50);
}
}
}
if (!inGame.entities.isEmpty() && strength <= 0) {
return true;
}
return false;
}
This should solve your problem. The methods return type has to change, so that we have an indicator when to remove any elements and when not. Every time the tick returns true, the corresponding element will be removed

Related

Where it is possible to write the base condition in the recursive methods

I was reading about recursive methods in java ... I do not undserstand the base condition of the recursive method ... Here are two examples
public int weight() {
return weight(root);
}
/ * Returns the weight of the tree where n is the root. * /
private int weight(Node n) {
if (n == null) {
return 0;
} else if (n.left == null) { // då är n.right också null
return n.data;
} else {
return weight(n.left) + weight(n.right);
}
}
public boolean isMobile() {
if (root == null) {
return true;
} else {
return isMobile(root);
}
}
/ * Returns true if the tree where n is the root of a mobile. * /
private boolean isMobile(Node n) {
if (n.left == null) { // då är n.right också null
return true;
} else {
return isMobile(n.left) && isMobile(n.right) &&
weight(n.left) == weight(n.right);
}
}
My wonder : in the weight() method why do not we do like this :
public int weight() {
if (root == null) {
return 0;
} else {
return weight(root);
}
}
As you can see the base condition in the isMobile() method is directly under it but the base condition in the weight() method is under the private method ..
When it is possible to write the base condition of the recursive directly under it or in a separate private method ?
Thanks
EDIT :
public int weight() {
if (root == null) {
return 0;
} else {
return weight(root);
}
}
private int weight(Node n) {
if (n == null) {
return 0;
} else if (n.left == null) { // då är n.right också null
return n.data;
} else {
return weight(n.left) + weight(n.right);
}
}
in the weight() method why do not we do like this : [...]
The simple answer is because parameterless weight() overload of the method is not recursive, even though it relies on a recursive implementation that takes Node as its parameter. The base condition must be in the recursive method itself, because that is where the decision to stop calling itself must be made.
Despite being overloads of the same name, your two weight methods work together like this:
public int nonRecursiveWeight() {
return recursiveWeight(root);
}
private int recursiveWeight(Node n) {
...
}
The nonRecursiveWeight provides a nice public "front" for the recursive implementation recursiveWeight, hiding the node from the API users.
isMobile pair of methods follows the same arrangement: you have a recursive implementation, and a non-recursive "front" sharing the same name.
Base condition must be in the recursive method. The method weight() is not recursive as it is not calling itself. It is calling a recursive method weight(Node n) which has and must have base condition.
if (n == null) { return 0; }
Intention in the isMobile() and isMobile(Node n) is a bit different. The author probably wanted to check for root == null directly in isMobile() method to avoid double checks in recursive method but they can be rewritten like this:
public boolean isMobile() {
return isMobile(root);
}
private boolean isMobile(Node n) {
if ( n == null || n.left == null ) return true;
return isMobile(n.left) && isMobile(n.right) && weight(n.left) == weight(n.right);
}
Again isMobile(Node n) is recursive and isMobile() is not. The isMobile methods now look the same as weight methods. In general the rule is that the recursive methods are the ones which call themselves and they must have base condition which will terminate recursion.
Also please note that you do not need to write else if you have a return before that. For example:
boolean someMethod() {
if ( something ) {
return true;
} else {
return false;
}
}
Can be rewritten as:
boolean someMethod() {
if ( something ) {
// ...
return true;
}
// if something was true then the next piece of code will never get executed
// if was not true then the next piece of code will always execute
// ...
return false;
}
You probably meant if (root == null) in your re-write.
You still have to check in weight(Node) since it's recursive–why do it twice?

Java: Getting if there is an element before a specified element in an ArrayList

public static boolean isComponentBefore(GuiInterface component) {
int index = 0;
for (int i = 0; i < components.size(); i++) {
if (components.get(i).getName() == component.getName()) {
if(components.get(i- 1) == null){
return false;
}
}
}
return true;
}
I currently use this, though this can lead to ConcurrentModificationExceptions & it isn't working because it keeps throwing ConcurrentModificationExceptions whenever I try to see if the element before the element passed in is null.
I was wondering if there are other ways to do this.
Looking at your logic, you will a NullPointerException incase the component in the ArrayList before the given component is null, because components.get(i) would be null and components.get(i).getName() will throw the NPE.
You can try to change the logic here a bit. For every null element in the list, check if the next component is the component you're searching for and return accordingly.
for (int i = 0; i < components.size(); i++) {
if (components.get(i) == null) { // If a particular element is null, check if the next element is what you want
if(components.get(i+1).getName().equals(component.getName())) { // you need to handle the edge case for i+1 as well for the last iteration
return false;
}
}
}
Note that you need to compare the Strings using equals() method and not the == operator. You also need to handle the corner case of i+1 for the last iteration.
This line
if (components.get(i).getName() == component.getName()) {
Should be
if (components.get(i).getName().equals(component.getName())) {
However, your condition can never happen. If component.get(i-1) is null, then in the previous loop iteration
components.get(i).getName() // <-- null pointer exception, so
component.get(i-1) must not be null and you need to hope that i isn't 0 or you'd get an index out of bounds exception.
Use an iterator
e.g
int i = 0;
Iterator<GuiInterface > it = components.iterator();
while (it.hasNext()) {
i++;
GuiInterface thisComp = it.next ();
if (thisComp.getName().equals(component.getName())) {
if(i > 0 && components.get(i- 1) == null){ // this code does not make sense
return false;
}
}
}
Assuming the passed component is not in your list:
public static boolean isComponentBefore(GUIComponent component) {
// Start at 1 to avoid IndexOutOfBounds
for(int i = 1; i < components.size(); i++) {
if (components.get(i).getName().equals(component.getName())) {
return components.get(i - 1) != null;
}
}
// Given component is not in the list, or the list only has one element
return false;
}
Assuming the passed component is in the list:
public static boolean isComponentBefore(GUIComponent component) {
int index = components.indexOf(component);
return index > 0 && components.get(index - 1) != null;
}

Check whether there are remaining items in the List while iterating

I'm doing a Bean Validation for a List of conditions:
public abstract class BaseMyConditionValidator<T extends Annotation> implements ConstraintValidator<T, List<MyCondition>> {
#Override
public void initialize(T constraintAnnotation) {}
#Override
public boolean isValid(List<MyCondition> conditions, ConstraintValidatorContext context) {
boolean result = true;
if (!conditions.isEmpty()){
int i = 0;
for (MyCondition cond : conditions){
if (cond.getJoinPart() != null){
if (!hasNext(i, conditions)){
return false;
}
}
i++;
}
}
return result;
}
private boolean hasNext(int index, List<MyCondition> conditions){
try {
conditions.get(index + 1);
} catch (Exception e){
return false;
}
return true;
}
}
My question is is there a simpler approach to deal with:
Checking if there is still an item next in line during a iteration of a List
You could use plain old Iterator to iterate through the list, or instead of hasNext(i, conditions) just check list length (i < conditions.size() - 1)
In the end, instead of iterating through whole list, just check if last element's JoinPart is null (at least it is what you are doing)
#Override
public boolean isValid(List<MyCondition> conditions, ConstraintValidatorContext context) {
return conditions.isEmpty() || conditions.get(conditions.size() - 1).getJoinPart() != null;
}
In fact, in your case/code you don't need to check whether there is another element in the list. Using for(MyCondition cond : conditions) will iterate over all elements in conditions list. If you need to check what is the size of the list, you can use contidions.size().
Of course!
for (int i = 0; i < conditions.size(); i++){
cond = conditions.get(i);
if (cond.getJoinPart() != null){
if (i < conditions.size()){
continue;
} else {
return false;
}
}
}
But I don't understand why you would do that... are you just trying to ensure that .getJoinPart() doesn't equal null for every element?

unwind to the first frame of a recursive call in Java?

Suppose I have a (very simple) recursive method like this:
public static void myMeth(int n)
{
// do something
// now execute the recursive call
if (n < 0) return;
else if ( n == SOME_CONST ) throw new UnsupportedOperationException();
else myMeth(n - 1);
}
(The second condition n == SOME_CONST is just there to make the point that sometimes an exception can occur, sometimes it does not).
Suppose I call myMeth(10), and that the exception does happen after a few recursive calls (say SOME_CONST == 5).
Is there any trick I could do (with try-catch block, that is) to get me back to the first frame of myMeth ?
This could work, there is probably a cleaner solution out there, but it's a start:
public static void myMeth(int n, boolean firstCall)
{
// do something
// now execute the recursive call
try
{
if (n < 0) return;
else if ( n == SOME_CONST ) throw new UnsupportedOperationException();
else myMeth(n - 1, false);
}
catch(UnsupportedOperationException e)
{
if (firstCall)
{
//logic
}
else
{
throw e;
}
}
}
try{
myMeth(n);
catch (UnsupportedOperationException e) {
myMeth(n); //or another number
}
Using another static variable to keep track of the first number (10)
static int SOME_CONST = 5;
static int keepN;
public static void myMeth(int n) {
// do something
// now execute the recursive call
try {
if (n < 0) {
return;
} else if (n == SOME_CONST) {
throw new UnsupportedOperationException();
} else {
myMeth(n - 1);
}
} catch (UnsupportedOperationException e) {
if (n == keepN) {
System.out.println(e);
System.out.println("YES first frame");
} else {
System.out.println("NO");
throw e;
}
}
}
public static void main(String[] args) {
keepN = 10;
myMeth(10);
}
// depth should be 0 on first call
public static boolean myMeth(int n, int depth)
{
// do something
// now execute the recursive call
if (n < 0) return true;
else if ( n == SOME_CONST ) return false;
boolean success = myMeth(n - 1, depth + 1);
if (depth == 0 && !success) {
// uh-oh
}
return success;
}
Or if you don't care about each individual frame in the recursion, replace depth with a boolean and change to boolean success = myMeth(n - 1, false);
I'm not sure what you're asking when you say you want to get back to the first frame though. Do you want to go back to the beginning of the first method call, so you can repeat the steps in the // do something block? Or are you fine executing right after the recursive call to myMeth?
If you're generating the Exception yourself, I replaced the need for that by using booleans. If not, you can replace it. You could also just throw an exception in the first frame, while still using booleans.
Yes, but this kind of trick will miss the whole concept of the recursive and will be hard to read and understand.
You shouldn't use recursive if you can't expect the definite number of options it can produce.
Otherwise use another solution.

Java: Adding nodes to graph bug

Preface: I know that there are high quality graph APIs available. I'm interested in writing my own for self-improvement.
This is my function to add nodes:
public void addNode(Vertex v, Collection<Edge> neighbors) {
int originalSize = size();
if (head == null) {
head = v;
}
else {
Collection<Edge> inEdges = new ArrayList<Edge>();
inEdges.addAll(neighbors);
traverseGraphToAdd(head, inEdges, v);
}
assert originalSize + 1 == size() :
String.format("adding operation failed. original size: %d, current size: %d", originalSize, size());
}
private void traverseGraphToAdd(Vertex start, Collection<Edge> inEdges, Vertex toAdd) {
Iterator<Edge> iter = inEdges.iterator();
Edge e;
while (iter.hasNext()) {
e = iter.next();
if (e.getSource().equals(start)) {
start.addEdge(e);
iter.remove();
}
else if (! directionalEdges && e.getSink().equals(start)) {
start.addEdge(e);
iter.remove();
}
}
if (inEdges.size() > 0) { //otherwise there's no point in continuing to search
for (Edge arc : start.getOutEdges()) {
traverseGraphToAdd(arc.getSink(), inEdges, toAdd);
}
}
}
Size and its dependencies:
public int size() {
int count = 0;
if (head == null) {
return 0;
}
else {
count = countNodes(head);
}
clearVisited();
return count;
}
private int countNodes(Vertex start) {
int result = 1;
start.setVisited(true);
for (Edge e: start.getOutEdges()) {
if (! e.getSink().isVisited()) {
result += countNodes(e.getSink());
}
}
return result;
}
private void clearVisited() {
if (head != null) {
clearNode(head);
}
}
private void clearNode(Vertex start) {
start.setVisited(false);
for (Edge e: start.getOutEdges()) {
if (e.getSink().isVisited()) {
clearNode(e.getSink());
}
}
}
The Edge class:
public Edge(Vertex source, Vertex sink, int weight) {
this.source = source;
this.sink = sink;
this.weight = weight;
}
The following call works:
g.addNode(ftw, new HashSet<Edge>()); //first node - empty edges
g.addNode(odp, Arrays.asList(new Edge(ftw, odp, 3))); //link new node to one already in the graph
This does not:
g.addNode(tlt, Arrays.asList(new Edge(tlt, ftw, 2)));
In this one, the first argument of the Edge constructor is not the node already in the graph. I try to rectify this in addNode with the following (repeated from above):
if (e.getSource().equals(start)) { /*... */ }
else if (! directionalEdges && e.getSink().equals(start)) { /*... */ }
directionalEdges is a class field that determines whether or not this graph is directional or not.
However, this causes assertion errors:
Exception in thread "main" java.lang.AssertionError: adding operation failed. original size: 1, current size: 1
What is going on here?
The graph you're trying to create in your example looks like this:
tlt -> ftw -> odp
After creating ftw -> odp, you should (and do, I believe) have head == ftw. After adding tlt, you should have head == tlt if you want your traversal algorithm to work properly. But in the code you've shown us, there is only one place where head is assigned to, and that happens only in the condition when head == null, in the fifth line of addNode(). Therefore, head doesn't change when you add tlt, and so traverseGraphToAdd() therefore starts form ftw instead of tlt as you intend for it to.
You have a more general problem here, however, namely that your code isn't able to handle directed graphs which aren't rooted (that is, they have more than one source node.) Consider what would happen if you wanted a graph like this one:
a -> b <- c
I think you'd have a problem with this, since you no longer have a single head.

Categories