You are a developer, not a coder.

subList 알맞게 사용하는 방법 본문

Backend-Languages/Java

subList 알맞게 사용하는 방법

Mattmk 2021. 2. 24. 15:10
SMALL

대규모프로세스 개발시, 서버개발자들이 아마 많이 만지는 코드중에 한개는 리스트형식을 크기대로 자르기위해

subList를 사용할 것이다.

 

이번 포스팅은 subList를 잘 사용하기 위해서

또한, 스택오버플로우를 방지하기 위한 내용을 담고 싶어서 작성하게 되었다.

 

// 0~2까지의 인덱스만 뽑아오기위해 다음과 같은 코드를 쓸것이다.
cateContTuple.setCateContBbsTupleList(items.subList(0, 3));

많은 개발자들은 위와같이 subList를 사용할 것이다.

 

이는 스택오버플로우 및 부모리스트인 items에 데이터 변경이 있을때 익셉션이 일어날 수있는 위험한 코드이다.

 

왜 스택오버플로우가 나는지, 어떠한 익셉션이 일어나는지 다음과 같은 예시를 보면 이해할 수 있다.

 

/*
 * Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.)
 * The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
 * The returned list supports all of the optional list operations.
 */

다음은 JAVA 공식 API에 있는 내용이다.

영어를 보면 view라는 단어가 보일것이다.

 

그렇다, subList는 view를 반환하기 때문에 불필요한 메모리를 점유 할수 있다는 것이다.

예를 들어 1만개의 리스트에서 단순 10 개만 subList 만들고 이를 캐시에 저장하는 경우, 10 개의 데이터만 캐시되는 아닌, 1만개의 리스트 값들이 모두 캐시 된다. 이를 통해 불필요한 메모리를 점유할 있다.

이럴 경우, 데이터양이 많아 지게 되면 스택오버플로우의 원인이 된다.

 

또한, parent의 값이 변경이 되면 익셉션을 일으키는 예시이다.

 

List<Integer> list = Lists.newArrayList(1, 2, 3, 4);
List<Integer> subList = list.subList(0, 2);
System.out.println('Before ---> ' + subList);
list.remove(0);
System.out.println('After ---> 'subList);

다음을 실행하면

Before ---> 1,2

After 출력전, java.util.ConcurrentModificationException 떨어진다.

 

결론적으로 subList를 가장 안전적이고, 잘 사용하기 위해서는 다음과 같이 새로운 리스트를 선언해 주입해 주는 방식이 최선의 방식이라고 한다.

cateContTuple.setCateContBbsTupleList(new ArrayList<CateContBbsTuple>(items.subList(0, 3)));

이렇게, 코드를 구현하면 추출하려는 리스트의 값만 메모리에 할당됨으로써 불필요한 메모리 점유를 방지 할 수 있다.

LIST
Comments