无法弄清楚如何修复我的 Iterator remove 方法

Can't figure out how to fix my Iterator remove method

所以这个程序所做的是使用 Iterator 方法处理 ArrayList 并将它们打印出来。

我正在通过覆盖创建自己的迭代器,而我需要帮助的是迭代器的移除方法。

代码:

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());
    }
}

}

主要方法代码:

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");


}

}

现在打印出来: 动物园现在有 6 种动物:猎豹美洲豹豹狮子豹虎

 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.

所以出于某种原因,Tiger 总是不断地被打印出来。即使我改变了很多不同的方法。我感觉这可能与 Object remove(int index) 方法有关。

此外,我明白在 "iterator without resetting" 部分之后应该没有任何内容,但我的代码不应该有一个异常说 "There is nothing in the next element"?

hasNext() 行为

您的 hasNext() 方法的行为与您编写的完全一样 - return 在您的 try 块中计算条件的结果,因此它只会 return false 因此永远不会进入您尝试在不重置的情况下通过迭代器的循环。不会抛出Exception

编辑:回应评论

让我们更详细地剖析一下 - 您当前的方法是:

@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;
}

try 块中,您有效地执行了两次比较,每次比较都会导致 boolean,然后 && 它们一起和 return 结果。第一个是

currentIndex <= currentSize

这大概是为了检查您的迭代器是否“超出了列表的末尾”。如果 currentIndex 不大于 currentSize,这将评估 false。事实上,我认为这是错误的,因为 currentSize 似乎是在构建时设置的并且从未更改过,但这不是重点。

第二个是

items[currentIndex] != null

如果 currentIndex 没有超出 items 的末尾,那么 items[currentIndex] 的值将简单地针对 null 进行测试。唯一会抛出 Exception 的情况是 currentIndex >= items.length。但是请注意,此处抛出的异常不会是 NoSuchElementException, but an ArrayIndexOutOfBoundsExceptionNoSuchElementExceptionEnumeration.

抛出(通常在标准语言库中)

最后,你们&&这些在一起了。现在,这是完整性的一个稍微棘手的部分。因为 the way that && is evaluated in Java - 如果第一个条件是 false 第二个永远不会被评估。所以,如果第一个条件是 false,你的函数 returns false 立即。如果第一个是 true,您的函数 return 就是第二个的值。

所以,实际上,您的 try...catch 构造在这里完全是多余的,因为 return 中的条件不会失败,即使失败了,它也不会抛出 Exception 无论如何你都在追赶。此外,该方法中的第二个 return 语句是多余的,并且正在评估与 try 中的完全相同的表达式,所以如果那个方法失败,第二个也会失败。

最后但同样重要的是,您应该意识到,在您的特定实现中,任何依赖于 items 的大小来抛出 Exception 的东西都可能是错误的 - 因为 items.length 不限于与 size 相同。当您 null items 中的值时,您不会从数组中“删除”它们 - 因此引用它们不会抛出 Exception,它只会引用一个值null

remove(int index) 行为

你的 remove(int index) 没有按照你喜欢的方式运行,因为你在递减 size 之前将 items[size] 处的元素清空,反转这两个语句,它应该按你想要的方式工作

最终评论

我已经回答了你的直接问题。但是 - 您的实现中还有其他错误,例如尝试在 hasNext()false 时调用 next()。你会得到一个 ArrayIndexOutOfBoundsException。我认为你打算满足 Iterator 接口规范并抛出一个 NoSuchElementException.

怀疑你从根本上误解了try...catch概念以及throw。您的代码应该 抛出 NoSuchElementException,而不是试图 catch 它 - 毕竟会生成什么?我认为值得阅读 Oracle tutorial on Exceptions,try...catch,throw etc.,可能会问另一个关于它的问题,或者问问你的导师。

简而言之 - 这里有两件事 - 你有底层代码可以检测正在发生的令人讨厌的事情并生成异常,例如

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
}

然后您有其他代码使用可能引发异常的功能/方法,并且

a) 允许继续抛出异常,或者

b)(你的情况)捕获异常并用它做其他事情 - 例如

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());
}