-2

So what this program does is processes ArrayList by using the Iterator method and prints them out.

I'm making my own Iterator by overriding and what I need help with is the remove method from Iterator.

Code:

public class MyArrayList implements Iterable<Object> {
public static final int DEFAULT_SIZE = 5;
public static final int EXPANSION = 5;
private int capacity;
private int size;
private Object[] items;
private int currentSize;
int modCount = 0;
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;


public MyArrayList() {
    size = 0;
    capacity = DEFAULT_SIZE;
    items = new Object[DEFAULT_SIZE];
    this.currentSize = items.length;
}


@Override
public Iterator<Object> iterator() {
    Iterator<Object> it = new Iterator<Object>() {
        private int currentIndex = 0;

        @Override
        public boolean hasNext() {
        try { return currentIndex <= currentSize && items[currentIndex] != null;
        }catch(NoSuchElementException e){
            System.out.println("There is nothing in the next element.");
        }
            return currentIndex <= currentSize && items[currentIndex] != null;
        }

        @Override
        public Object next() {
            checkForComodification();
            try{
        }catch(NoSuchElementException e){
            System.out.println("There is nothing in the next element.");
        }
            return items[currentIndex++];
        }

        @Override
        public void remove(){
            if (lastRet< 0)
                throw new IllegalStateException();
            checkForComodification();
        try {
            MyArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        }catch (IndexOutOfBoundsException e){
            throw new ConcurrentModificationException();
            }

        }

    final void checkForComodification(){
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }


    };
    return it;
}


private void expand() {
    Object[] newItems = new Object[capacity + EXPANSION];
    for (int j = 0; j < size; j++) newItems[j] = items[j];
    items = newItems;
    capacity = capacity + EXPANSION;
}

public void add(Object obj) {
    try {
        if (size >= capacity) this.expand();
        items[size] = obj;
        size++;
    } catch (IndexOutOfBoundsException e) {
        System.out.println("There is an error adding this word." + e.getMessage());
    }
}

public int size() {
    return size;
}

public Object get(int index) {
    try {
        return items[index];
    }catch (ArrayIndexOutOfBoundsException e){
        System.out.println("ERROR- Cannot GET element. Index is out of range. Position: " +e.getMessage());
    }
    return items[index];
}


public boolean contains(Object obj) {
    for (int j = 0; j < size; j++) {
        if (obj.equals(this.get(j))) return true;
    }
    return false;
}

public void add(int index, Object obj) {
    try {
        if (size >= capacity) this.expand();
        for (int j = size; j > index; j--) items[j] = items[j - 1];
        items[index] = obj;
        size++;
    }catch (IndexOutOfBoundsException e){
        System.out.println("ERROR- Cannot ADD element. Index out of range. Position: " +e.getMessage()+".");
    }
}

public int indexOf(Object obj) {
    for (int j = 0; j < size; j++) {
        if (obj.equals(this.get(j))) return j;
    }
    return -1;
}

public boolean remove(Object obj) {
    for (int j = 0; j < size; j++) {
        if (obj.equals(this.get(j))) {
            for (int k = j; k < size - 1; k++) items[k] = items[k + 1];
            items[size] = null;
            size--;
            return true;
        }
    }
    return false;
}

public Object remove(int index) {
    try {
        Object result = this.get(index);
        for (int k = index; k < size - 1; k++) items[k] = items[k + 1];
        items[size] = null;
        size--;
        return result;
    }catch(IndexOutOfBoundsException e){
        System.out.print("ERROR- Cannot REMOVE element. Index out of range. Position: " + e.getMessage());
    }
    return null;
}

public void set(int index, Object obj) {
    try {
        items[index] = obj;
    }catch (IndexOutOfBoundsException e){
        System.out.println("ERROR- Cannot SET word.. Index out of range. Position: "+e.getMessage());
    }
}

}

Main method code:

class Task4Test {

static MyArrayList zoo = new MyArrayList();


public static void printZoo() {
    System.out.print("The zoo now holds " + zoo.size() + " animals: ");
    for (int j = 0; j < zoo.size(); j++) System.out.print(zoo.get(j) + " ");
    System.out.println();
}
public static void main(String[] args) {

    String[] zooList = {"Cheetah", "Jaguar", "Leopard", "Lion", "Panther", "Tiger"};

    for (String x: zooList) zoo.add(x);
    printZoo();

    System.out.printf("\nTesting the iterator\n>> ");
    Iterator it = zoo.iterator();
    while (it.hasNext()) {
        System.out.print(it.next() + " ");
    }
    System.out.println();

    System.out.printf("\nTesting the iterator again without resetting\n>> ");
    while (it.hasNext()) {
        System.out.print(it.next() + " ");
    }
    System.out.println();

    System.out.printf("\nTesting the iterator again after resetting\n>> ");
    it = zoo.iterator();
    while (it.hasNext()) {
        System.out.print(it.next() + " ");
    }
    System.out.println();

    System.out.printf("\nTesting for-each loop\n>> ");
    for(Object animal: zoo) System.out.print(animal + " ");
    System.out.println();

    System.out.println("\nLetting all the animals escape");
    while (zoo.size()>0) zoo.remove(0);
    printZoo();

    System.out.printf("\nTesting the iterator with an empty list\n>> ");
    it = zoo.iterator();
    while (it.hasNext()) {
        System.out.print(it.next() + " ");
    }
    System.out.println();

    System.out.println("\nTest complete");


}

}

Now this prints out: The zoo now holds 6 animals: Cheetah Jaguar Leopard Lion Panther Tiger

 Testing the iterator
 >> Cheetah Jaguar Leopard Lion Panther Tiger 

 Testing the iterator again without resetting
 >> //Is it supposed to be empty like this? (read below)

 Testing the iterator again after resetting
 >> Cheetah Jaguar Leopard Lion Panther Tiger 

 Testing for-each loop
 >> Cheetah Jaguar Leopard Lion Panther Tiger 

 Letting all the animals escape
 The zoo now holds 0 animals: 

Testing the iterator with an empty list
>> Tiger //This is the main problem i'm trying to fix.

So for some reason Tiger always keep getting printed. Even when I change up loads of different methods. I have a feeling it could be something to do with Object remove(int index) method.

Furthermore, I understand after the "iterator without resetting" section there should be nothing but with my code shouldn't there be an Exception saying "There is nothing in the next element"?

John Conde
  • 217,595
  • 99
  • 455
  • 496
bob9123
  • 725
  • 1
  • 9
  • 31
  • Not quite sure what your problem is. Do you not want Tiger to be always printed? If yes, then when do you need it printed? – Cristik Apr 15 '15 at 21:23
  • Can you explain what your code is supposed to be doing rather than simply dumping it here for us to slog through? – Hovercraft Full Of Eels Apr 15 '15 at 21:24
  • @Cristik Sorry that my description is not clear enough. So the remove iterator method should remove ALL elements in the array. So there should be nothing printed but it prints out "Tiger". – bob9123 Apr 15 '15 at 21:28
  • @HovercraftFullOfEels I'm sorry, I made more clear now. – bob9123 Apr 15 '15 at 21:28
  • Why are you creating your own iterator? Why not use the collections own iterator to remove the item? – Hovercraft Full Of Eels Apr 15 '15 at 21:31
  • @HovercraftFullOfEels It's the question that has to be done from the book. – bob9123 Apr 15 '15 at 21:31
  • There's no exception in the "iterator without resetting" section because you never create and throw a `NoSuchElementException`. Having a catch block doesn't mean that exception is necessarily going to happen, and since you control all the code in the try block, you can see it never will throw one. – Michael Myers Apr 15 '15 at 21:41
  • Thanks @MichaelMyers , I fixed that. Do you have any idea how to sort out the remove method error? – bob9123 Apr 16 '15 at 17:44

1 Answers1

1

hasNext() behaviour

Your hasNext() method is behaving exactly as you programmed it - returning the result of the conditional within your try block, so it will simply return false and therefore the loop where you try to go through the iterator without resetting will never be entered. No Exception will be thrown.

EDIT : in response to comments

Let's dissect that in a little more detail - your current method is:

@Override
public boolean hasNext() {
    try { 
        return currentIndex <= currentSize && items[currentIndex] != null;
    }
    catch(NoSuchElementException e) {
        System.out.println("There is nothing in the next element.");
    }

    return currentIndex <= currentSize && items[currentIndex] != null;
}

in the try block, you effectively perform two comparisons that will each result in boolean and then && them together and return the result. The first is

currentIndex <= currentSize

This, presumably, is to check that you iterator is not "beyond the end" of the list. This will evaluate false if currentIndex not bigger than currentSize. In fact, I think this is bugged because currentSize appears to be set at construction time and never altered, but that is beside the point here.

The second is

items[currentIndex] != null

If currentIndex is not beyond the end of items, then the value of items[currentIndex] will simply be tested against null. The only case where an Exception would be thrown is where currentIndex >= items.length. Note, though, the exception that would be thrown here would not be a NoSuchElementException, but an ArrayIndexOutOfBoundsException. The NoSuchElementException is (usually, in the standard language libraries) thrown by an Enumeration.

Finally, you && these together. Now, this is a slightly tricky part for completeness. Because of the way that && is evaluated in Java - if the first condition is false the second is never evaluated. So, if the first conditional is false, your function returns false immediately. If the first is true, your function returns the value of the second.

So, in reality, your try...catch construct here is entirely redundant as the condition in the return will not fail and, even if it did, it would not throw the type of Exception you are catching anyway. Furthermore, the second return statement in that method is redundant and is evaluating exactly the same experession as the one in the try anyway, so if that one failed, so would the second.

Last, but not least, you should be aware that anything in your particular implementation that relies on the size of items to throw an Exception is likely to be buggy anyway - because items.length is not constrained to be the same as size. When you null the values in items, you don't "remove" them from the array - so referring to them will not throw an Exception, it will simply refer to a value of null

remove(int index) behaviour

Your remove(int index) doesn't behave as you like because of you null out the element at items[size] before you decrement size reverse those two statements and it should work as you want

Final comment

I've addressed your direct questions. However - there are other bugs within your implementation e.g. try calling next() when hasNext() is false. You will get an ArrayIndexOutOfBoundsException. I think you intend to satisfy the Iterator interface specification and throw a NoSuchElementException.

I suspect you have fundamentally misunderstood the try...catch concept as well as the throw. Your code should be throwing the NoSuchElementException, not trying to catch it - after all what would be generating it? I think it's worth reading the Oracle tutorial on Exceptions,try...catch,throw etc., possibly asking another question about it, or asking your tutor.

In brief - you have two things here - you have the underlying code that can detect nasty things happening and generate exceptions e.g.

public Object get(int index) throws NoSuchElementException
{
    // error check for -ve index and throw exception if detected
    if (index < 0)
    {
         throw new NoSuchElementException();
    }

    //code to do the real processing if index is correct
}

and then you have other code using features / methods that might throw exceptions and either

a) allows the Exception to be thrown onwards, or

b) (your case) catches the Exception and does something else with it - e.g.

try {
    Object x = items[myIndex];
}
catch (ArrayIndexOutOfBoundObject e) {
    //Do some processing e.g. output a message
    System.err.println("Naughty, naughty - " + myIndex + " is out of bounds";
    // and:or throws a potentially different exception
    throw new NoSuchElementException(e.message());
}
Community
  • 1
  • 1
J Richard Snape
  • 20,116
  • 5
  • 51
  • 79
  • Thanks for the remove solution. I've finally done it. Now I still don't understand fully the Exception bit after looking at google/youtube pages for ages. I have updated my code for this. My logic on this is that it will TRY to see if there is an element at the next section. If there isn't there will be an error/false and it will catch it and print out the message. However my logic is obviously still wrong and I don't understand it as my layout for try/catch is same as pages I have seen. – bob9123 Apr 17 '15 at 13:39
  • OK - I'll update to expand on that to hopefully cover all the bases and make the answer OK to accept. – J Richard Snape Apr 17 '15 at 13:43
  • You're welcome - hope it helped your understanding. Thanks for the accept / vote. – J Richard Snape Apr 17 '15 at 15:27