Java의 List.subList()는 fromIndex와 toIndex를 두어 sub list를 얻는다. 

주의할 점은 toIndex는 포함하지 않는 값이다. fromIndex 이상 toIndex 미만이다. (내가 자주 실수하는 내용이기도 하다..)


List<E>subList(int fromIndex, int toIndex)

간단하게 테스트하면 이렇다. 



    List<String> list = new ArrayList<String>();


    list.add("1");

    list.add("2");

    list.add("3");

    list.add("4");

    

    System.out.println("List : " + list);

    

    List<String> subList = list.subList(1,3);

    System.out.println("Sub List : " + subList);



결과는 다음과 같다.


List : [1, 2, 3, 4]

Sub List : [2, 3]



ArrayList의 subList는 SubList라는 내부 클래스를 생성한다. 


    public List<E> subList(int fromIndex, int toIndex) {

        subListRangeCheck(fromIndex, toIndex, size);

        return new SubList(this, 0, fromIndex, toIndex);

    }


private class SubList extends AbstractList<E> implements RandomAccess {

        private final AbstractList<E> parent;

        private final int parentOffset;

        private final int offset;

        int size;


        SubList(AbstractList<E> parent, int offset, int fromIndex, int toIndex) {

            this.parent = parent;

            this.parentOffset = fromIndex;

            this.offset = offset + fromIndex;

            this.size = toIndex - fromIndex;

            this.modCount = ArrayList.this.modCount;

        }


        메소드 안에..checkForComodification()를 호출하고 있다.

}


checkForComodification()으로 짐작하겠지만, 원래 List를 SubList가 reference(parent)하고 있다. 계속 관련되어 체크한다. 

따라서 아래 코드에서 원본 list의 요소를 삭제하면, java.util.ConcurrentModificationException이 발생한다. 

ArrayList<String> list = new ArrayList<String>();


    list.add("1");

    list.add("2");

    list.add("3");

    list.add("4");

    List<String> subList = list.subList(2,4);

    list.remove(1);



Exception in thread "main" java.util.ConcurrentModificationException

at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1169)



관련된 내용은 api에 설명되어 있다. 


http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#subList%28int,%20int%29


The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)




반면, Set.subSet()은 TreeSet에 정의되어 있다. 



NavigableSet<E>subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
Returns a view of the portion of this set whose elements range from fromElement to toElement.
SortedSet<E>subSet(E fromElement, E toElement)


예제는 다음고 ㅏ같다. 

TreeSet<String> set = new TreeSet<String>();

set.add("1");

set.add("2");

set.add("3");

    set.add("4");

    SortedSet<String> subset1 = set.subSet("1", "2");

    SortedSet<String> subset2 = set.subSet("1", true, "2", true);

    

    System.out.println("set : " + set);

    System.out.println("Sub set 1 : " + subset1);

    System.out.println("Sub set 2 : " + subset2);


결과는 다음과 같다. 


set : [1, 2, 3, 4]

Sub set 1 : [1]

Sub set 2 : [1, 2]



TreeSet은 ArrayList의 subList처럼 index(int)가 아닌 "값"으로 subset을 한다. 

Set을 Index(int)로 데이터를 얻어내려면, Set를 List로 바꿔야 한다. 


Tree.subSet은 새로운 NavigationMap.subMap()으로 만든 TreeSet을 생성하기 때문에 subSet() 이후에 데이터가 변경되어도 ConcurrentModificationException이 발생되지 않는다. 


    public SortedSet<E> subSet(E fromElement, E toElement) {

        return subSet(fromElement, true, toElement, false);

    }

   

 public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,

                                  E toElement,   boolean toInclusive) {

        return new TreeSet<>(m.subMap(fromElement, fromInclusive,

                                       toElement,   toInclusive));

    }



No problem!!

TreeSet<String> set = new TreeSet<String>();

set.add("1");

set.add("2");

set.add("3");

    set.add("4");

    SortedSet<String> subset1 = set.subSet("1", "2");

    SortedSet<String> subset2 = set.subSet("1", true, "2", true);

  

    set.remove("1");

    

    System.out.println("set : " + set);

    System.out.println("Sub set 1 : " + subset1);

    System.out.println("Sub set 2 : " + subset2);


Posted by '김용환'

댓글을 달아 주세요