[java] Java로 자체 반복자를 작성할 수 있습니까?

포함 된 목록이 [alice, bob, abigail, charlie]있고 ‘a’로 시작하는 요소를 반복하는 반복자를 작성하려면 직접 작성할 수 있습니까? 어떻게 할 수 있습니까?



답변

확실한. 반복기는 java.util.Iterator인터페이스 의 구현 일뿐 입니다. 에서 기존의 반복 가능한 객체 (예 : a LinkedList)를 사용 java.util하는 경우 하위 클래스를 만들고 iterator함수를 재정 의하여 고유 한 값을 반환하거나 특수 Iterator인스턴스 에서 표준 반복기를 래핑하는 수단을 제공해야 합니다 ( 더 광범위하게 사용되는 이점이 있습니다) 등


답변

재사용 가능한 가장 좋은 옵션은 Iterable 인터페이스를 구현하고 iterator () 메서드를 재정의하는 것입니다.

다음은 Iterator () 메서드를 재정의하는 인터페이스를 구현하는 클래스와 같은 ArrayList의 예입니다.

import java.util.Iterator;

public class SOList<Type> implements Iterable<Type> {

    private Type[] arrayList;
    private int currentSize;

    public SOList(Type[] newArray) {
        this.arrayList = newArray;
        this.currentSize = arrayList.length;
    }

    @Override
    public Iterator<Type> iterator() {
        Iterator<Type> it = new Iterator<Type>() {

            private int currentIndex = 0;

            @Override
            public boolean hasNext() {
                return currentIndex < currentSize && arrayList[currentIndex] != null;
            }

            @Override
            public Type next() {
                return arrayList[currentIndex++];
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
        return it;
    }
}

이 클래스는 Generics를 사용하여 Iterable 인터페이스를 구현합니다. . 배열에 요소가 있다는 점을 고려하면 예를 들어 “foreach”루프에서 사용하는 필수 인스턴스 인 반복기의 인스턴스를 가져올 수 있습니다.

Iterator를 확장하지 않고 반복자의 익명 인스턴스를 생성하고 currentSize의 값을 활용하여 배열을 탐색 할 수있는 위치까지 확인할 수 있습니다 (용량이 10 인 배열을 생성했다고 가정 해 보겠습니다. 0과 1의 요소). 인스턴스는 현재 위치에 대한 소유자 카운터를 가지며 현재 값이 null이 아닌지 확인하는 hasNext ()와 currentIndex의 인스턴스를 반환하는 next ()를 사용하여 재생하기 만하면됩니다. 다음은이 API를 사용하는 예입니다.

public static void main(String[] args) {
    // create an array of type Integer
    Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};

    // create your list and hold the values.
    SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);

    // Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
    for(Integer num : stackOverflowList) {
        System.out.print(num);
    }

    // creating an array of Strings
    String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};

    // create your list and hold the values using the same list implementation.
    SOList<String> languagesList = new SOList<String>(languages);

    System.out.println("");
    // Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
    for(String lang : languagesList) {
        System.out.println(lang);
    }
}
// will print "12345
//C
//C++
//Java
//Python
//Scala

원하는 경우 Iterator 인스턴스를 사용하여 반복 할 수도 있습니다.

// navigating the iterator
while (allNumbers.hasNext()) {
    Integer value = allNumbers.next();
    if (allNumbers.hasNext()) {
        System.out.print(value + ", ");
    } else {
        System.out.print(value);
    }
}
// will print 1, 2, 3, 4, 5

foreach 설명서는 http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html에 있습니다. 내 개인 연습 Google 코드 에서보다 완전한 구현을 볼 수 있습니다 .

이제 필요한 효과를 얻으려면 Iterator에 필터 개념을 연결해야한다고 생각합니다. 예를 들어 char “a”로 시작하지 않는 값으로 next () 구현을 필터링합니다. 주어진 필터가있는 값으로 필터링 된 목록을 기반으로하는 보조 Interator로 놀아야한다고 생각합니다.


답변

Iterable이 계승을 계산하는 좋은 예

FactorialIterable fi = new FactorialIterable(10);
Iterator<Integer> iterator = fi.iterator();
while (iterator.hasNext()){
     System.out.println(iterator.next());
}

Java 1.8 용 단축 코드

new FactorialIterable(5).forEach(System.out::println);

맞춤 반복 가능한 클래스

public class FactorialIterable implements Iterable<Integer> {

    private final FactorialIterator factorialIterator;

    public FactorialIterable(Integer value) {
        factorialIterator = new FactorialIterator(value);
    }

    @Override
    public Iterator<Integer> iterator() {
        return factorialIterator;
    }

    @Override
    public void forEach(Consumer<? super Integer> action) {
        Objects.requireNonNull(action);
        Integer last = 0;
        for (Integer t : this) {
            last = t;
        }
        action.accept(last);
    }

}

사용자 정의 반복기 클래스

public class FactorialIterator implements Iterator<Integer> {

    private final Integer mNumber;
    private Integer mPosition;
    private Integer mFactorial;


    public FactorialIterator(Integer number) {
        this.mNumber = number;
        this.mPosition = 1;
        this.mFactorial = 1;
    }

    @Override
    public boolean hasNext() {
        return mPosition <= mNumber;
    }

    @Override
    public Integer next() {
        if (!hasNext())
            return 0;

        mFactorial = mFactorial * mPosition;

        mPosition++;

        return  mFactorial;
    }
}


답변

다음은 ‘a’로 시작하는 요소를 반복하는 반복자를 작성하는 완전한 코드입니다.

import java.util.Iterator;

public class AppDemo {

    public static void main(String args[]) {

        Bag<String> bag1 = new Bag<>();

        bag1.add("alice");
        bag1.add("bob");
        bag1.add("abigail");
        bag1.add("charlie");

        for (Iterator<String> it1 = bag1.iterator(); it1.hasNext();) {

            String s = it1.next();
            if (s != null)
                System.out.println(s);
        }
    }
}

사용자 정의 반복기 클래스

import java.util.ArrayList;
import java.util.Iterator;

public class Bag<T> {

    private ArrayList<T> data;

    public Bag() {

        data = new ArrayList<>();
    }

    public void add(T e) {

        data.add(e);
    }

    public Iterator<T> iterator() {

        return new BagIterator();
    }

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

        private int index;
        private String str;

        public BagIterator() {

            index = 0;
        }

        @Override
        public boolean hasNext() {

             return index < data.size();
        }

        @Override
        public T next() {

            str = (String) data.get(index);
            if (str.startsWith("a"))
                return (T) data.get(index++);
            index++;
            return null;
        }
    }
}


답변

고유 한 반복자를 구현할 수 있습니다. 이터레이터는 List에서 반환 한 이터레이터를 래핑하도록 구성되거나 커서를 유지하고 List의 get (int index) 메서드를 사용할 수 있습니다. Iterator의 next 메서드와 hasNext 메서드에 논리를 추가하여 필터링 기준을 고려하기 만하면됩니다. 또한 반복자가 제거 작업을 지원할지 여부도 결정해야합니다.


답변

다음은 질문에 대한 완전한 답변입니다.

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

class ListIterator implements Iterator<String>{
    List<String> list;
    int pos = 0;

    public ListIterator(List<String> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        while(pos < list.size()){
            if (list.get(pos).startsWith("a"))
                return true;
            pos++;
        }
        return false;

    }

    @Override
    public String next() {
        if (hasNext())
            return list.get(pos++);
        throw new NoSuchElementException();
    }
}

public class IteratorTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("alice", "bob", "abigail", "charlie");
        ListIterator itr = new ListIterator(list);

        while(itr.hasNext())
            System.out.println(itr.next()); // prints alice, abigail
    }
}
  • ListIterator ‘a’로 시작하는 요소를 반환하는 배열의 반복기입니다.
  • Iterable 인터페이스를 구현할 필요가 없습니다. 그러나 그것은 가능성입니다.
  • 이것을 일반적으로 구현할 필요가 없습니다.
  • hasNext () 및 next ()에 대한 계약을 완전히 충족합니다. 즉, hasNext ()가 여전히 요소가 있다고 말하면 next ()는 해당 요소를 반환합니다. 그리고 hasNext ()가 더 이상 요소를 말하지 않으면 유효한 NoSuchElementException예외를 반환합니다 .

답변