如何使用 Iterator java

问题描述

我有以下问题。我一直在做一个任务,其中给出了迭代器,并且 Predicate 类必须检查迭代器中是否存在字符串。我覆盖了迭代器中的 hasNext()next() 方法。 Hier 是 PredicateIteratorTest。我收到消息 junit.framework.AssertionFailedError: expected:<Java [and UML]> but was:<Java [11]> at PredicateIteratorTest.providesValuesBeginningWithJava(PredicateIteratorTest.java:37)

它应该返回前一个元素。

public class PredicateIteratorTest {
    private final List<String> values = List.of(//
            "Java and UML","UML and Java","Java 11","UML 2.0","Effective Java");
    private Iterator<String> valuesEndingWithJava;
    private Iterator<String> valuesBeginningWithJava;
    private Iterator<String> novalues;

    @Before
    public void setUp() {
        valuesEndingWithJava = new PredicateIterator<>(values.iterator(),new EndsWith("Java"));
        valuesBeginningWithJava = new PredicateIterator<>(values.iterator(),new StartsWith("Java"));
        novalues = new PredicateIterator<>(values.iterator(),new StartsWith("Doesn't match"));
    }

    @Test
    public void providesValuesEndingWithJava() {
        assertTrue(valuesEndingWithJava.hasNext());
        assertEquals("UML and Java",valuesEndingWithJava.next());
        assertTrue(valuesEndingWithJava.hasNext());
        assertEquals("Effective Java",valuesEndingWithJava.next());
    }
}

这是 PredicateIterator 类。在 if(predicate.test(iterator.next())){ 之后,我想做一些类似于 ListIterator 中的 iterator.prevIoUs() 方法,但不使用 ListIterator,因为测试仅使用 Iterator。我怎样才能做到?

public class PredicateIterator<T> implements Iterator<T>{

    private  Iterator<T> iterator;
    private  Predicate<T> predicate;

    public PredicateIterator(Iterator<T> iter,Predicate<T> predicate){
        this.iterator = iter;
        this.predicate = predicate;
    }

    @Override
    public boolean hasNext(){
        while(iterator.hasNext()){
            if(predicate.test(iterator.next())){
                return true;
                }
        }
        return false;
    }


    @Override
    public T next(){
        T elem;
        while (iterator.hasNext()){
            elem = iterator.next();
            if(predicate.test(elem)){
                return elem;
            }
        }
        throw new NoSuchElementException();
    }

}

我通过添加 ListIterator 和 iterator.prevIoUs() 更改了 PredicateIterator。但现在我有测试错误 java.lang.UnsupportedOperationException at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:73) at java.base/java.util.ImmutableCollections$ListItr.prevIoUs(ImmutableCollections.java:260) at PredicateIterator.hasNext(PredicateIterator.java:20) at PredicateIteratorTest.providesValuesBeginningWithJava(PredicateIteratorTest.java:36)

private ListIterator<T> iterator;
    private  Predicate<T> predicate;

    public PredicateIterator(Iterator<T> iter,Predicate<T> predicate){
        this.iterator = (ListIterator<T>) iter;
        this.predicate = predicate;
    }

    @Override
    public boolean hasNext(){
        while(iterator.hasNext()){
            if(predicate.test(iterator.next())){
                iterator.prevIoUs();
                return true;
                }
        }
        return false;
    }

解决方法

创建一个布尔字段并将其分配给 false 但它在找到值后在 hasNext 方法中将其分配给 true 然后在 next 方法中检查此字段,如果它为 false 则意味着您在 hasNext 之前调用了 next 方法方法,那么你必须在next方法中调用hasNext方法。

public class PredicateIterator<T> implements Iterator<T> {

    private Predicate predicate;

    private Iterator<T> iter;
    private T type;
    private boolean test = false;

    public PredicateIterator(Iterator<T> iter,Predicate<T> predicate) {
        if (iter == null || predicate == null) throw new NoSuchElementException();
        this.predicate = predicate;
        this.iter =  iter;


    }


    @Override
    public boolean hasNext() {

        if (iter == null) throw new NoSuchElementException();

        while (iter.hasNext()) {

            type = iter.next();

            if (predicate.test(type)) {
                test = true;
                return true;
            }
        }
        return false;
    }

    @Override
    public T next() {

        if (!test) {

            if ( hasNext()) {
                T newTyp = type;
                type = null;
                test = false;
               return newTyp;
            }
        }

       else  if (type != null) {

            T newTyp = type;
            type = null;
            test = false;
            return newTyp;
        }
        throw new NoSuchElementException();

    }
}
,

好的,我发现问题了。在进行谓词测试之前,我修改了您的 PredicateIterator<T> 类以保存该值。它似乎适用于定义的测试。

class PredicateIterator<T> implements Iterator<T> {
    
    private Iterator<T> iterator;
    private Predicate<T> predicate;
    T value;
    public PredicateIterator(Iterator<T> iter,Predicate<T> predicate) {
        this.iterator = iter;
        this.predicate = predicate;
    }
    
    @Override
    public boolean hasNext() {
        
        while (iterator.hasNext()) {
            value = iterator.next();  //<-- save value before test
            if (predicate.test(value)) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public T next() {
        if (value != null) {
            T retValue = value;
            value = null;
            return retValue;   // <-- return saved value.
        } else {
        throw new NoSuchElementException();
        }
    }   
}

再观察一次。如果您需要更改任何测试列表,您将无法更改,因为 List.of() 返回一个不可变列表。但是您可以将其作为参数传递给可变实现。例如。 new ArrayList<>(List.of(...));

,

非常感谢,我复制了您的 hasNext() 方法并更改了 next(),所以它看起来像这样:

@Override
    public T next() {
        if(value!= null){
           if(predicate.test(value)) {
               return value;
           }
       }
       throw new NoSuchElementException();
    }

第一个测试 providesValuesEndingWithJava() 现在可以正确编译,但现在出现了另一个问题。它抛出一个 NoSuchElementException。这是测试和我收到的消息。我尝试使用 while(value!=null)while(iterator.hasNext()) 进行编译,但编译时间过长导致崩溃。

 @Test
    public void hasNextReturnsFalseAfterLastElement1() {
        valuesEndingWithJava.next();
        valuesEndingWithJava.next();
        assertFalse(valuesEndingWithJava.hasNext());
    }
java.util.NoSuchElementException
    at PredicateIterator.next(PredicateIterator.java:34)
    at PredicateIteratorTest.hasNextReturnsFalseAfterLastElement1(PredicateIteratorTest.java:44)