๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Java

์ž๋ฐ” ์ค‘๊ธ‰ 2ํŽธ - List(2)

by KongJiHoon 2025. 8. 10.

๐Ÿ“Œ ์ปดํŒŒ์ผ ํƒ€์ž„(Compile Time) vs ๋Ÿฐํƒ€์ž„(Runtime) ์˜์กด๊ด€๊ณ„

  • ์ปดํŒŒ์ผ ํƒ€์ž„(Compile Time)
    • ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•˜๋Š” ์‹œ์ 
    • ์ž๋ฐ” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ณด๋Š” ์˜์กด๊ด€๊ณ„
    • ํด๋ž˜์Šค ์†Œ์Šค ์ฝ”๋“œ ์ƒ์— ์ •์ ์œผ๋กœ ๋ณด์ด๋Š” ์˜์กด๊ด€๊ณ„
    • ์‹คํ–‰ํ•˜์ง€ ์•Š์•„๋„ ๋ณด์ด๋Š” ๊ด€๊ณ„
  • ๋Ÿฐํƒ€์ž„(Runtime)
    • ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ์ 
    • ์‹ค์ œ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค๋“ค์ด ์„œ๋กœ ์ฐธ์กฐํ•˜๋Š” ๋™์ ์ธ ์˜์กด๊ด€๊ณ„
    • ์‹คํ–‰ ์ค‘์— ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Œ

 

์ปดํŒŒ์ผ ํƒ€์ž„ ์˜์กด๊ด€๊ณ„

public class BatchProcessor {
    private final MyList<Integer> list; // ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์—๋งŒ ์˜์กด

    public BatchProcessor(MyList<Integer> list) {
        this.list = list;
    }

    public void logic(int size) {
        for (int i = 0; i < size; i++) {
            list.add(0, i);
        }
    }
}

 

  • BatchProcessor๋Š” ์ฝ”๋“œ์ƒ MyList ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กด
  • MyArrayList๋‚˜ MyLinkedList ๊ตฌ์ฒด ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •๋ณด๋Š” ์ฝ”๋“œ์— ์—†์Œ
  • ์ด ์ƒํƒœ๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„ ์˜์กด๊ด€๊ณ„๋ผ๊ณ  ํ•จ

 

๋Ÿฐํƒ€์ž„ ์˜์กด๊ด€๊ณ„

MyArrayList<Integer> list = new MyArrayList<>();
BatchProcessor processor = new BatchProcessor(list); // ์ฃผ์ž…
processor.logic(50_000);

 

 

  • ์‹คํ–‰ ์‹œ์ ์— MyList์˜ ๊ตฌํ˜„์ฒด๋กœ MyArrayList ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ฃผ์ž…
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ ์‹คํ–‰ ์ค‘์—๋Š” BatchProcessor๊ฐ€ MyArrayList ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉ
MyLinkedList<Integer> list = new MyLinkedList<>();
BatchProcessor processor = new BatchProcessor(list); // ์ฃผ์ž…
processor.logic(50_000);

 

 

  • ๋Ÿฐํƒ€์ž„์— MyLinkedList๋ฅผ ์ฃผ์ž…ํ•˜๋ฉด ์‹คํ–‰ ์‹œ์  ์˜์กด๊ด€๊ณ„๊ฐ€ ๋ณ€๊ฒฝ๋จ
  • ์ฝ”๋“œ๋Š” ์ˆ˜์ • ์—†์ด ๊ตฌํ˜„์ฒด๋ฅผ ๊ต์ฒด ๊ฐ€๋Šฅ

 

์ปดํŒŒ์ผ ํƒ€์ž„ ์˜์กด๊ด€๊ณ„

  • ํด๋ž˜์Šค ์ฝ”๋“œ์—์„œ ์–ด๋–ค ํƒ€์ž…(ํด๋ž˜์Šค, ์ธํ„ฐํŽ˜์ด์Šค)์— ์˜์กดํ•˜๋Š”์ง€ ๋‚˜ํƒ€๋ƒ„
  • BatchProcessor๋Š” MyList ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กด → ๊ตฌํ˜„ ๋ณ€๊ฒฝ์ด ์ž์œ ๋กœ์›€

 

๋Ÿฐํƒ€์ž„ ์˜์กด๊ด€๊ณ„

  • ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ์ ์— ์–ด๋–ค ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ์‹ค์ œ๋กœ ์ฃผ์ž…๋˜๊ณ  ์‚ฌ์šฉ๋˜๋Š”์ง€
  • DI(Dependency Injection)๋ฅผ ํ†ตํ•ด ์œ ์—ฐํ•˜๊ฒŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ

 

์žฅ์ 

  • OCP(๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™) ์ค€์ˆ˜ → ์ฝ”๋“œ ์ˆ˜์ • ์—†์ด ์ƒˆ๋กœ์šด ๊ตฌํ˜„์ฒด ํ™•์žฅ ๊ฐ€๋Šฅ
  • ๋Ÿฐํƒ€์ž„์— ์ „๋žต(์•Œ๊ณ ๋ฆฌ์ฆ˜)์„ ๊ต์ฒดํ•˜๋Š” ์ „๋žต ํŒจํ„ด ์ ์šฉ ๊ฐ€๋Šฅ

 

. ์ „๋žต ํŒจํ„ด(Strategy Pattern) 

  • ์ „๋žต(Strategy) = ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ธํ„ฐํŽ˜์ด์Šค (MyList)
  • ๊ตฌ์ฒด ์ „๋žต(Concrete Strategy) = ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„์ฒด (MyArrayList, MyLinkedList)
  • ์ปจํ…์ŠคํŠธ(Context) = ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค (BatchProcessor)
  • ์ „๋žต ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ต์ฒด ๊ฐ€๋Šฅ

 

MyArrayList vs MyLinkedList ์„ฑ๋Šฅ๋น„๊ต

 

package com.example.collection.list;

public class MyListPerformanceTest {


    public static void main(String[] args) {
        int size = 50_000;

        System.out.println("== MyArrayList ์ถ”๊ฐ€ ==");

        addFirst(new MyArrayList<>(), size);
        addMid(new MyArrayList<>(), size); // ๋ฐ์ดํ„ฐ ์ฐพ๋Š”๋ฐ O(1), ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€(๋ฐ€๊ธฐ) O(n)
        MyArrayList<Integer> list = new MyArrayList<>(size);


        addLast(list, size); // ์ฐพ๋Š”๋ฐ O(1), ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ O(1)


        int loop = 10000;

        System.out.println("== MyArrayList ์กฐํšŒ ==");

        getIndex(list, loop, 0); // ์•ž ์กฐํšŒ
        getIndex(list, loop, size / 2); //์ค‘๊ฐ„ ์กฐํšŒ
        getIndex(list, loop, size - 1); // ๋งˆ์ง€๋ง‰ ์กฐํšŒ

        System.out.println("== MyArrayList ๊ฒ€์ƒ‰ ==");

        search(list, loop, 0); // ์•ž ์กฐํšŒ
        search(list, loop, size / 2); //์ค‘๊ฐ„ ์กฐํšŒ
        search(list, loop, size - 1); // ๋งˆ์ง€๋ง‰ ์กฐํšŒ


        System.out.println("== MyLinkedList ์ถ”๊ฐ€ ==");

        addFirst(new MyLinkedList<>(), size);
        addMid(new MyLinkedList<>(), size); // ์ฐพ๋Š”๋ฐ O(n), ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ O(1)

        MyLinkedList<Integer> list1 = new MyLinkedList<>();
        addLast(list1, size); // ์ฐพ๋Š”๋ฐ O(n), ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ O(1)


        System.out.println("== MyLinkedList ์กฐํšŒ ==");

        getIndex(list1, loop, 0); // ์•ž ์กฐํšŒ
        getIndex(list1, loop, size / 2); //์ค‘๊ฐ„ ์กฐํšŒ
        getIndex(list1, loop, size - 1); // ๋งˆ์ง€๋ง‰ ์กฐํšŒ

        System.out.println("== MyLinkedList ๊ฒ€์ƒ‰ ==");

        search(list1, loop, 0); // ์•ž ์กฐํšŒ
        search(list1, loop, size / 2); //์ค‘๊ฐ„ ์กฐํšŒ
        search(list1, loop, size - 1); // ๋งˆ์ง€๋ง‰ ์กฐํšŒ

    }


    private static void addFirst(MyList<Integer> list, int size) {
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < size; i++) {

            list.add(0, i);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("์•ž์— ์ถ”๊ฐ€ - ํฌ๊ธฐ : " + size + ", ๊ณ„์‚ฐ ์‹œ๊ฐ„ : " + (endTime - startTime) + "ms");
    }

    private static void addMid(MyList<Integer> list, int size) {
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < size; i++) {

            list.add(i / 2, i);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("ํ‰๊ท  ์ถ”๊ฐ€ - ํฌ๊ธฐ : " + size + ", ๊ณ„์‚ฐ ์‹œ๊ฐ„ : " + (endTime - startTime) + "ms");
    }

    private static void addLast(MyList<Integer> list, int size) {
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < size; i++) {

            list.add(i);
        }

        long endTime = System.currentTimeMillis();
        System.out.println("๋’ค์— ์ถ”๊ฐ€ - ํฌ๊ธฐ : " + size + ", ๊ณ„์‚ฐ ์‹œ๊ฐ„ : " + (endTime - startTime) + "ms");
    }

    private static void getIndex(MyList<Integer> list, int loop, int index) {

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < loop; i++) {

            list.get(index);

        }

        long endTime = System.currentTimeMillis();

        System.out.println("index : " + index +", ๋ฐ˜๋ณต : " + loop + ", ๊ณ„์‚ฐ์‹œ๊ฐ„ : " + (endTime - startTime) + "ms");

    }


    private static void search(MyList<Integer> list, int loop, int findValue) {

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < loop; i++) {

            list.indexOf(findValue);

        }

        long endTime = System.currentTimeMillis();

        System.out.println("findValue : " + findValue +", ๋ฐ˜๋ณต : " + loop + ", ๊ณ„์‚ฐ์‹œ๊ฐ„ : " + (endTime - startTime) + "ms");

    }
}

 

โžค ์ถ”๊ฐ€(์‚ฝ์ž…) ์„ฑ๋Šฅ

  • ์•ž์— ์ถ”๊ฐ€
    • MyArrayList: O(n)1349ms
    • MyLinkedList: O(1)2ms
  • ํ‰๊ท (์ค‘๊ฐ„) ์ถ”๊ฐ€
    • MyArrayList: O(n)638ms
    • MyLinkedList: O(n)1066ms
  • ๋’ค์— ์ถ”๊ฐ€
    • MyArrayList: O(1)2ms
    • MyLinkedList: O(n)2169ms (๋‹จ์ผ ์—ฐ๊ฒฐ + ๊ผฌ๋ฆฌ ํฌ์ธํ„ฐ ์—†์Œ)

 

โžค ์กฐํšŒ(์ธ๋ฑ์Šค ์ ‘๊ทผ) ์„ฑ๋Šฅ

  • MyArrayList: index 0/์ค‘๊ฐ„/๋ ๋ชจ๋‘ ≈0ms (O(1))
  • MyLinkedList: index 0 1ms, ์ค‘๊ฐ„ 438ms, ๋ 873ms (O(n))

 

โžค ๊ฒ€์ƒ‰(๊ฐ’ ํƒ์ƒ‰) ์„ฑ๋Šฅ

  • MyArrayList: 0 0ms, ์ค‘๊ฐ„ 115ms, ๋ 222ms (O(n))
  • MyLinkedList: 0 0ms, ์ค‘๊ฐ„ 492ms, ๋ 983ms (O(n))

 

๊ธฐ๋Šฅ ๋ฐฐ์—ด ๋ฆฌ์ŠคํŠธ(MyArrayList) ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(MyLinkedList)
์•ž์— ์ถ”๊ฐ€/์‚ญ์ œ O(n) – 1369ms O(1) – 2ms
ํ‰๊ท (์ค‘๊ฐ„) ์ถ”๊ฐ€/์‚ญ์ œ O(n) – 651ms O(n) – 1112ms
๋’ค์— ์ถ”๊ฐ€/์‚ญ์ œ O(1) – 2ms O(n) – 2195ms
์ธ๋ฑ์Šค ์กฐํšŒ O(1) – 1ms O(n) – ํ‰๊ท  438ms
๊ฒ€์ƒ‰ O(n) – ํ‰๊ท  115ms O(n) – ํ‰๊ท  492ms

 

 

 

๐Ÿ“Œ์ •๋ฆฌ

  • ์ง์ ‘ ๊ตฌํ˜„ ๋ฒ„์ „ ๊ธฐ์ค€, ์•ž์‚ฝ์ž…์€ LinkedList๊ฐ€ ์••๋„์ , ๋’ค์‚ฝ์ž…์€ ArrayList๊ฐ€ ๋งค์šฐ ์œ ๋ฆฌ.
  • ์ค‘๊ฐ„ ์‚ฝ์ž…์€ ์ด๋ก ์ƒ ๋น„์Šทํ•ด๋„ ์‹ค์ธก์—์„  ArrayList๊ฐ€ ๋” ๋น ๋ฅผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Œ(์บ์‹œ/๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ ์ตœ์ ํ™” ๋•Œ๋ฌธ).
  • ์กฐํšŒ๋Š” ๋ฌด์กฐ๊ฑด ArrayList ๊ฐ•์„ธ.
  • ์‹ค๋ฌด์—์„  ArrayList ๊ธฐ๋ณธ, ํŠน์ˆ˜ ์ผ€์ด์Šค(์•ž์‚ฝ์ž… ๋นˆ๋ฒˆ)๋งŒ LinkedList ๊ณ ๋ ค