【问题标题】:Can't figure out how to fix my Iterator remove method无法弄清楚如何修复我的迭代器删除方法
【发布时间】:2015-06-22 01:26:15
【问题描述】:

所以这个程序所做的就是使用 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 种动物:猎豹 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.

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

此外,我明白在“不重置的迭代器”部分之后应该什么都没有,但我的代码不应该有一个异常说“下一个元素中没有任何东西”?

【问题讨论】:

  • 不太确定您的问题是什么。您不希望始终打印 Tiger 吗?如果是,那么您什么时候需要打印?
  • 你能解释一下你的代码应该做什么,而不是简单地把它扔在这里让我们费力地通过吗?
  • @Cristik 抱歉,我的描述不够清楚。所以删除迭代器方法应该删除数组中的所有元素。所以应该没有打印任何东西,但它会打印出“Tiger”。
  • @HovercraftFullOfEels 对不起,我现在说得更清楚了。
  • 为什么要创建自己的迭代器?为什么不使用集合自己的迭代器来删除项目?

标签: java iterator overriding iterable


【解决方案1】:

hasNext() 行为

您的 hasNext() 方法的行为与您编写的完全一样 - 在您的 try 块中返回条件的结果,因此它将简单地返回 false ,因此您尝试通过迭代器的循环没有永远不会进入重置。不会抛出Exception

编辑:响应 cmets

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

@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,然后&amp;&amp; 它们一起并返回结果。第一个是

currentIndex <= currentSize

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

第二个是

items[currentIndex] != null

如果currentIndex 没有超出items 的末尾,那么items[currentIndex] 的值将简单地针对null 进行测试。唯一会抛出Exception 的情况是currentIndex &gt;= items.length。但请注意,此处抛出的异常不是NoSuchElementException,而是ArrayIndexOutOfBoundsExceptionNoSuchElementException(通常在标准语言库中)由Enumeration 抛出。

最后,你们&amp;&amp; 这些在一起。现在,这对于完整性来说是一个有点棘手的部分。因为the way that &amp;&amp; is evaluated in Java - 如果第一个条件是false,则永远不会评估第二个条件。因此,如果第一个条件是 false,您的函数会立即返回 false。如果第一个是true,您的函数将返回第二个的值。

因此,实际上,您在此处的 try...catch 构造完全是多余的,因为返回的条件不会失败,即使失败了,它也不会抛出您正在捕获的 Exception 类型。此外,该方法中的第二个return 语句是多余的,并且无论如何评估与try 中的语句完全相同的表达式,因此如果该语句失败,那么第二个语句也会失败。

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

remove(int index) 行为

你的remove(int index) 的行为不像你喜欢的那样,因为你在减少items[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());
}

【讨论】:

  • 感谢删除解决方案。我终于做到了。现在,在查看 google/youtube 页面多年后,我仍然不完全理解 Exception 位。我已经为此更新了我的代码。我对此的逻辑是它将尝试查看下一部分是否有元素。如果没有,则会出现错误/错误,它将捕获并打印出消息。但是我的逻辑显然仍然是错误的,我不理解它,因为我的 try/catch 布局与我看到的页面相同。
  • 好的 - 我会更新以扩展它以希望涵盖所有基础并使答案可以接受。
  • 不客气 - 希望它有助于您的理解。感谢您的接受/投票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-07
  • 1970-01-01
  • 2018-08-11
  • 1970-01-01
  • 2016-03-18
  • 1970-01-01
相关资源
最近更新 更多