【问题标题】:Why am I getting a null pointer exception in my iterator? [duplicate]为什么我的迭代器中出现空指针异常? [复制]
【发布时间】:2016-01-30 23:24:20
【问题描述】:

在双向链表上调用我的迭代器时,我得到一个空指针异常。空指针异常发生在 main 行 assertEquals(i, (int) it.next());

     /***************************
      * nested class DequeIterator
      ***************************/
     private class DequeIterator implements Iterator<E>
      {
        // instance data member of ListIterator
        private Node current;

        // constructors for ListIterator
        public DequeIterator()
        {
          current = first; // head in the enclosing list
        }

        public boolean hasNext()
        {
          return current != null;
        }

        public E next()
        {
          if (hasNext() == false){ throw new NoSuchElementException();}
          else {
          E ret = current.item;
          current = current.next;
          return ret;
          }
        }

public void addLast(E item) {

        if (item.equals(null)) { throw new NullPointerException(); }

        else {

        Node node = new Node(item, null);
        Node ptr = last;

        ptr.prev.next = node;
        node.next = ptr;
        node.prev = ptr.prev;
        ptr.prev = node;    
        N++;

        }
    }

public static void main(String[] args) {

        Deque<Integer> lst = new Deque<Integer>(); // empty list


        for(int i = 1; i <= 5; i++) {
              lst.addLast(i);
            }
        assertEquals(5, lst.size());
        Iterator<Integer> it = lst.iterator();
        int i = 1;
        while(it.hasNext()) {
          assertEquals(i, (int) it.next());
          i++;
        }
        assertEquals(6, i);
        assertEquals(5, lst.size());
}

谁能告诉我为什么此时我得到一个空指针异常?

【问题讨论】:

  • 您将空值转换为int

标签: java iterator deque


【解决方案1】:

因为 Integer 包装器类型是可空的,并且在您的队列中有一个空 Integer,然后您尝试将其转换为 int primitive type ...

尝试像这样进行条件检查以验证元素不为空:

while(it.hasNext()) {
          Integer e = it.next();
          if(e != null)
            assertEquals(i, (int)e );
          i++;
        }

【讨论】:

  • 我明白了。这是因为在双端队列的两端有两个空的“虚拟”节点,对吧?
  • 是的,但是您应该在迭代器中检查它们,而不是在您的测试代码中。如果一开始就无法将 null 项目添加到集合中,则您的迭代器不应返回此类项目。
【解决方案2】:

首先查看循环的终止条件:

public boolean hasNext(){
    return current != null;
}

这意味着它最后一次运行时将返回null,因为它只检查当前元素而不是下一个元素是否为非空。

所以你的代码变成了这样:

Integer it_next = null;
assertEquals(i, (int)it_next);

而转换为int 是引发异常的原因。如果您查看the rules for how unboxing works,您可以找出原因:

如果 r 是 Integer 类型的引用,则拆箱转换会将 r 转换为 r.intValue()

所以你的代码变得类似于

((Integer)null).intValue();

这是对空值的方法调用,导致异常。

据推测,如果next 的值为null,则您想要的解决方法是在hasNext 中不返回true。像这样的:

public boolean hasNext(){
    return current != null && current.next != null;
}

【讨论】:

    【解决方案3】:

    鉴于您发布的代码不完整,看来双端队列末尾有一个标记为last,它的item 很可能是null

    更正您的迭代器以检查 hasNext() 中的 last

    public boolean hasNext()
    {
        return current != last && current != null;
    }
    

    为安全起见,已保留对 null 的检查。可能没有必要。

    【讨论】:

    • 嗯,双端队列的两端有两个虚拟节点,都是空的。它们被称为firstlast。由于last = null,在hasNext() 中检查current != null 是否就足够了?
    • 从您发布的代码来看,last 绝不是null(例如,ptr.prev.next = node; 行,在设置 ptr = last; 之后)。 last.next 可能是 nulllast.item 也是。
    猜你喜欢
    • 2022-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-21
    • 2018-01-20
    • 2023-01-09
    • 2020-03-13
    相关资源
    最近更新 更多