如何使用 Iterator java 获取前一个元素

How to get previous element with Iterator java

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

它应该 return 前一个元素。

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 class。在 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;
    }

好的,我找到问题了。我修改了你的 PredicateIterator<T> class 以在进行谓词测试之前保存值。它似乎适用于定义的测试。

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() returns 是一个不可变的列表。但是您可以将其作为参数传递给可变实现。例如。 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)

创建一个布尔字段并将其分配给 false 但是它在 hasNext 方法中找到一个值后将其分配给 true 然后在 next 方法中检查此字段,如果它为 false 则意味着您之前调用了 next 方法hasNext方法,那么你必须在下一个方法中调用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();

    }
}