【问题标题】:Own Iterator for generic Pair class通用 Pair 类的自己的迭代器
【发布时间】:2018-12-13 18:48:00
【问题描述】:

我正在尝试为我自己的泛型类编写我的自己的迭代器。我一直在观看一些 YouTube 教程并在网上搜索。

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Pair<T> implements Iterable<T> {

    private T left;
    private T right;

    public Pair(T left, T right){
        this.left = left;
        this.right = right;
    }

    public  T getRight(){return this.right;}
    public  T getLeft(){return this.left;}

    // own Iterator
    @Override
    public Iterator<T> iterator() {
        return new myIterator;
    }


    class myIterator implements Iterator<T>{
        T newLeft = null;

        @Override
        public boolean hasNext() {
            if(newLeft == null && Pair.getLeft() != null){
                return true;
            }
            else if(newLeft !=null){
                return Pair.getRight() !=null;
            }
            else {
                return false;
            }
        }
        @Override
        public T next() {
            if(newLeft == null && Pair.getLeft() != null){
                newLeft = Pair.getLeft();
                return newLeft;
            }
            else if(newLeft != null){
                T newRight = Pair.getLeft();
                newLeft = Pair.getRight();
                return newRight;
            }
            throw new NoSuchElementException();
        }
    }
}

IntelliJ 指出的问题是,我不能按照我尝试的方式在 Iterator-Class 中使用 getLeft 和 getRight,因为 无法从静态上下文中引用非静态方法 .我一直在研究静态等等,但无法解决这个问题。我是完全走错了路,还是我的方法至少有点接近?

更新

运行时:

public static void main(String[] args) {
        Pair<Integer> intPair= new Pair(5,1);
        Pair<String> stringPair=new Pair("foo", "bar");

        Iterator<Integer> itr= intPair.iterator();
        while(itr.hasNext()){
            System.out.println(itr.next());
        }
    }

我遇到一个无限循环,打印 5。所以,Iterator 本身可以工作,但我的方法有一个逻辑错误。正在努力,但我感谢任何输入。 :)

更新 2

发现逻辑错误:NewLeft 从未更改为 null。正在努力解决它。

UPDATE3

:已解决! 具有嵌入式迭代器类和主类的完整对类,调用如下:
import java.util.Iterator;
import java.util.NoSuchElementException;

public class Pair<T> implements Iterable<T> {

    private T left;
    private T right;

    public Pair(T left, T right){
        this.left = left;
        this.right = right;
    }

    public  T getRight(){return this.right;}
    public  T getLeft(){return this.left;}

    // size of a pair is always 2
    public int size =2;

    // own Iterator
    @Override
    public Iterator<T> iterator() {
        return new myIterator();
    }

    // embedded iterator class
    public class myIterator implements Iterator<T>{
        T newLeft = null;
        T newRight = null;

        @Override
        public boolean hasNext() {
            if(newLeft == null && getLeft() != null){
                return true;
            }
            else if(newLeft !=null && newRight == null){
                newRight=getRight();
                return getRight() !=null;
            }
            else {
                return false;
            }
        }
        @Override
        public T next() {
            if(newLeft == null && getLeft() != null){
                newLeft = getLeft();
                return newLeft;
            }
            else if(newLeft != null && getRight() != null){
                newRight = getRight();
                return newRight;
            }
            throw new NoSuchElementException();
        }
    }
}

主要:

import java.util.Iterator;

public class main {

    public static void main(String[] args) {
        Pair<Integer> intPair= new Pair(5,1);
        Pair<String> stringPair=new Pair("foo", "bar");

        Iterator<Integer> itr= intPair.iterator();
        while(itr.hasNext()){
            System.out.println(itr.next());
        }

        Iterator<String> itrS= stringPair.iterator();
        while(itrS.hasNext()){
            System.out.println(itrS.next());
        }
    }
}

感谢所有提供帮助的人,是您让我找到了这个解决方案:)

【问题讨论】:

  • 看来您需要将Pair.getLeft() 更改为getLeft()Pair.getRight() 更改为getRight()
  • 容易多了:return Arrays.asList(left, right).iterator();.
  • @AndyTurner 不完全正确,因为它不能处理 getRight() 或 getLeft() 返回 null 的情况。
  • @Eran 好的,所以创建一个没有空值的列表,并返回它的迭代器。 Stream.of(left, right).filter(Objects::nonNull).collect(toList()).iterator().
  • @Eran,谢谢,它成功了,错误消失了。目前正在测试

标签: java generics iterator


【解决方案1】:

您的初始代码定义了一个变量T newLeft,其唯一目的是跟踪左侧值是否已被消耗,由非null 值指示。使用boolean 变量会更清楚,即这里的boolean hasSeenLeft;。然后,很明显这个类是不完整的,因为它没有跟踪是否已经消费了正确的值。

在您的固定代码中,您有 newLeftnewRight,它们解决了问题,但仍然具有误导性,因为它们的名称和类型都没有表明实际目的。如果将它们更改为boolean 变量,则可以设计它们以指示是否存在待处理的值,例如

final class myIterator implements Iterator<T> { // no need to make this public
    boolean hasPendingLeft = getLeft() != null, hasPendingRight = getRight() != null;

    @Override
    public boolean hasNext() {
        return hasPendingLeft || hasPendingRight;
    }

    @Override
    public T next() {
        if(hasPendingLeft) {
            hasPendingLeft = false;
            return getLeft();
        }
        else if(hasPendingRight) {
            hasPendingRight = false;
            return getRight();
        }
        throw new NoSuchElementException();
    }
}

更简单,更易读。

请注意,这两种解决方案都不能处理中间更改,但是这个Pair 类看起来无论如何在最好的情况下应该是不可变的。在这种情况下,值得将 leftright 声明为 final

对于可变类,值得为中间修改添加快速失败行为,类似于 Collection API:

final class myIterator implements Iterator<T> { // no need to make this public
    boolean hasPendingLeft = getLeft() != null, hasPendingRight = getRight() != null;

    @Override
    public boolean hasNext() {
        return hasPendingLeft || hasPendingRight;
    }

    @Override
    public T next() {
        if(hasPendingLeft) {
            hasPendingLeft = false;
            T left = getLeft();
            if(left == null) throw new ConcurrentModificationException();
            return left;
        }
        else if(hasPendingRight) {
            hasPendingRight = false;
            T right = getRight();
            if(right == null) throw new ConcurrentModificationException();
            return right;
        }
        throw new NoSuchElementException();
    }
}

所以即使在错误的情况下,这仍然可以保证非null 值,然后会抛出更有意义的异常。

【讨论】:

    【解决方案2】:

    我猜你想迭代这对中的 0 到 2 个可能的值?在您的迭代器中,您应该引用 T 的实例。您收到的消息是因为您试图以静态方式调用 Pair 中的方法(即,当 Pair 是类)

    【讨论】:

    • 所以,我理解我的“静态/非静态错误”,谢谢 :) 按照@Eran 的建议,我将 Pair.getLeft() 等更改为仅 getLeft()。我说得对吗,这是指实例吗?
    • @Shushiro 我没有任何实现迭代器的经验以及它如何获取您的 Pair 类的实例,但我认为这应该可以解决问题。也许只是看看它是否有效?
    • 冯登布鲁克。目前正在这样做:) 至少这有点合乎逻辑。静态/非静态问题 (Pair) 的原因已经消失,getLeft() 和 getRight() 返回 this.left/this.right,它来自我的 Pair,然后应该是我想要的?我希望如此,目前正在测试:)
    • 迭代器正在工作,但我的迭代器方法中至少有一个逻辑错误
    猜你喜欢
    • 2014-08-08
    • 2015-05-26
    • 2011-02-20
    • 2015-02-12
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多