elect elect - 5 months ago 56
Java Question

Java stream, remove and perform action from ConcurrentLinkedQueue

I am unsure how to do this, I'd like to iterate the

ConcurrentLinkedQueue
(all of it), removing the i-th item and performing some code on it.

This is what I was used to do:

public static class Input {

public static final ConcurrentLinkedQueue<TreeNode> treeNodes = new ConcurrentLinkedQueue<>();
}

public static class Current {

public static final ConcurrentHashMap<Integer, TreeNode> treeNodes = new ConcurrentHashMap<>();
}


TreeNode
is a simple class

TreeNode treeNode = Input.treeNodes.poll();

while (treeNode != null) {

treeNode.init(gl3);

Current.treeNodes.put(treeNode.getId(), treeNode);

treeNode = Input.treeNodes.poll();
}


This is how I am trying to do using stream:

Input.treeNodes.stream()
.forEach(treeNode -> {
Input.treeNodes.remove(treeNode);
treeNode.init(gl3);
Current.treeNodes.put(treeNode.getId(), treeNode);
});


I am afraid that something may be error prone having to remove the item inside the
forEach
action.

So my question is:

Is this safe and/or are there any better ways to do it?

Answer

Just as you've assumed, you should not modify the backing collection while processing the stream because you might get a ConcurrentModificationException (just as with for(Object o:objectArray){} loops)

On the other hand it is not very clear which TreeNode you are trying to remove, as in the current case, seemingly you wish to remove all elements from the List, perform some actions on them and put them in a Map.

You may safely achieve your current logic via:

Input.treeNodes.stream()
         .map(treeNode -> {
             treeNode.init(gl3);
             Current.treeNodes.put(treeNode.getId(), treeNode);
         });
Input.treeNodes.clear();