본문 바로가기
테크스토리

*LinkedList* 어디까지 알고있니? (feat. Iterator & ConcurrentModificationException)

by 쏘세지입술 2022. 10. 8.
반응형

오늘은 드디어! 내가 학교 다닐때 가장 좋아했던 자료구죠 LinkedList 이다. 아 참고로 나는 컴퓨터 공학을 전공하다가 지금은 중퇴한 상황이다 (자세한 설명은 생략...). LinkedList는 전에 공부했던 ArrayList와 같이 Collection중에서도 List에 해당하는 자료구죠 들인데 두개의 장단점이 확실하다. https://www.nextree.co.kr/p6506/

 

자료구조: Linked List 대 ArrayList

2014년 모두들 어떤 목적과 계획을 갖고 살고 계신지요? 저는 올 한해 “Go to the Base”를 목표로 여러 계획을 세웠는데요. 그 중 하나가 과거 5년 동안 저를 되 돌아 보고 부족했던 기본 지식을 탄

www.nextree.co.kr

자세한건 이 링크를 참조하기 바란다. 누군지 모르겠지만 아주 이해하기 쉽게 설명을 잘 한거 같다. (나도 나중에는 꼭 이런 블로거가 되야지 열정열정열정!!!!)


LinkedList를 공부하다 보면 자연스럽게 공부해야하고 익숙해져야 하는것들이 몇가지 있는데 그게 Iterator interface이다. 지금까지 데이터를 iterate하기 위해서 for-loop 과같은 loop을 썼다면 이제는 iterator에 익숙해 져야한다. Iterator interface 안에서도 ListIterator라는것이 있는데 이것에 대해 조금 알아보면 좋을거 같다!

https://docs.oracle.com/javase/7/docs/api/java/util/ListIterator.html

 

ListIterator (Java Platform SE 7 )

An iterator for lists that allows the programmer to traverse the list in either direction, modify the list during iteration, and obtain the iterator's current position in the list. A ListIterator has no current element; its cursor position always lies betw

docs.oracle.com

보통 iterator와는 다르게 listIterator는 양방향으로 이동할수 있다는 특징이있고 또한 현재위치(current element)라는 개념이 없다. ListIterator의 커서는 각 요소 중간에 위치하고 있으며 previous() & next() 와 같은 메소드로 이동한다. 커서가 중간에 위치하고 있는 이유는 무한반복 loop을 방지하기 위함이라고 한다. 

이러한 이유때문에 주의야할 점 2가지를 오늘 배웠다. 

 

1. Iterator를 declare 하고 initilize한후 next() 메소드를 불러야 한다. 그 이유는 위에 얘기한것처럼 커서는 중간에 위치하고 있기때문에 처음 생성된면 아무것도 없는 허공에 떠있는것과 유사하다. 그렇기에 커서를 옮겨서 list안에 요소들 중간으로 옮겨놔야한다.

2. ListIterator는 양방향으로 이동할수 있기 때문에 boolean 변수를 하나만들어서 어떤 액션을 취하기 전에 확인하는 단계를 거치는 것이 좋다. 예를 들어

private static void visit(LinkedList cities) {
        Scanner scanner = new Scanner(System.in);
        boolean quit = false;
        boolean goingForward = true;
        ListIterator<String> listIterator = cities.listIterator();

        if(cities.isEmpty()) {
            System.out.println("No cities in the itenerary");
            return;
        } else {
            System.out.println("Now visiting " + listIterator.next());
            printMenu();
        }

        while (!quit) {
            int action = scanner.nextInt();
            scanner.nextLine();
            switch(action) {
                case 0:
                    System.out.println("Holiday (Vacation) over");
                    quit = true;
                    break;

                case 1:
                    if(!goingForward) {
                        if(listIterator.hasNext()) {
                            listIterator.next();
                        }
                        goingForward = true;
                    }
                    if(listIterator.hasNext()) {
                        System.out.println("Now visiting " + listIterator.next());
                    } else {
                        System.out.println("Reached the end of the list");
                        goingForward = false;
                    }
                    break;

                case 2:
                    if(goingForward) {
                        if(listIterator.hasPrevious()) {
                            listIterator.previous();
                        }
                        goingForward = false;
                    }
                    if(listIterator.hasPrevious()) {
                        System.out.println("Now visiting " + listIterator.previous());
                    } else {
                        System.out.println("We are at the start of the list");
                        goingForward = true;
                    }
                    break;

                case 3:
                    printMenu();
                    break;

            }

        }
    }

Scanner를 써서 유저로 하여금 숫자를 입력하게 한다. 1 -> 앞으로 이동해라 2 -> 뒤로 이동해라. 

그 후에 goingForward 라는 boolean 변수를 만들어 앞으로 가는게 맞는지 뒤로가는게 맞는지 확인하는 절차를 거친다. 

만약 앞으로 이동하라는 1을 입력했을 경우 goingForward가 true인지 확인하고 만약 false라면 iterator 커서를 next() 메소드를 이용해서 다음 위치로 옮긴후 goingforward의 값을 true로 변환한다. 반대로 유저가 2를 입력하고 뒤로 이동해야하는데 goingForward가 true라면 previous() 이용해서 커서를 뒤로 한칸 옮긴후 goingforward를 false로 변환한다. 


ConcurrentmodificationException

Collection interface 에 속하는 클래스를 순회중에 일부 요소가 변경될때 일어날수 있는 문제를 감지하여 throw 하는 exception이다. 밑에 링크 블로거님이 아주 친절하게 자세하게 설명해주셨으니 참조해야겠다. 

https://codechacha.com/ko/java-concurrentmodificationexception/

 

Java - ConcurrentModificationException 원인 및 해결 방법

ConcurrentModificationException는 보통 리스트나 Map 등, Iterable 객체를 순회하면서 요소를 삭제하거나 변경을 할 때 발생합니다. removeIf, removeAll, Iterable 등의 메소드를 이용하여 리스트 순회 중 요소를

codechacha.com

개인적으로는 Iterator을 사용하는 방법과 removeIf()를 사용하여 제거하는 방법이 가장 베스트인거 같다. 

 

반응형

댓글