Hi there!

So I'm working on my next assignment and it's all about implementing a few exceptions in order to get us familiar with the topic.

I am tasked with implementing 3 very simple exceptions to my previous program. So far I have 2 out of 3 working fine with zero issues.

It's the third one that's causing me some headaches. Now, I will be honest, I posted a similar topic to this on another board, but I left out a few details that weren't extremely relevant to the main problem here. I will post those to see if you guys would be able to help me out!

Well first thing's first, here's my code. It's very long and I will make sure to bold the areas of interest. Also, I'm only posting the relevant classes:

MAIN:

package assignment.pkg3;

import java.util.Scanner;

public class Assignment3 {
    
 //Function for user menu display and input
    public static int getMenuChoice()
        {
            Scanner keyboard = new Scanner(System.in);
            
            System.out.println("\n-----------------------------"
            + "\nHere are your Choices: \n"
            + "Enter 1 to add a Subscriber \n"
            + "Enter 2 to add an Application \n"
            + "Enter 3 to remove a Subscriber \n"
            + "Enter 4 to remove an Application \n"
            + "Enter 5 to display all Subscribers \n"
            + "Enter 6 to display all Applications \n"
            + "Enter 7 to Quit "
                    + "\n-----------------------------\n");
            
            return keyboard.nextInt();
        }
    
    public static void main(String[] args) 
    {
        //Field Declarations
        Set<Element> anElementSet;
        Element anElement;
        Subscriber aSub;
        Application anApp;
        
        Scanner keyboard = new Scanner(System.in);
        
        int menuChoice;
        
        String search = "";
        
        boolean isDone = false;
        boolean correctInt = false;

        menuChoice = getMenuChoice();
        
        anElementSet = new Set<Element>();
        
        
        //Initiate loop to display menu
        while(!isDone)
        {
             if(menuChoice == 7)
            {
                System.out.println("Are you sure you want to quit? (Y/N)");
                String askQuit;
                askQuit = keyboard.nextLine().toUpperCase();
                
                if(askQuit.equals("Y"))
                {
                    isDone = true;
                    break;
                }
            }
             
             switch(menuChoice)
            {
                
            case 1:
                //add subscriber to Element Set array
                anElement = new Subscriber();
                do
                {
                    try
                    {
                    anElement.readIn();
                    correctInt = true;
                    }
                    catch(NegativeIntException e)
                    {
                       System.out.println("\nTry again.");
                       correctInt = false;
                    }
                    catch(NumberFormatException e)
                    {
                       System.out.println("\nTry again.");
                       correctInt = false; 
                    }
                }
                while(!correctInt);
                //Try to add the member
                try
                {
                anElementSet.add(anElement);
                }
                catch(DuplicateObjectException e)
                {
                    System.out.println("\nPlease enter a different Subscriber");                          
                }
            break;
            
            case 2:
                //add application to Element Set array
                anElement = new Application();
                do
                {
                    try
                    {
                    anElement.readIn();
                    correctInt = true;
                    }
                    catch(NegativeIntException e)
                    {
                       System.out.println("\nTry again.");
                       correctInt = false;
                    }
                    catch(NumberFormatException e)
                    {
                       System.out.println("\nTry again.");
                       correctInt = false; 
                    }
                }
                while(!correctInt);
                //Try to add the member
                try
                {
                anElementSet.add(anElement);
                }
                catch(DuplicateObjectException e)
                {
                    System.out.println("\nPlease enter a different Application.");              
                }
            break;
                
            case 3:
                //remove subscriber from Element Set array
                [B]System.out.println("Enter Subscriber's name: ");
                search = keyboard.nextLine().toUpperCase();
                
                 for(int i = 0; i < anElementSet.size(); i++)
                {
                    anElement = anElementSet.getCurrent();

                    if(anElement instanceof Subscriber)
                    { 
                        aSub =(Subscriber)anElement;      
                    
                        try
                        {
                            if((aSub.getName()).equals(search))
                            {
                                anElementSet.removeObject(aSub);       
                            }
                        }
                        catch(CannotRemoveException e)
                        {
                              System.out.println("Member not found, "
                                    + "removal unsuccessful.");
                        }

                    }
                }[/B]
                
                
                 
                 break;
                
            case 4:
                //remove application from Element Set array
                [B]System.out.println("Enter Application's name: ");
                search = keyboard.nextLine().toUpperCase();
                
                 for(int i = 0; i < anElementSet.size(); i++)
                {
                    anElement = anElementSet.getCurrent();

                    if(anElement instanceof Application)
                    { 
                        anApp =(Application)anElement;
                    
                        try
                        {
                            if((anApp.getName()).equals(search))
                            {
                                anElementSet.removeObject(anApp);       
                            }
                        }
                        catch(CannotRemoveException e)
                        {
                              System.out.println("Member not found, "
                                    + "removal unsuccessful.");
                        }

                    }
                }[/B]
                 
                break;
                
            case 5:
                //display all Subscribers in the Element Set array
                anElementSet.displayAllInClass(Subscriber.class.getName());
                break;
                
            case 6:
                //display all Applications in the Element Set array
                anElementSet.displayAllInClass(Application.class.getName());
                break;
             }
             menuChoice = getMenuChoice();
        }
    }
}

ARRAYLIST (SET) CLASS:

package assignment.pkg3;   

import java.util.ArrayList;

  /**
     This revised version of the Set<T> generic class uses
	  the revised version of the Element class, the version
	  that uses the Object parameter for the abstract method,
	  equals..
	  
	  This allows us to reintroduce the isMemberOf method to
	  the Set data structure.	  
  */
  
    public class Set <T>
   {
      // Fields ...
      ArrayList<T> theList;   
   	                  // Will reference an ArrayList of objects
                        // from the class T.
      int currentIndex;   
   	                  // Index of current element in the set
      final int START_CAP = 100;
                        // Initial capacity of the ArrayList.
   							// This over-rides the default initial
   							// capacity of 10.  
   							     
   // Constructor ...
   
   /**
      The Set constructor sets up an ArrayList of T references
   	with STARTSIZE-many cells. It also initializes currentIndex
   	to -1.
   */
   
       public Set()
      {
         theList = new ArrayList<T>(START_CAP);
         currentIndex = -1;
      }
      
   // Test methods
   
   /**
      The isEmpty method returns true if the calling object
   	is empty and false otherwise.
   	@return true if the calling object is empty and false
   	        otherwise.
   */
   
       public boolean isEmpty()
      {
         return theList.isEmpty();
      }
   
   /**
      The isMemberOf method tests to see if the parameter, aT,
   	is already a member of the Set.  This assumes the type
   	T has an appropriate equals method, redefining the Object
   	class equals method, so that we are not just comparing
   	references.
    	@param anElement the object being checked for membership in
   	       the set
   	@return true if anElement is already in the set and false
    */
   
       public boolean isMemberOf(T aT)
      {
         // Local data ...
         String paramClass = aT.getClass().getName();
         String currClass;
      	
      	// Logic ...
         for (T currT: theList)
         {
            currClass = currT.getClass().getName();
         	
         	// Only compare aT against those objects
         	// that belong to aT's class
            if (currClass.equals(paramClass))
            {
               if (currT.equals(aT))
               {
                  return true;
               }
            }
         }
      	
      	// No matching object found
         return false;
      }
   
   // Access methods
   
   /**
      The size method returns the number of objects 
   	currently in the set.
   	@return the value of currentSize
   */
   
       public int size()
      {
         return theList.size();
      }
   
   /**
      The getCurrent() method returns a reference to the
   	current object in the set.  Note the pre-condition.
   	This method should only be called if the set is
   	not empty.  The method advances currentIndex to
   	the next object to set up for the next call to
   	getCurrent.  If getCurrent returns a copy of
   	the last object, currentIndex is reset to 0. Note
   	that this method assumes the type T has a 
   	copy constructor.
   	Pre: currentIndex is not -1 (which can only
   	     occur if currentSize is not 0).
   	@return reference to the current object in the set
   */
   
       public T getCurrent()
      {
         // Local data ...
         int saveIndex = currentIndex;
      	
      	// Logic ...
         if (currentIndex == theList.size() - 1)
         {
         // Recycle to beginning of list
            currentIndex = 0;
         }
         else
         {
         // Advance currentIndex to next object
            currentIndex++;
         }
         
      	// Return a reference to the current object
         return theList.get(saveIndex);
                  // NOTE:  WE ARE RETURNING A REFERENCE
      				// TO AN OBJECT IN THE SET, NOT A COPY 
      				// OF THE OBJECT. WHY?  BECAUSE IF WE
      				// TRIED TO USE THE clone() METHOD HERE
      				// THE COMPILER GETS GRUMPY!  ALL METHODS
      				// WE APPLY TO OBJECTS IN THE SET MUST BE
      				// IN THE Object CLASS. 
      }
   
   // Mutator methods ...
      
   /**
       The add method attempts to add the aT parameter to the set.
   	 It will fail if aT is already in the calling object set.
     	 @param aT the T-thing we attempt to add
   	 @return false if the object is a duplicate and 
   	         it couldn't be added and true otherwise
   */
   
       public void add(T aT)
               throws DuplicateObjectException
      {
              
             // Check if aT is already in the calling object
             if (this.isMemberOf(aT))             
             {
                 throw new DuplicateObjectException(aT);
             }
             
             theList.add(aT);
     
             if (theList.size() == 1)
             { 
                currentIndex = 0;
           
                // Successful add
                System.out.println("\nMember successfully added to set.");
             }
          }
      
   	 
   /**
      The clear method resets the set to the empty set.
   */
   
       public void clear()
      {
         currentIndex = -1;
         theList = new ArrayList<T>();
      }
       
       [B]public void removeObject(T anObject)
               throws CannotRemoveException
       {
         String paramClass = anObject.getClass().getName();
         String currClass;
         int removalCount = 0;
         
       // Logic ...
         for (T currT: theList)
         {
            currClass = currT.getClass().getName();

            if (currClass.equals(paramClass))
            {
               if (currT.equals(anObject))
               {
                  theList.remove(anObject);
                  System.out.println("Member found and has been removed from "
                          + "the set.");
                  removalCount++;
               }              
            }
         }
         
         if (removalCount == 0)
         {
             throw new CannotRemoveException();
         }
       }
       [/B]
       //Declare universal class display method
    public void displayAllInClass(String theClassName)
    {
        if (theList.isEmpty())
         {
            System.out.println("There are no members in the set. ");
         }
        else
        {  
            for (int i = 0; i < theList.size(); i++)
            {        
                
               if(theClassName.equals(theList.get(i).getClass().getName()))
               {
                   System.out.println(theList.get(i).toString());
                   System.out.println("\n");
               }
            }
        }
    }
   
   // The display method
   
   /**
      The display method displays all of the objects in the
   	set.  This method assumes that the class T implements
   	the toString method in an appropriate manner, so that
   	the contents of the relevant object can be displayed.
   */
   
       public void display()
      {
         // Local variables
       	                     // we will display
         if (theList.isEmpty())
         {
            System.out.println("There are no objects in the set. ");
         }
         else
         {
            System.out.println("Here are the objects in the set: \n");
            for (int i = 0; i < theList.size(); i++)
            {
               System.out.println(theList.get(i).toString());
               System.out.println("\n");
            }
         }
      
      }
   }

Okay! So I bolded the areas that are giving me issues. I can't quite figure out the logic for the exceptions in main that will coincide with how I have the function call set up, if that makes sense.

Here's a test run of me attempting to remove a non-existent object:

-----------------------------
Here are your Choices:
Enter 1 to add a Subscriber
Enter 2 to add an Application
Enter 3 to remove a Subscriber
Enter 4 to remove an Application
Enter 5 to display all Subscribers
Enter 6 to display all Applications
Enter 7 to Quit
-----------------------------

1
Subscriber's name:
b
Subscriber's url:
b
Subscriber's ad clicks:
123

Member successfully added to set.

-----------------------------
Here are your Choices:
Enter 1 to add a Subscriber
Enter 2 to add an Application
Enter 3 to remove a Subscriber
Enter 4 to remove an Application
Enter 5 to display all Subscribers
Enter 6 to display all Applications
Enter 7 to Quit
-----------------------------

3
Enter Subscriber's name:
g

-----------------------------
Here are your Choices:
Enter 1 to add a Subscriber
Enter 2 to add an Application
Enter 3 to remove a Subscriber
Enter 4 to remove an Application
Enter 5 to display all Subscribers
Enter 6 to display all Applications
Enter 7 to Quit
-----------------------------

It just does nothing.

Here's what happens if I attempt to remove an object that exists in the set:

-----------------------------
Here are your Choices:
Enter 1 to add a Subscriber
Enter 2 to add an Application
Enter 3 to remove a Subscriber
Enter 4 to remove an Application
Enter 5 to display all Subscribers
Enter 6 to display all Applications
Enter 7 to Quit
-----------------------------

1
Subscriber's name:
b
Subscriber's url:
b
Subscriber's ad clicks:
123

Member successfully added to set.

-----------------------------
Here are your Choices:
Enter 1 to add a Subscriber
Enter 2 to add an Application
Enter 3 to remove a Subscriber
Enter 4 to remove an Application
Enter 5 to display all Subscribers
Enter 6 to display all Applications
Enter 7 to Quit
-----------------------------

3
Enter Subscriber's name:
b
Member found and has been removed from the set.
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at assignment.pkg3.Set.removeObject(Set.java:199)
at assignment.pkg3.Assignment3.main(Assignment3.java:150)
Java Result: 1
BUILD SUCCESSFUL (total time: 9 seconds)

Whoa! What the heck is that!!??

I am greatly confused here and any guidance would be extremely helpful! If you need any more info I can post more of my code, just let me know! Thank you!

I think I see the problem. When the user presses on Remove object from list, the method has a loop.
However, everytime you ask an object from the list, you call getCurrent(), nothing to do with the loop.

I hope this will solve it!

I think I see the problem. When the user presses on Remove object from list, the method has a loop.
However, everytime you ask an object from the list, you call getCurrent(), nothing to do with the loop.

I hope this will solve it!

I am not sure what you mean.

Is it this line?

anElement = anElementSet.getCurrent();

If so, the getCurrent method was one provided to us by our instructor. I believe that, couple with the for loop, it just advances through each object in the set. I use it in the search for an object with the same name as the string entered by the user. How could that be causing the issue?

Thanks!

You are right. I didn't understand getCurrent() when I saw it...
(The name doesn't really describe it's function)

Could you post a zip with all the source files in it? I would like to test the program myself, I can't see what the problem is from this code.

You are right. I didn't understand getCurrent() when I saw it...
(The name doesn't really describe it's function)

Could you post a zip with all the source files in it? I would like to test the program myself, I can't see what the problem is from this code.

Sure thing, check attached.

Thanks again for the help.

Ah, I found it!

I have run into that problem a while ago, they should make a seperate Exception for it:
You are trying to remove an Object, from a Set/List you are iterating over:

for (T currT: theList)
         {
            currClass = currT.getClass().getName();

            if (currClass.equals(paramClass))
            {
               if (currT.equals(anObject))
               {
                  theList.remove(anObject);
                  System.out.println("Member found and has been removed from "
                          + "the set.");
                  removalCount++;
               }              
            }
         }

You are trying to remove anObject, from the Set/List in the for loop.
To solve it, I made a temporary object, and removed the object from the List/Set when the loop is done.

I haven't yet found out why there is no exception when the user enters a name that is not in the list, but I'll look into that.

I am not exactly sure what you mean by creating a temporary object as I have never done something like that before.

I did, though, find that the problem stems from the function being void as opposed to something like a boolean. Example (the exceptions may be wrong, but I just did this to test):

public boolean removeObject(T anObject)
               throws CannotRemoveException
       {
         String paramClass = anObject.getClass().getName();
         String currClass;
         int removalCount = 0;
         
       // Logic ...
         for (T currT: theList)
         {
            currClass = currT.getClass().getName();
            
            if (currClass.equals(paramClass))
            {
               if (currT.equals(anObject))
               {
                  theList.remove(anObject);
                  System.out.println("Member found and has been removed from "
                          + "the set.");
                  removalCount++;
                  return true;
               }              
            }
         }
         
         if (removalCount == 0)
         {
             throw new CannotRemoveException();
         }
                      return false;
       }

Removes the object without issues. I need the function to be void, though. I know you found a solution for the issue, but I am not familiar with that method so maybe this new info will help to find an alternate solution.

Edit:

Bear in mind that a fair amount of the code in the SET class was given by our instructor, so don't assume that I wrote everything! :P

Edited 5 Years Ago by Syrne: n/a

Inside the Set class:

public void removeObject(T anObject)
               throws CannotRemoveException
       {
         String paramClass = anObject.getClass().getName();
         String currClass;
         int removalCount = 0;
         
         T removeObject = null; // removeObject is my temporary object (not an official name)
       // Logic ...
         for (T currT: theList)
         {
            currClass = currT.getClass().getName();

            if (currClass.equals(paramClass))
            {
               if (currT.equals(anObject))
               {
            	   removeObject = anObject; // set removeObject as anObject
                  System.out.println("Member found and has been removed from "
                          + "the set.");
                  removalCount++;
               }              
            }
         }
         if (removeObject != null)
        	 theList.remove (removeObject); // remove the object from the list, when the loop is finished.
         
         if (removalCount == 0)
         {
             throw new CannotRemoveException();
         }
       }

(I hope for your instructor that he has not written this part...)

Inside the Set class:

public void removeObject(T anObject)
               throws CannotRemoveException
       {
         String paramClass = anObject.getClass().getName();
         String currClass;
         int removalCount = 0;
         
         T removeObject = null; // removeObject is my temporary object (not an official name)
       // Logic ...
         for (T currT: theList)
         {
            currClass = currT.getClass().getName();

            if (currClass.equals(paramClass))
            {
               if (currT.equals(anObject))
               {
            	   removeObject = anObject; // set removeObject as anObject
                  System.out.println("Member found and has been removed from "
                          + "the set.");
                  removalCount++;
               }              
            }
         }
         if (removeObject != null)
        	 theList.remove (removeObject); // remove the object from the list, when the loop is finished.
         
         if (removalCount == 0)
         {
             throw new CannotRemoveException();
         }
       }

(I hope for your instructor that he has not written this part...)

No, I wrote that function in its entirety. Also, I see now. When attempting your method I was creating an object, but not removing it correctly. Here's what I tried:

for (T currT: theList)
         {
            currClass = currT.getClass().getName();
            
            if (currClass.equals(paramClass))
            {
                T aTempObject = anObject;
               if (currT.equals(aTempObject))
               {
                  theList.remove(aTempObject);
                  System.out.println("Member found and has been removed from "
                          + "the set.");
                  removalCount++;
               }              
            }
         }

I understand now that I needed a separate statement that removes the temporary object. Thank you, I will continue looking into the issue of the exception not executing as well and report back with any new findings!

Great, good job! I probably should have called it something else, but that's hard to describe...

If I find out why the second problem is there, I'll tell you (haven't found out yet)!

The ListIterator interface exists specifically to solve this problem (illegal modification of the List while it is being iterated over with a normal Iterator).
Use theList.getListIterator() to get the list iterator and use that to loop thru the ArrayList - you'll be able to remove the appropriate element without generating an Exception. See the API doc for details.

ps There's a subtle problem with hiddepolen's solution, which is that the code to identify the object to remove tests for the class name being the same before it tests equals(...). However, the remove(...) method just tests for equals(...), so it's possible that there is an element before the right one that is of a different class (presumably a super or sub class) that also equals(...) and that will be removed instead. I admit that this is a bit obscure, however.

Edited 5 Years Ago by JamesCherrill: n/a

Great, good job! I probably should have called it something else, but that's hard to describe...

If I find out why the second problem is there, I'll tell you (haven't found out yet)!

I know why it is not throwing any exceptions. It's a logic issue.

Consider my try/catch statements:

for(int i = 0; i < anElementSet.size(); i++)
                    {
                        anElement = anElementSet.getCurrent();

                        if(anElement instanceof Subscriber)
                        { 
                            aSub =(Subscriber)anElement; 

                            try
                            {
                                if((aSub.getName()).equals(search))
                                {
                                    anElementSet.removeObject(aSub);       
                                }

                            }
                            catch(CannotRemoveException e)
                            {
                                  System.out.println("Member not found, "
                                        + "removal unsuccessful.");
                            }

                        }

The removeObject function containing the exception throw will NEVER be called if the input does not match an object here:

if((aSub.getName()).equals(search))
      {
         anElementSet.removeObject(aSub);       
      }

No exception will ever be thrown. The thing is, I am not sure how else I would check that the input matches. Is there some sort of way to do the check in the removeObject function itself? Like add another parameter (string) to the function?

So confused here, I despise logic issues! Thank you for the great help.

The ListIterator interface exists specifically to solve this problem (illegal modification of the List while it is being iterated over with a normal Iterator).
Use theList.getListIterator() to get the list iterator and use that to loop thru the ArrayList - you'll be able to remove the appropriate element without generating an Exception. See the API doc for details.

ps There's a subtle problem with hiddepolen's solution, which is that the code to identify the object to remove tests for the class name being the same before it tests equals(...). However, the remove(...) method just tests for equals(...), so it's possible that there is an element before the right one that is of a different class (presumably a super or sub class) that also equals(...) and that will be removed instead. I admit that this is a bit obscure, however.

I will definitely research this further then. Thank you.

Edited 5 Years Ago by Syrne: n/a

Okay, so I figured out how to implement the string check, but I ran into a problem.

Here's the current revised function:

public void removeObject(T anObject, String userInput)
               throws CannotRemoveException
       {
         String paramClass = anObject.getClass().getName();
         String currClass;
         int removalCount = 0;
         
         T aTempObject = null;
         System.out.println(paramClass);
         
       // Logic ...
         for (T currT: theList)
         {
            currClass = currT.getClass().getName();
           
            if (currClass.equals(paramClass))
            {
               if (currT.equals(anObject) && userInput.equals(anObject.getName()))
               {
                  aTempObject = anObject;
               }              
            }
         }
         
         if (aTempObject != null)
         {
             theList.remove(aTempObject);
             removalCount++;
             System.out.println("\nMember found and has been removed from "
                          + "the set.");
         }
         
         if (removalCount == 0)
         {
             throw new CannotRemoveException();
         }
       }

this line:

userInput.equals(anObject.getName())

Does not work, why is this? How can I get the name of the object any other way?


I receive a "Cannot find symbol" error.
Symbol: method getName()
Location: variable anObject of type T

Any ideas?

Cannot Find Symbol is an error when you try to call a method or variable that does not exist.
I think you need anObject.getClass().getName(), just like you did previously.

I don't mean to butt in here, so please feel free to ignore this post.

This method seems to be spiralling into more and more complexity, but I didn't see anything in the requirements that needs it to be so hard.
What's wrong with something simple like:

public void removeObject(T anObject) throws CannotRemoveException {
   boolean removedOK =  theList.remove(anObject);
   if (removedOK) return;
   else throw new CannotRemoveException ();
}

(that was the long version for clarity) you can code it as

public void removeObject(T anObject) throws CannotRemoveException {
   if (! theList.remove(anObject)) throw new CannotRemoveException ();
}

Yeah, that's better, but usually it complicates things when you start changing other peoples code (maybe there is some requirement), if the code is correct.

... usually it complicates things when you start changing other peoples code (maybe there is some requirement), if the code is correct.

Yes, I agree. I only jumped in here because things seemed to be getting more and more complex without ever getting correct. Anyway, I'll leave you in peace now.
J

This question has already been answered. Start a new discussion instead.