티스토리 뷰

왜?

 자바를 공부하면 For문을 먼저 배우게되고 For문을 배우면 따라나오는 것이 For Each문이다. 한국어로 이를 표현했을 때 "향상된 For문"이라는 말이 많이 나오는데 정말 향상되었는가에 대한 궁금증으로 인해 확인해보기로 했다.

 

 테스트는 List안에 10000건의 값을 넣고 1로 초기화하는 것으로 진행하였다.

public static long testFor(List<Integer> list, long runTime){
    int size = list.size();
    long result = 0;
    long runTimeTmp = runTime;

    while(0 < runTimeTmp--){
        long start = System.nanoTime();
        for(int i=0; i<size; i++){
            Integer integer = list.get(i);
            integer = 1;
        }
        long end = System.nanoTime();
        result += (end-start);
    }
    return result / runTime;
}
public static long testForEach(List<Integer> list, long runTime){
    int size = list.size();
    long result = 0;
    long runTimeTmp = runTime;
    while(0 < runTimeTmp--){
        long start = System.nanoTime();
        for(Integer integer : list){
            integer = 1;
        }
        long end = System.nanoTime();
        result += (end-start);
    }
    return result / runTime;
}

 

ArrayList

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    for(int i=1; i<=100000; i++){
        list.add(i);
    }
    long testCaseCount = 10L;
    System.out.println("ArrayList");
    System.out.println("For문 속도 : " + testFor(list, testCaseCount));
    System.out.println("ForEach문 속도 : " + testForEach(list, testCaseCount));
}
// ArrayList
// For문 속도 : 2913625
// ForEach문 속도 : 3020366

 근소한 차이로 계속 For문이 더 빨랐다.

 

LinkedList

public static void main(String[] args) {
    List<Integer> list = new LinkedList<>();
    for(int i=1; i<=100000; i++){
        list.add(i);
    }
    long testCaseCount = 10L;
    System.out.println("LinkedList");
    System.out.println("For문 속도 : " + testFor(list, testCaseCount));
    System.out.println("ForEach문 속도 : " + testForEach(list, testCaseCount));
}
// LinkedList
// For문 속도 : 5556549624
// ForEach문 속도 : 2700891

 압도적으로 For문보다 ForEach문이 빨랐다.

 

 

토의

 뭔가 이상하다는 걸 알았다. 분명 ForEach문은 향상된 For문이라 했는데 ArrayList와 LinkedList에서 테스트했을 때 각각 다른 결과물을 보여줬다.

 이때 생각해야하는 것이 ArrayList와 LinkedList의 자료구조적 차이이다. ArrayList에서 get()메소드와 LinkedList에서의 get()메소드는 값을 가지고오는 그 구조자체가 다르다.

 

 ArrayList는 배열을 이어놓은 Collection으로 get()메소드를 사용할 때 ArrayList의 배열에 index값을 그냥 return하기만하면 된다. 아래와 같이 메소드에 index값이 들어오면 배열값만 return해주는 역할만 하며 따라서 get()메소드 사용시 복잡한 찾기과정이 없는 것이다.

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}
E elementData(int index) {
    return (E) elementData[index];
}

 

 단, LinkedList는 배열을 이어놓은 것이 아닌 Node에 이전 Node와 다음 Node의 주소를 담아두어 연결한 Collection이다. 따라서 get()메소드에서 특정 index를 받더라도 바로 툭하고 값이 튀어나오는 것이 아닌 Node를 처음부터 원하는 index위치까지 돌려서 값을 찾아야하는 복잡한 찾기과정이 발생하게 된다. 따라서 List에서 특정 값만 바로 뽑아내는 ForEach문에 비해 For문으로 get()메소드를 사용하여 하나하나 찾게될 경우 상당히 오랜시간이 걸리게 된 것이다.

public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}
Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

 

결론

 결국 For문과 ForEach문의 속도는 어디가 더 빠른가?는 ArrayList와 LinkedList의 구조적 차이 때문에 어떤 것을 사용하느냐에 따라 다르다는 것이다.

 성능적 이슈때문에 For문과 ForEach문을 고려해야할 때는 ArrayList == For, LinkedList == ForEach가 된다고 볼 수 있다.

'JAVA > JAVA' 카테고리의 다른 글

static은 상속이 될까?  (1) 2021.03.29
댓글
최근에 올라온 글
Total
Today
Yesterday