Results 1 to 20 of 20
  1. #1
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default How can I avoid java.util.ConcurrentModificationException exception?

    Gentlemen (and Ladies maybe?)

    I now have an addCD() method which prompts the user for the details of a new CD (this works fine) and then checks to see if the combined artist and title details already exist in the cdList. If they do not then the new CD should be added to the end of the list. The newCD details are being added to the list but they are being added to the end of the first ArrayList ("Andy Sheppard") at index 3, and the above exception is being thrown. The equals(Object) method has been overridden to check that the artist and title of CD A equals that of CD B. This also works OK. However my code needs a tweak to ensure that the new CD details are added to the end of the list and the exception is not thrown.
    Can anyone advise please? Many thanks, Disgruntled of CyberSpace.

    Java Code:
    import java.util.*;
    
     /** Class MusicLibrary - models a simple catalogue of CDs
      * 
      */
    
    public class MusicLibrary
    {
       private SortedMap<String, List<CD>> cdCatalogue;
       
       
       public MusicLibrary()
       {
          super();
          this.cdCatalogue = new TreeMap<String, List<CD>>();
       }
       
           
       /**
        * Displays the details of all CDs in an instance of MusicLibrary class
        */
       public void displayCDs()
       //requires the toString() method to be overridden in the CD class
       {
          for (String eachCD : this.cdCatalogue.keySet()) 
          {
             List<CD> cdList = this.cdCatalogue.get(eachCD);
             for (CD everyCD : cdList)
             {
                System.out.println(everyCD);
             }
          }
      }
        
       /**
        * Sorts the CDs for each artist in order of year
        */
       public void sortCDsForArtist()
       {
          for (String eachCD : this.cdCatalogue.keySet()) 
          {
             List<CD> cdListCopy = this.cdCatalogue.get(eachCD);
             for (CD everyCD : cdListCopy)
             {
                Collections.sort(cdListCopy);
             }
          }
       }
       
       /**
        * If the artist argument exists in the CD catalogue
        * the details of the artist's most recent CD are
        * displayed. If the artist is not catalogued a
        * warning is displayed.
        */
       public void displayMostRecent(String anArtist)
       {
             List<CD> artistsCD = this.cdCatalogue.get(anArtist);
             if (artistsCD != null && !artistsCD.isEmpty())
             {
                System.out.println(artistsCD.get(0));
             }
             else
             {
                System.out.println("There are no titles for this artist");
             }
        }
        
        /**
         * Prompts the user to enter the details for a new CD
         * and returns the new CD as a message answer.
         */
        public CD getCDDetailsFromUser()
        {
           String artistCD = OUDialog.request("Enter artist");
           String titleCD = OUDialog.request("Enter title");
           String genreCD = OUDialog.request("Enter genre");
           String yearCD = OUDialog.request("Enter year");
           int intYearCD = Integer.parseInt(yearCD);
           CD userCD = new CD(artistCD, titleCD, genreCD, intYearCD);
           return userCD;
        }
        
        /**
         * Prompts the user for new CD details and adds the new CD to the end
         * of the list if it does not already exist.
         */
        public void addCD()
        {
             CD newCD = this.getCDDetailsFromUser();
             for (String eachCD : this.cdCatalogue.keySet()) 
             {
                List<CD> cdList = this.cdCatalogue.get(eachCD);
                for (CD everyCD : cdList)
                {
                   if(!newCD.equals(everyCD))
                   {
                      cdList.add(newCD);
                   }
                }
             }
        }
        
    }

  2. #2
    emceenugget is offline Senior Member
    Join Date
    Sep 2008
    Posts
    564
    Rep Power
    6

    Default

    when looking for a way to prevent an exception from occurring, it helps to actually look up what causes the exception.

    ConcurrentModificationException (Java 2 Platform SE 5.0)

    a google search of "prevent java.util.ConcurrentModificationException" gives the first result here: Learning From Code: Fast Fail Iterators, page 2 of 2

    it basically says that if you have an iterator for a collection and modify the collection, the iterator will see this and throw the exception.

  3. #3
    r035198x is offline Senior Member
    Join Date
    Aug 2009
    Posts
    2,388
    Rep Power
    7

    Default

    Your logic is wrong anyway. Your add method attempts to add the new CD as many times as there are CDs that are not the same as the new one. Suppose you have 100 CDs in the list and one of them is the same as the new one being added, then
    Java Code:
    if(!newCD.equals(everyCD))
    {
          cdList.add(newCD);
    }
    will add the new CD 99 times to the list.
    Why not just use something as simple as:
    Java Code:
    List<CD> cdList = this.cdCatalogue.get(eachCD);
    if(!cdList.contains(newCD )) {
        cdList.add(newCD);
    }

  4. #4
    mrmatt1111's Avatar
    mrmatt1111 is offline Senior Member
    Join Date
    Aug 2009
    Location
    San Jose, CA, USA
    Posts
    320
    Rep Power
    5

    Default

    Java Code:
    List<CD> cdList = this.cdCatalogue.get(eachCD);
    if(!cdList.contains(newCD )) {
        cdList.add(newCD);
    }
    Is not correct because in this case it will always be true:

    Java Code:
    CD newCD = this.getCDDetailsFromUser(); //always creates a new object
    My Hobby Project: LegacyClone

  5. #5
    r035198x is offline Senior Member
    Join Date
    Aug 2009
    Posts
    2,388
    Rep Power
    7

    Default

    Quote Originally Posted by mrmatt1111 View Post
    Java Code:
    List<CD> cdList = this.cdCatalogue.get(eachCD);
    if(!cdList.contains(newCD )) {
        cdList.add(newCD);
    }
    Is not correct because in this case it will always be true:
    Why will it always return true? The OP still has to get that newCD the same way they were doing it. No need to re-post it.

  6. #6
    mrmatt1111's Avatar
    mrmatt1111 is offline Senior Member
    Join Date
    Aug 2009
    Location
    San Jose, CA, USA
    Posts
    320
    Rep Power
    5

    Default

    Quote Originally Posted by r035198x View Post
    Why will it always return true? The OP still has to get that newCD the same way they were doing it. No need to re-post it.

    Comparing by reference isn't the same as comparing by contents. "contains" as far as i know compares by reference.

    So if "newCD" is a new object and this is the first time we see this particular list then "newCD" cannot be in the list; therefore:

    Java Code:
    if(!cdList.contains(newCD ))

    is always true (per instance of List).
    My Hobby Project: LegacyClone

  7. #7
    r035198x is offline Senior Member
    Join Date
    Aug 2009
    Posts
    2,388
    Rep Power
    7

    Default

    Quote Originally Posted by mrmatt1111 View Post
    Comparing by reference isn't the same as comparing by contents. "contains" as far as i know compares by reference.

    .
    No it does not. It simply does a check based on calling the equals method which checks the contents. Read the API specs for the method.

  8. #8
    mrmatt1111's Avatar
    mrmatt1111 is offline Senior Member
    Join Date
    Aug 2009
    Location
    San Jose, CA, USA
    Posts
    320
    Rep Power
    5

    Default

    Ack, you are right and i'm wrong. :)

    It does use equals. I should have checked that. =)
    My Hobby Project: LegacyClone

  9. #9
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default

    Quote Originally Posted by r035198x View Post
    No it does not. It simply does a check based on calling the equals method which checks the contents. Read the API specs for the method.
    OK I've tried this and as suspected it adds newCD to each individual ArrayList, so it gets added 14 times. And if you take the if statement outside the for loop cdList is not recognised as it is local to the for loop :confused:

    Java Code:
    public void addCD()
        {
             CD newCD = this.getCDDetailsFromUser();
             for (String eachCD : this.cdCatalogue.keySet()) 
             {
                List<CD> cdList = this.cdCatalogue.get(eachCD);
                System.out.println(cdList);
                if(!cdList.contains(newCD)) 
                {
                   cdList.add(newCD);
                }
             }
        }

  10. #10
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default

    Quote Originally Posted by r035198x View Post
    No it does not. It simply does a check based on calling the equals method which checks the contents. Read the API specs for the method.
    Here's a new angle to this.
    The CD gets added second from last in the list rather than at the end, and the exception still gets thrown :confused:

    Java Code:
    public void addCD()
        {
             CD newCD = this.getCDDetailsFromUser();
             List<CD> temp = new ArrayList<CD>();
             temp.add(newCD);
             for (String eachCD : this.cdCatalogue.keySet()) 
             {
                List<CD> cdList = this.cdCatalogue.get(eachCD);
                if(!cdList.contains(newCD)) 
                {
                   this.cdCatalogue.put(newCD.getArtist(), temp);
                }
             }
        }

  11. #11
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Another way to do this perhaps is something like so:
    1) check if the Map already has a List<CD> associated with the artist,
    2) if so extract that List from the Map and use it,
    3) and if not create a new List<CD>, place it in the Map and use it.

    For instance:
    Java Code:
      public void addCD() {
        CD newCD = this.getCDDetailsFromUser();
        String artist = newCD.getArtist();
        
        List<CD> cdList = cdCatalogue.get(artist);
        if (cdList == null) {
          cdList = new ArrayList<CD>();
          cdCatalogue.put(artist, cdList);
        }
        cdList.add(newCD);
      }
    
    }
    Last edited by Fubarable; 08-27-2009 at 11:03 PM.

  12. #12
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default

    Quote Originally Posted by trueblue View Post
    Here's a new angle to this.
    The CD gets added second from last in the list rather than at the end, and the exception still gets thrown :confused:

    Java Code:
    public void addCD()
        {
             CD newCD = this.getCDDetailsFromUser();
             List<CD> temp = new ArrayList<CD>();
             temp.add(newCD);
             for (String eachCD : this.cdCatalogue.keySet()) 
             {
                List<CD> cdList = this.cdCatalogue.get(eachCD);
                if(!cdList.contains(newCD)) 
                {
                   this.cdCatalogue.put(newCD.getArtist(), temp);
                }
             }
        }
    This works perfectly thank you but I fear I cannot use it because I have to stick to guidelines as below. I also have to re-use methods as much as possible. :(
    I think yours works perfectly with this slight modification so the CD goes at the end of the list
    Java Code:
    cdList.add(cdList.size(),newCD);
    "Add a public instance method to the MusicLibrary class called addCD(), which takes no arguments and returns no value. The method should first prompt the user for details of the CD to be added and create a new CD object with those details. It should then check whether the catalogue already contains that CD (duplicate CDs contain the same artist and the same title). If the CD is not in the catalogue, it is added to the end of the list, otherwise no further action is taken."

  13. #13
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Regardless of the specs, you first have to see if the Map contains the artist you are looking for. There is no escaping this. None. If the artist is in the Map, then sure check to see if the list has the CD prior to adding it, but again first you must check that the map contains the artist and associated list, and thereby make sure that you add the CD to the correct list.
    e.g.,
    Java Code:
      public void addCD() {
        CD newCD = this.getCDDetailsFromUser();
        String artist = newCD.getArtist();
        
        List<CD> cdList = cdCatalogue.get(artist);
        if (cdList == null) {
          cdList = new ArrayList<CD>();
          cdList.add(newCD);
          cdCatalogue.put(artist, cdList);
        } else {
          if (!cdList.contains(newCD)) {
            cdList.add(newCD);
          }
        }
      }
    Also, does CD override equals and hashCode? If not, it should.
    Last edited by Fubarable; 08-27-2009 at 11:48 PM.

  14. #14
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    Regardless of the specs, you first have to see if the Map contains the artist you are looking for. There is no escaping this. None. If the artist is in the Map, then sure check to see if the list has the CD prior to adding it, but again first you must check that the map contains the artist and associated list, and thereby make sure that you add the CD to the correct list.
    e.g.,
    Java Code:
      public void addCD() {
        CD newCD = this.getCDDetailsFromUser();
        String artist = newCD.getArtist();
        
        List<CD> cdList = cdCatalogue.get(artist);
        if (cdList == null) {
          cdList = new ArrayList<CD>();
          cdList.add(newCD);
          cdCatalogue.put(artist, cdList);
        } else {
          if (!cdList.contains(newCD)) {
            cdList.add(newCD);
          }
        }
      }
    Also, does CD override equals and hashCode? If not, it should.
    Remember it's a two pronged assault. I think your code will only check for the artist so will allow duplicates to get through. A duplicate CD contains the same artist and title as another CD.
    CD does override equals() - it does a boolean check for the artist and title of two CDs. This method needs to be re-used in the code for addCD().

  15. #15
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Quote Originally Posted by trueblue View Post
    Remember it's a two pronged assault.
    Yes, I know that.

    I think your code will only check for the artist so will allow duplicates to get through.
    Are you absolutely sure about that?
    Java Code:
          if (!cdList.contains(newCD)) {
            cdList.add(newCD);
          }
    Did you test it with duplicates?

  16. #16
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    Yes, I know that.


    Are you absolutely sure about that?
    Java Code:
          if (!cdList.contains(newCD)) {
            cdList.add(newCD);
          }
    Did you test it with duplicates?
    Yes I did test it with a CD with the same artist and title as an existing CD and it allowed it to be added.

  17. #17
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Hm, my code didn't allow duplicates when I tested it.
    1) are you sure that you tested the latest iteration of my suggestion?
    2) please post your CD class equals method.

  18. #18
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    Hm, my code didn't allow duplicates when I tested it.
    1) are you sure that you tested the latest iteration of my suggestion?
    2) please post your CD class equals method.
    I tested this and it seems to work OK

    Java Code:
    /**
        * Overrides the equals() method and returns true if the
        * artist & title of the receiver CD have the same state as
        * the artist and title of the argument CD. Otherwise false is returned.
        */
        public boolean equals(Object disc)
        {
           CD aDisc = (CD)disc; 
           boolean artistCD = this.getArtist().equals(aDisc.getArtist());
           boolean titleCD = this.getTitle().equals(aDisc.getTitle());
           if (artistCD && titleCD)
           {
              return true;
           }
           else
           {
              return false;
           }
        }

  19. #19
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Your equals looks OK except that it's usually a good idea to first do a "background" check on the Object to be compared, i.e.:
    Java Code:
        public boolean equals(Object disc)
        {
           if (disc == null || !(disc instanceof CD))
           {
             return false;
           }
    
           CD aDisc = (CD)disc; 
           boolean artistCD = this.getArtist().equals(aDisc.getArtist());
           boolean titleCD = this.getTitle().equals(aDisc.getTitle());
           if (artistCD && titleCD)
           {
              return true;
           }
           else
           {
              return false;
           }
        }

  20. #20
    trueblue is offline Member
    Join Date
    Mar 2009
    Posts
    57
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    Your equals looks OK except that it's usually a good idea to first do a "background" check on the Object to be compared, i.e.:
    Java Code:
        public boolean equals(Object disc)
        {
           if (disc == null || !(disc instanceof CD))
           {
             return false;
           }
    
           CD aDisc = (CD)disc; 
           boolean artistCD = this.getArtist().equals(aDisc.getArtist());
           boolean titleCD = this.getTitle().equals(aDisc.getTitle());
           if (artistCD && titleCD)
           {
              return true;
           }
           else
           {
              return false;
           }
        }
    I tested the equals override with several CD combos and all returned the correct boolean.
    I've looked at both our codes and come up with a hybrid but this doesn't work either as it throws a nullpointer exception

    Java Code:
    public void addCD() 
        {
           CD newCD = new CD("The Jam", "All Mod Cons", "Mod", 1978);//this.getCDDetailsFromUser();
           String anArtist = newCD.getArtist();
           List<CD> temp = new ArrayList<CD>();
           temp.add(newCD);    
           List<CD> artistCDList = cdCatalogue.get(anArtist);
           for (CD eachCD : artistCDList) 
           {
              if(!eachCD.equals(newCD)) 
              {
                 this.cdCatalogue.put(newCD.getArtist(), temp);
              }
           }
        }

Similar Threads

  1. Replies: 5
    Last Post: 02-27-2009, 05:19 AM
  2. Exception in thread "main" java.util.NoSuchElementException
    By vileoxidation in forum New To Java
    Replies: 5
    Last Post: 09-17-2008, 07:29 AM
  3. Replies: 1
    Last Post: 07-02-2008, 02:15 PM
  4. Replies: 4
    Last Post: 06-08-2008, 02:19 PM
  5. Replies: 5
    Last Post: 05-14-2008, 01:43 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •