티스토리 뷰

어떤 프로그래밍을 하든 반복 구분 사용은 기본 중의 기본이다. 이 반복 구문도 잘만 사용하면 성능 향상을 가져올 수 있다.

 

반복 구문에서의 속도는?


자바에서 사용하는 반복 구문은 세 가지이다.

  • for
  • do-while
  • while

 

일반적으로 for문을 많이 사용한다. while문은 잘못하면 무한 루프에 빠질 수 있으므로 되도록이면 for문을 사용하기를 권장한다.

JDK 5.0 이전에는 for 구문을 다음과 같이 사용하였다. 여기서 list는 값이 들어있는 ArrayList이다.


for(int loop=0; loop<list.size(); loop++)

이렇게 코딩을 하는 습관은 좋지 않다. 매번 반복하면서 list.size() 메서드를 호출하기 때문이다. 이럴 때는 다음과 같이 수정해야 한다.


int listSize = list.size();
for(int loop=0; loop<listSize; loop++)

이렇게 하면 필요 없는 size() 메서드를 반복 호출이 없어지므로 더 빠르게 처리된다.

JDK 5.0부터는 다음과 같이 for-each를 사용할 수 있다.


ArrayList<String> list = new ArrayList<String>();
...
for (String str : list)

단, 이 방식은 데이터의 첫 번째 값부터 마지막까지 처리해야 할 경우에만 유용하다. 만약 순서를 거꾸로 돌리거나 특정 값부터 데이터를 탐색하는 경우에는 적절하지 않다.

 


@State(Scope.Thread)
@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class For {

    int LOOP_COUNT = 100000;

    List<Integer> list;

    @Setup
    public void setUp() {
        list = new ArrayList<>(LOOP_COUNT);
        for (int loop = 0; loop < LOOP_COUNT; loop++) {
            list.add(loop);
        }
    }

    @Benchmark
    public void traditionalForLoop() {
        int listSize = list.size();
        for (int loop = 0; loop < listSize; loop++) {
            resultProcess(list.get(loop));
        }
    }

    @Benchmark
    public void traditionalSizeForLoop() {
        for (int loop = 0; loop < list.size(); loop++) {
            resultProcess(list.get(loop));
        }
    }

    @Benchmark
    public void timeForEachLoop() {
        for (Integer loop : list) {
            resultProcess(loop);
        }
    }

    int current;
    public void resultProcess(int result) {
        current = result;
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(For.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

 

반복 구문에서의 필요 없는 반복


가장 많은 실수 중 하나는 반복 구문에서 계속 필요 없는 메서드 호출을 하는 것이다.


public void sample(DataVo data, String key) {
    TreeSet treeSet2 = null;
    treeSet2 = (TreeSet)data.get(key);
    if (treeSet2 != null) {
        for (int i=0; i< treeSet2.size(); i++) {
            DataVO2 data2 = (DataVO2)treeSet2.toArray()[i];
            ...
        }
    }
}

TreeSet 형태의 데이터를 갖고 있는 DataVO에서 TreeSet을 하나 추출하여 처리하는 부분이다. 이 소스의 문제는 toArray() 메서드를 반복해서 수행하는 것이다. 또한 treeSet2.Size() 메서드를 지속적으로 호출하도록 되어 있다.

수정한 결과는 다음과 같다.


public void sample(DataVo data, String key) {
    TreeSet treeSet2 = null;
    treeSet2 = (TreeSet)data.get(key);
    if (treeSet2 != null) {
        DataVO2[] dataVO2 = (DataVO2)treeSet2.toArray();
        int treeSetSize = treeSet2.size();
        for (int i=0; i< treeSetSize; i++) {
            DataVO2 data2 = dataVO2[i];
            ...
        }
    }
}

 

반복 구문은 어떤 애플리케이션을 개발하더라도 반드시 사용해야 하는 부분이다. 하지만 조금이라도 생각을 잘못하면 무한 루프를 수행하여 애플리케이션을 재시작하거나 스레드를 찾아서 중단시켜야 하는 경우가 발생하므로 성능상 문제가 되는 프로그램이 되기도 한다. 하지만 반대로 생각하면, 반복 구문의 문제점을 찾으면 성능상 문제가 되는 부분을 더 쉽게 해결할 수 있다는 말이 된다.

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함