I have the following code:
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
game.actionStack.remove(this);
}
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Action action : this.actionStack) {
action.step(this);
}
}
}
}
An exception gets thrown when game.actionStack.remove(this); occurs. Is there a way to remove the element safely from inside the Action class like I want?
I'm guessing you're getting a ConcurrentModificationException because you're calling the list remove method while iterating it. You can't do that.
An easy fix is to work on a copy of the array when iterating:
for (Action action : new ArrayList<>(this.actionStack)) {
action.step(this);
}
A slightly more efficient fix is to use an explicit Iterator and call its remove method. Perhaps have step() return a boolean indicating whether it wants to remain in the list for the next step or not:
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext();) {
Action action = it.next();
if (!action.step(this)) {
it.remove();
}
}
From : the java tutorial we get the following:
Iterators
...
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Use Iterator instead of the for-each construct when you need to:
Remove the current element. The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.
Iterate over multiple collections in parallel.
The following method shows you how to use an Iterator to filter an arbitrary Collection — that is, traverse the collection removing specific elements.
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
This simple piece of code is polymorphic, which means that it works for any Collection regardless of implementation. This example demonstrates how easy it is to write a polymorphic algorithm using the Java Collections Framework.
Note: I assume, you implemented equals and hashCode methods for your class
You need to use iterator to remove like below;
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext(); ) {
it.remove();
}
}
}
}
Edit: step function is doing simple remove job. I move it to Game constructor
I suspect that you are getting a Concurrent Modification Exception. I would suggest you do it like this
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
List<Action> tmpActionList = new List<Action>();
tmpActionList = game.actionStack
tmpActionList.remove(this);
game.actionStack = tmpActionList;
}
}
Let me know if it works.
Related
The idea of LinkedList is, that each element has a reference to its successor (and predecessor in the case of doubled linked list), so concatenation of two LinkedLists happens that last element of the first list get reference to first element of second list Detailed explanation here, what is made in O(1) time.
Howewer they made it stupid in Java.
It has no method java.util.LinkedList.addFirst(LinkedList) or something.
if you look at the method java.util.LinkedList.addAll(Collection), it iterates over an array, what collection returns with c.toArray(), and then adds each element of this array. What is even twice stupid:
1) linked list is iterated in 0(n)
2) elements are added to linked list in 0(n) time.
Is there any possibility to extends the standart LinkedList so he would have good concatenation method? Because now, the simplest, but bad solution i see to make the copy- paste of LinkedList code and make some methods protected in order to extend that with implementation of right addALL
You can't use addAll for that, because O(1) linked list concatenation is a destructive operation. In other words, you start with two non-empty lists, and end up with one big list and one empty list.
You are looking for two operations
void transferBeforeFirst(LinkedList<T> other);
void transferAfterLast(LinkedList<T> other);
They take LinkedList<T> other in whatever state it may be, and leave it empty upon return. This is rather counterintuitive, because generally the caller expects to find his data unchanged after calling a library method.
Of course, technically this could certainly be done. However, this goes against the grain of Java API design, which prefers to leave method parameters unchanged.
I don't think there is a way to do that, and the reason is that java has a strong object orientation and doesn't operate with data in a direct way such has C does, so if you have two linked lists and you want to make one out of two, you are forced to copy one of them entirely instead of only liking it at the end of the other one.
This behaviour is because special casing the adding of two linked lists together would destroy the sconfd list.
Notice that the LinkedList.Node class has both a next and a prev so it is indeed doubly-linked. To just join the chains together would make list2.first.prev point to list1.last which would then break list2.
public void addLast(LinkedList<? extends E> l) {
// My list continues on into the new list.
last.next = l.first;
// Back-link too - THIS BREAKS l!!
l.first.prev = last;
// End of new list is now last.
last = l.last;
}
Secondly notice that LinkedList<? extends E>. Remember that you can extend LinkedList so you may be adding two lists of a completely different class together - that would also require careful handling.
If you really want to achieve O(1) you could write an IterableIterable that would walk an Itearble<Iterable<T>> delivering each element from each Iterable in turn - kind of like a flatMap for Iterables.
class IterableIterable<T> implements Iterable<T> {
private final Iterable<? extends Iterable<T>> i;
public IterableIterable(Iterable<? extends Iterable<T>> i) {
this.i = i;
}
#Override
public Iterator<T> iterator() {
return new IIT();
}
private class IIT implements Iterator<T> {
// Pull an iterator.
final Iterator<? extends Iterable<T>> iit = i.iterator();
// The current Iterator<T>
Iterator<T> it = null;
// The current T.
T next = null;
#Override
public boolean hasNext() {
boolean finished = false;
while (next == null && !finished) {
if (it == null || !it.hasNext()) {
if (iit.hasNext()) {
it = iit.next().iterator();
} else {
// All over when we've exhausted the list of lists.
finished = true;
}
}
if (it != null && it.hasNext()) {
// Get another from the current list.
next = it.next();
}
}
return next != null;
}
#Override
public T next() {
T n = next;
next = null;
return n;
}
}
}
That's why LinkedList has the addLast() method
https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#addLast%28E%29
and it does have a addFirst() too
https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#addFirst%28E%29
you can't do better than that, because Java has not the pointer concept.
you could try to implement your own native code for that, however.
In a program, I have a HashSet of Foo:
final Set<Foo> set = new HashSet<>();
// add a lot of elements to the set
class Foo {
public void destroy() {
// other stuff [such as removing this as event handler]
set.remove(this);
}
}
I want to call destroy() for all members of the set.
The purpose of the destroy() method is to remove the element as handler for events and from the set.
This is what I have tried:
Use an Iterator / for each loop - throws ConcurrentModificationException:
for (Iterator<Foo> i = set.iterator(); i.hasNext(); ) { i.next().destroy() }
Remove one element at the time - horrible inefficient:
while (!set.isEmpty()) { set.iterator().next().destory(); }
I am looking for a solution to this problem that works well with very many elements in the set. Thank you very much.
You are almost done in your first attempt.
Try
for (Iterator<Foo> i = set.iterator(); i.hasNext(); ) {
Foo foo = i.next();
// other stuff with foo. Something like foo.someOtherStuff();
i.remove();
}
That will remove safely from the set. Need not to call destroy even.
I'm getting a very strange action in my code. I have an ArrayList of the following class.
class mySocket
{
public String name;
public Socket sck;
public mySocket(String n,Socket s)
{
this.name=n;
this.sck=s;
}
}
I declare the object like this
ArrayList<mySocket> handler = new ArrayList<>();
Now the problem is that when I try to remove an item using this method:
public void removeByName(String name)
{
synchronized(this)
{
mySocket t;
int i;
for(i=0;i<handler.size();i++)
{
t=handler.get(i);
if((t.name.equals(name)))
{
handler.remove(i);
break;
}
}
}
}
The remove function clears everything that follows the index.
For Example:
if this ArrayList has 3 elements and I call handler.remove(1) it removes not only 1 but also the object on line 2.
I think your issue is that you are using an indexed for loop and removing by index. In your example, if your list has 3 elements and you remove index 1, the object that was at index 2 is still there. It's just now at index 1.
A better way to do what you're attempting is to use an iterator or for-each loop.
//code outside for loop the same
for( mySocket socket : handler ) {
if((socket.name.equals(name)))
{
handler.remove(socket);
break;
}
}
Is the ordering of your mySocket objects important? If not, storing them in a Map keyed by name would save you some trouble. Then you would just call handler.remove(name). This operation is safe, even if name doesn't exist in the map. Also, for current uses of the collection handler that don't care aobut the name, you can retrieve the unordered Set of mySockets by calling map.values(). You would then be able to iterate over that Set using an iterator or for-each as above.
You CAN NOT remove items in a Collection while looping through them, the result, as you have seen, is undefined.
You either have to build a list of items to be removed and use
originalList.removeAll(itemsToBeRemoved);
Or you build your loop using an iterator.
Iterator<mySocket> handlerIterator = handler.iterator();
while (handlerIterator.hasNext()) {
mySocket t = handlerIterator.next();
if (t.name.equals(name)) {
handlerIterator.remove();
}
}
I'm a little puzzled over something. Java's documentation tells us that there is no defined behavior when removing items from a collection while iterating over that collection using an Iterator object and that the only safe way to do so is to use Iterator.remove().
How then, would you safely remove an event handler from an ArrayList if, in the course of iterating through the list one of the handlers has decided that it's time to remove itself as a listener?
// in public class Dispatcher
public void dispatchEvent(){
Iterator<IEventHandler> iterator = mHandlers.iterator();
IEventHandler handler = null;
while(iterator.hasNext()){
handler = iterator.next();
handler.onCallbackEvent();
}
}
public void insertHandler(IEventHandler h){
mHandlers.add(h);
}
public void removeHandler(IEventHandler h){
mHandlers.remove(h);
}
Meanwhile, the handler was instantiated like this...
final Dispatcher d = new Dispatcher();
d.insertHandler(new IEventHandler(){
#Override
public void onCallbackEvent(){
Log.i(" callback happened ");
d.removeHandler(this);
}
});
See the potential problem? You're removing the handler from the ArrayList as a result of the onCallbackEvent() declared in that specific handler while you're still iterating using the Iterator.
Is this an intractable problem? What's the safe way to handle this situation?
This is a very common problem when implementing an event system. The only solution is to copy the list of handlers on change. You can do this yourself in the insertHandler/removeHandler methods or just use CopyOnWriteArrayList.
You could reimplement removeHandler to store the handlers scheduled for removal.
public void removeHandler(IEventHandler h){
mHandlersToRemove.add(h);
}
and then remove them before you do any dispatching.
public void dispatchEvent(){
mHandlers.removeAll(mHandlersToRemove);
mHandlersToRemove.clear();
...
You could also remove at the end of dispatchEvent, but then you could only remove from within handlers. (Otherwise you might dispatch to handlers that were removed.)
If you're interested in a theoretical solution to this problem, you can look at how C++ implements iterators. In an stl vector, the iterator has an erase method that returns the next valid iterator.
It would look something like this:
for (itr = listA.begin(); itr != listA.end(); )
{
if ( shouldRemove(*itr) ) {
itr = listA.erase(itr);
}
else {
++itr;
}
}
Of course, this example doesn't apply to your question since it's both in C++ and it would be awkward to propagate the new iterator up to the top-level loop (or add a return value to your call for a "remove" condition). But maybe there's a similar java implementation somewhere out there : )
Say I have already created an iterator called "iter" and an arraylist called "database". I want to be able to look through the arraylist and see if any element in the arraylist is equal to a String called "test". If it is, then I would like to add the element to another list.
while(iter.hasNext()) {
if(database.next() == test) {
database.next().add(another_list);
}
}
What am I doing wrong? I'm completely new to iterators in java. Do I need to write my own iterator class? Any code examples would be greatly appreciated. Thanks
The problem with your code is that every time you call .next(), it advances the iterator forward to the next position. This means that this code
if(database.next() == test) {
database.next().add(another_list);
}
Won't work as intended, because the first call to database.next() will not give back the same value as the second call to database.next(). To fix this, you'll want to make a temporary variable to hold on to the new value, as seen here:
while(iter.hasNext()) {
/* type */ curr = iter.next();
if(curr == test) {
curr.add(another_list);
}
}
(Filling in the real type of what's being iterated over in place of /* type */)
In many cases, though, you don't need to use iterators explicitly. Most of the Collections types implement the Iterable interface, in which case you can just write
/* container */ c;
for(/* type */ curr: c) {
if(curr == test) {
curr.add(another_list);
}
}
Hope this helps!
if(database.contains("test"))
{
another_list.add("test");
}
you can use the built in method contains(...)
you should use equals(...) for data comparisions
look at the javadoc to see if there is already a method present for your purpose