오늘 우리는 Java에서 Iterator가 무엇이고 왜 필요한지 에 대해 이야기하겠습니다 .
이미 알고 있듯이 Java에는 Iterator 인터페이스를 구현하는 훌륭한 Collection 인터페이스가 있습니다. 바로 예약하겠습니다. 반복자 인터페이스를 Java의 반복자 패턴과 혼동해서는 안 됩니다! 명확히 하기 위해 먼저 인터페이스를 살펴보겠습니다.
Java에 반복자가 없다고 잠시 상상해 봅시다. 이 경우 , 각자는 컬렉션의 깊이까지 뛰어들어 와
문자 그대로 "반복자"는 "무차별 대입 " 으로 번역될 수 있습니다 . 즉, 컬렉션의 모든 요소를 반복할 수 있는 특정 엔터티입니다. 게다가 컬렉션의 내부 구조와 배열을 깊이 파고들지 않고도 이 작업을 수행할 수 있습니다. |
ArrayList
의 차이점을 진정으로 이해해야 합니다 . LinkedList
HashSet
TreeSet
Iterator가 구현해야 하는 메서드
boolean hasNext()
— 반복 가능한 객체(현재 컬렉션)에 여전히 값이 남아 있는 경우 true
더 이상 값이 없으면 메서드는 를 반환합니다 false
. E next()
— 컬렉션(객체)의 다음 요소를 반환합니다. 더 이상 요소가 없으면( check 가 없고 컬렉션 끝에 도달했을 때 hasNext()
호출한 경우) 메서드는 를 throw합니다 . - 에서 마지막으로 얻은 요소를 제거합니다 . 이 메소드는 다음을 발생시킬 수 있습니다: next()
NoSuchElementException
void remove()
next()
UnsupportedOperationException
, 이 반복자가 메서드를 지원하지 않는 경우remove()
(예를 들어 읽기 전용 컬렉션의 경우)IllegalStateException
, 메소드가next()
아직 호출되지 않았거나remove()
마지막 호출 이후 이미 호출된 경우next()
.
for-each
. 확장자는 ListIterator입니다. 추가 Java 목록 반복자 메서드를 살펴보겠습니다. 당신은 아마도 그들을 알고 있을 것입니다:
void add(E e)
— 요소를E
에 삽입합니다 .List
boolean hasPrevious()
— 역방향 검색 중에 요소가 있으면true
반환 됩니다 .List
int nextIndex()
— 다음 요소의 인덱스를 반환합니다.E previous()
— 이전 시트 요소를 반환합니다.int previousIndex()
— 이전 요소의 인덱스를 반환합니다.void set(E e)
- 마지막 호출에서 반환된 요소를next()
또는previous()
요소로 대체합니다e
.
List
학생들에게 보내는 인사말을 포함하는 텍스트 를 만들어 보겠습니다 .
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
이제 반복자를 가져와서 포함된 모든 줄을 콘솔에 인쇄하겠습니다.
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
이제 "병목 현상"이 발생합니다. Java 컬렉션은 아마도 알고 있듯이(모르는 경우 알아내십시오) 인터페이스를 확장 Iterable
하지만 이것이 단지 List
, Set
반복자 Queue
를 지원한다는 의미는 아닙니다. For java Map iterator
도 지원되지만 다음을 위해 호출되어야 합니다 Map.entrySet()
.
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
그런 다음 메서드는 "키"-"값" 쌍을 포함하는 next()
개체를 반환합니다 . Entry
그러면 모든 것이 동일합니다 List
.
while (mapIterator.hasNext()) {
Map.Entry<String, Integer> entry = mapIterator.next();
System.out.println("Key: " + entry.getKey());
System.out.println("Value: " + entry.getValue());
}
당신은 이렇게 생각합니다. “그만해. 우리는 인터페이스에 대해 이야기하고 있으며 기사 제목은 "패턴"입니다. 즉, 반복자 패턴은 반복자 인터페이스입니까? 아니면 인터페이스가 패턴인가요? 이 단어가 처음 나타나면 참고 사항을 제시하겠습니다. 패턴은 디자인 패턴이며, 클래스 또는 상호 연결된 여러 클래스가 준수해야 하는 특정 동작입니다. Java의 반복자는 내부 구조에 반복이 포함된 모든 객체에 대해 구현될 수 있으며 논의 중인 메서드의 서명을 변경할 수 있습니다. 패턴을 구현할 때 가장 중요한 것은 클래스가 준수해야 하는 논리입니다. 반복자 인터페이스는List, Set, Queue, Map
프로그래머의 재량에 따라 이미 만들어진 구조( )와 다른 구조 모두에 적용되는 동일한 이름의 패턴을 비공개로 구현한 것입니다 . Iterator 인터페이스를 확장하여 패턴을 구현하지만 패턴을 구현하기 위해 인터페이스를 확장할 필요는 없습니다. 간단한 비유: 모든 물고기는 헤엄칩니다. 그러나 헤엄치는 모든 것이 물고기는 아닙니다. 예를 들어, 나는... 단어를 선택하기로 결정했습니다. 좀 더 구체적으로 말하면 명사입니다. 접두사, 루트, 접미사 및 끝 부분으로 구성됩니다. WordPart
단어의 일부에 대해 이를 확장하는 인터페이스와 클래스를 만듭니다 Prefix, Root, Suffix и Ending
.
interface WordPart {
String getWordPart();
}
static class Root implements WordPart {
private String part;
public Root(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Prefix implements WordPart {
private String part;
public Prefix(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Suffix implements WordPart {
private String part;
public Suffix(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Ending implements WordPart {
private String part;
public Ending(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
그런 다음 클래스 Word
(단어)에는 부분이 포함되며, 여기에 추가로 단어의 부분 수를 반영하는 정수를 추가합니다.
public class Word {
private Root root;
private Prefix prefix;
private Suffix suffix;
private Ending ending;
private int partCount;
public Word(Root root, Prefix prefix, Suffix suffix, Ending ending) {
this.root = root;
this.prefix = prefix;
this.suffix = suffix;
this.ending = ending;
this.partCount = 4;
}
public Word(Root root, Prefix prefix, Suffix suffix) {
this.root = root;
this.prefix = prefix;
this.suffix = suffix;
this.partCount = 3;
}
public Word(Root root, Prefix prefix) {
this.root = root;
this.prefix = prefix;
this.partCount = 2;
}
public Word(Root root) {
this.root = root;
this.partCount = 1;
}
public Root getRoot() {
return root;
}
public Prefix getPrefix() {
return prefix;
}
public Suffix getSuffix() {
return suffix;
}
public Ending getEnding() {
return ending;
}
public int getPartCount() {
return partCount;
}
public boolean hasRoot() {
return this.root != null;
}
public boolean hasPrefix() {
return this.prefix != null;
}
public boolean hasSuffix() {
return this.suffix != null;
}
public boolean hasEnding() {
return this.ending != null;
}
네, 오버로드된 생성자가 4개 있습니다(단순화를 위해 접미사가 하나만 있다고 가정하겠습니다). 명사는 하나의 접두사로 구성될 수 없으므로 매개변수가 하나인 생성자의 경우 루트를 설정합니다. 이제 반복자 패턴인 WordIterator의 구현을 작성해 보겠습니다. 두 가지 메서드를 재정의 hasNext()
합니다 next()
.
public class WordIterator implements Iterator<Word.WordPart> {
private Word word;
private int wordPartsCount;
public WordIterator(Word word) {
this.word = word;
this.wordPartsCount = word.getPartCount();
}
@Override
public boolean hasNext() {
if (wordPartsCount == 4) {
return word.hasPrefix() || word.hasRoot() || word.hasSuffix() || word.hasEnding();
} else if (wordPartsCount == 3) {
return word.hasPrefix() || word.hasRoot() || word.hasSuffix();
} else if (wordPartsCount == 2) {
return word.hasPrefix() || word.hasRoot();
} else if (wordPartsCount == 1) {
return word.hasRoot();
}
return false;
}
@Override
public Word.WordPart next() throws NoSuchElementException {
if (wordPartsCount <= 0) {
throw new NoSuchElementException("No more elements in this word!");
}
try {
if (wordPartsCount == 4) {
return word.getEnding();
}
if (wordPartsCount == 3) {
return word.getSuffix();
}
if (wordPartsCount == 2) {
return word.getPrefix();
}
return word.getRoot();
} finally {
wordPartsCount--;
}
}
}
남은 것은 클래스에 반복자를 할당하는 것입니다 Word
.
public class Word implements Iterable<Word.WordPart> {
…
@Override
public Iterator<WordPart>iterator() {
return new WordIterator(this);
}
…
}
이제 "rush"라는 단어의 형태소 분석을 수행해 보겠습니다.
public class Main {
public static void main(String[] args) {
Word.Root root = new Word.Root("беж");
Word.Prefix prefix = new Word.Prefix("пере");
Word.Suffix suffix = new Word.Suffix("к");
Word.Ending ending = new Word.Ending("a");
Word word = new Word(root, prefix, suffix, ending);
Iterator wordIterator = word.iterator();
while (wordIterator.hasNext()) {
Word.WordPart part = (Word.WordPart) wordIterator.next();
System.out.println(part.getClass() + ": " + part.getWordPart());
}
}
}
반복자 패턴 구현에서 다음 출력 순서를 선택했습니다.
- 종결
- 접미사
- 콘솔
- 뿌리
GO TO FULL VERSION