-3

As per docs ConcurrentModificationException states: ConcurrentModificationException occurs when an object is tried to be modified concurrently when it is not permissible.

I'm trying to de-rust on some java conceptsand make a huffman compression application.
I have a helper function that I believe is causing this, but I am unsure why.

When I pass in root and set it to the new root which is returned by huffmanHelper

(my code probably isn't doing fully what I want it to yet)
My question: * behind the scenes why is what I am attempting a problem in java.*

thank you

package huffman;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;

public class huffman {

public static Map<Character, Integer> frequency = new HashMap<Character, Integer>();
public static PriorityQueue<node> nodesPQ = new PriorityQueue<node>();

public static void main(String[] args) {
    
    /* get input */
    Scanner scanner = new Scanner(System.in);
    String input = scanner.nextLine();
    frequency = inputFrequency(frequency,input);
    System.out.println(frequency);
    scanner.close();
    nodesPQ = createNodes(nodesPQ, frequency);
    node a = nodesPQ.poll();
    node b = nodesPQ.poll();
    node OGroot = new node(a,b,a.getFrequency() + b.getFrequency(),null);
    node finalRoot = createBranch(nodesPQ,OGroot);
    finalRoot.inorderPrint();
}


/* counts occurrences of letters in output returns Map<Char, # of occurrences> */
public static Map<Character,Integer> inputFrequency(Map<Character,Integer> map,String input){
    /* split input into char Array */
    char[] charsArray = input.toCharArray();
    
    /* fill hashmap ['Char', # of occurrences] */
    for(char i : charsArray) {
        int count = 0;                                                          
        for(char j : charsArray){
            if(i == j) {
             count++;            
            }
            map.put(i,count);                   
        }
    }
    return map;
}


/* take Map of <Character, # of occurrences> and create nodes inside PQ*/
public static PriorityQueue<node> createNodes(PriorityQueue<node> nodePQ,Map<Character,Integer> map){
            
        nodePQ = new PriorityQueue<>();  
        // create nodes inside PQ
        for (Map.Entry<Character,Integer> i : frequency.entrySet())  {
            Character character = i.getKey();
            Integer occurrences = i.getValue();
            node n = new node(null,null,occurrences,character);
            
                nodePQ.add(n);
            }        
      
        return nodePQ;
        } 


 



public static node createBranch(PriorityQueue<node> nodePQ, node root){
    node newRoot = null;
    for(node i : nodePQ) {
        node nextFrequent = nodePQ.poll();
        root = huffmanHelper(nodesPQ,root,nextFrequent);

    }
        return newRoot;
        
}
    





public static node huffmanHelper(PriorityQueue<node> nodePQ, node root, node nextFrequent){
    node newRoot = new node(nextFrequent,root,root.getFrequency() + nextFrequent.getFrequency(),null);
    
    //get next letter and frequency 
    return newRoot; 
        }   
}

my stack trace:

hello my name is sam
{ =4, a=2, s=2, e=2, h=1, y=1, i=1, l=2, m=3, n=1, o=1}
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.PriorityQueue$Itr.next(PriorityQueue.java:536)
    at huffman.huffman.createBranch(huffman.java:83) - is the start of 
    forLoop in createBranch
    at huffman.huffman.main(huffman.java:26) - is node finalRoot = 
    createBranch(nodesPQ,OGroot); in main
Slowly_Learning
  • 57
  • 1
  • 10
  • 2
    if you get errors, show the actual error. That means showing the stack trace and explaining which part of your (]mcve]) code it maps to, not just giving its name and description: [help folks help you](/help/how-to-ask) because shouldn't need to run your code. And as a new user: welcome to Stackoverflow but [please read up how to properly format your post](/editing-help) and then edit your post accordingly. We'll put in the effort to help if you put in the effort to follow the [posting guidelines](/help/how-to-ask) =) – Mike 'Pomax' Kamermans Dec 26 '20 at 18:19
  • 1
    Which line of your code does the stack trace say that the error happens in? – Ole V.V. Dec 26 '20 at 18:19
  • Lets start with: [What is a stack trace, and how can I use it to debug my application errors?](https://stackoverflow.com/q/3988788) – Pshemo Dec 26 '20 at 18:23
  • sorry about the lack of stack trace, it's there now – Slowly_Learning Dec 26 '20 at 18:25
  • 2
    No it isn't, because it says the error is on line 26, and the code you pasted has an empty line on 26. That's _a_ stack trace, but not for _this_ code, so make sure to reduce your code as [mcve] for putting in your post, and then show the stack trace for _that_ code: don't show a stack trace for different code. Also, please remember to auto-format your code in your code editor/IDE because no one likes reading weirdly and even unmatched indented code with large stretches of empty lines. – Mike 'Pomax' Kamermans Dec 26 '20 at 18:26
  • Can we assume that code you posted is exactly the same as the one which generated that exception (line numbers matters here)? – Pshemo Dec 26 '20 at 18:27
  • Nah, you can't make that assumption @Pshemo - see the comment above. – Amir Afghani Dec 26 '20 at 18:28
  • I'm going to guess that root is in the priorityQueue and you're re-assigning root in the for loop. – Amir Afghani Dec 26 '20 at 18:29
  • added the lines of code associated with stack trace, let me know if anything is unclear – Slowly_Learning Dec 26 '20 at 18:30
  • But the code in your question _literally cannot_ have a stack trace on line 26, so even if you just copy pasted, the code you're showing in your post does not match the code you're running locally. That could be a bad paste, that could be an accidental newline, etc. etc. which is _why_ we have posting guidelines: properly format your code first, so that these kind of mistakes don't happen for you. Not everything we ask you to fix is your fault, but it _is_ still your responsibility to make sure your post [is accurate](/help/how-to-ask). – Mike 'Pomax' Kamermans Dec 26 '20 at 18:44
  • 1
    If you're trying to "de-rust your Java brain", using code conventions for naming and formatting is a good start. – chrylis -cautiouslyoptimistic- Dec 26 '20 at 19:01

1 Answers1

2

This line removes an element from the priority queue:

    node nextFrequent = nodePQ.poll();

It happens inside a loop iterating over the same priority queue, so counts as a forbidden concurrent modification. This causes your exception.

is there a better way you can think of iterating over a PriorityQueue to remove items? just a regular for loop w PQ.size() ?

If you want to exhaust the queue in priority order, keep taking out elements until poll() returns null (code is not tested):

    node nextFrequent = nodePQ.poll();
    while (nextFrequent != null) {
        // Do something with nextFrequent
        nextFrequent = nodePQ.poll();
    }

The poll method Retrieves and removes the head of this queue, or returns null if this queue is empty.

Documentation link: Queue.poll()

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • THANK YOU, simple, to the point, helpful and not condesending I APPRECIATE YOU Ole V.V. – Slowly_Learning Dec 26 '20 at 18:41
  • V.V is there a better way you can think of iterating over a PriorityQueue to remove items? just a regular for loop w PQ.size() ? – Slowly_Learning Dec 26 '20 at 18:50
  • Thank you for your help I solved this by changing my createBranch function like so: public static node createBranch(PriorityQueue nodePQ, node root){ for(int i = 0; i < nodePQ.size(); i++) { node nextFrequent = nodePQ.poll(); root = huffmanHelper(nodesPQ,root,nextFrequent); } return root; } What is funny about this loop is that it ends with extra items (4 to be exact) in the PriorityQueue (probably just weird java stuff) I'm going to just change for loop to while(!nodePQ.isEmpty) & your suggestion and see what happens. thanks again – Slowly_Learning Dec 27 '20 at 19:29
  • 1
    works fine w while(!nodePQ.isEmpty) thank you stackoverflowers – Slowly_Learning Dec 27 '20 at 19:38
  • Your attempt `for (int i = 0; i < nodePQ.size(); i++) {` will end when `i` has grown to the remaining size. So if there are 8 or 9 elements in the queue from the outset, once 4 are remaining, `i` will have grown to 4 or 5 and the loop will end. I take it that this is not what you want. – Ole V.V. Dec 27 '20 at 20:13
  • ahhh okay that makes sense, wasn't using my brain there. thank you – Slowly_Learning Dec 27 '20 at 22:15