[Java ] 개념노트 39 StringBuilder 이해하기

[Java 개념노트 39] StringBuilder 이해하기

안녕하세요. Java 개념노트 시리즈 서른아홉 번째 글입니다.

지난 글에서는 자바에서 문자열을 다루는 대표 클래스인 String 클래스에 대해 정리했습니다. 이번 글에서는 문자열을 자주 수정하거나 이어 붙일 때 더 효율적으로 사용할 수 있는 StringBuilder에 대해 알아보겠습니다.

String은 불변 객체이기 때문에 문자열을 계속 수정하는 것처럼 보여도 실제로는 새로운 문자열이 계속 만들어질 수 있습니다. 문자열을 여러 번 이어 붙여야 하는 상황에서는 StringBuilder를 사용하면 더 효율적으로 처리할 수 있습니다.


1. StringBuilder란?

StringBuilder는 문자열을 효율적으로 수정하고 조립하기 위한 클래스입니다.

String은 한 번 만들어지면 내부 내용이 바뀌지 않는 불변 객체입니다. 반면 StringBuilder는 하나의 객체 안에서 문자열 내용을 계속 변경할 수 있습니다.

쉽게 말하면
StringBuilder는 문자열을 계속 이어 붙이고, 수정하고, 삭제할 수 있는 문자열 조립 도구입니다.

2. StringBuilder가 필요한 이유

문자열을 한두 번 연결할 때는 String+ 연산자를 사용해도 괜찮습니다. 하지만 반복문 안에서 문자열을 계속 이어 붙이면 불필요한 문자열 객체가 많이 만들어질 수 있습니다.

String result = "";

for (int i = 1; i <= 5; i++) {
    result += i;
}

System.out.println(result);

실행 결과는 다음과 같습니다.

12345

결과는 정상적으로 나오지만, 내부적으로는 문자열이 반복해서 새로 만들어질 수 있습니다. 반복 횟수가 많아지면 비효율적일 수 있습니다.

주의
반복문 안에서 문자열을 계속 +로 이어 붙이는 코드는 비효율적일 수 있습니다. 이럴 때 StringBuilder를 사용하면 좋습니다.

3. String과 StringBuilder의 차이

StringStringBuilder의 가장 큰 차이는 문자열을 변경할 수 있는지 여부입니다.

구분 String StringBuilder
특징 불변 객체 변경 가능한 객체
문자열 수정 수정 시 새 문자열 생성 기존 객체 안에서 변경
사용 상황 문자열 변경이 적을 때 문자열을 여러 번 조립할 때
대표 사용법 text + "Java" builder.append("Java")

4. StringBuilder 객체 만들기

StringBuildernew 키워드를 사용해서 만들 수 있습니다.

StringBuilder sb = new StringBuilder();

처음부터 문자열을 넣어서 만들 수도 있습니다.

StringBuilder sb = new StringBuilder("Java");

이렇게 만든 StringBuilder 객체에 문자열을 추가하거나 수정할 수 있습니다.

5. append() 메서드

append()는 StringBuilder에서 가장 많이 사용하는 메서드입니다. 문자열 뒤에 값을 이어 붙일 때 사용합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        sb.append("Java");
        sb.append(" ");
        sb.append("Study");

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

Java Study

append()를 호출할 때마다 기존 문자열 뒤에 값이 추가됩니다.

핵심 포인트
문자열을 여러 번 이어 붙일 때는 StringBuilderappend()를 자주 사용합니다.

6. append()는 여러 자료형을 받을 수 있다

append()는 문자열뿐만 아니라 숫자, 문자, boolean 값도 받을 수 있습니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        sb.append("점수: ");
        sb.append(100);
        sb.append(", 합격 여부: ");
        sb.append(true);
        sb.append(", 등급: ");
        sb.append('A');

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

점수: 100, 합격 여부: true, 등급: A

숫자나 boolean 값을 넣어도 문자열 형태로 이어 붙습니다.

7. 메서드 체이닝

append()는 자기 자신인 StringBuilder 객체를 다시 반환합니다. 그래서 여러 append를 한 줄로 이어서 작성할 수 있습니다. 이런 방식을 메서드 체이닝이라고 합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        sb.append("Java")
          .append(" ")
          .append("StringBuilder")
          .append(" ")
          .append("Study");

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

Java StringBuilder Study

한 줄로 너무 길게 작성하면 읽기 어려울 수 있으므로, 적당히 줄바꿈해서 작성하면 좋습니다.

8. toString()으로 String으로 변환하기

StringBuilder는 문자열을 조립하는 도구입니다. 최종 결과를 String으로 사용하고 싶다면 toString()을 호출합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        sb.append("Hello");
        sb.append(" ");
        sb.append("Java");

        String result = sb.toString();

        System.out.println(result);
    }
}

실행 결과는 다음과 같습니다.

Hello Java

문자열 조립은 StringBuilder로 하고, 최종 결과는 toString()으로 꺼내는 흐름을 자주 사용합니다.

9. 반복문에서 StringBuilder 사용하기

반복문 안에서 문자열을 계속 이어 붙일 때 StringBuilder를 사용하면 좋습니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        for (int i = 1; i <= 5; i++) {
            sb.append(i);
        }

        System.out.println(sb.toString());
    }
}

실행 결과는 다음과 같습니다.

12345

반복문이 실행될 때마다 기존 StringBuilder 객체에 값이 추가됩니다. 문자열을 계속 새로 만드는 방식보다 효율적입니다.

10. 구분자를 넣어 문자열 만들기

여러 값을 하나의 문자열로 만들 때 쉼표 같은 구분자를 넣어야 할 때가 있습니다.

public class Main {
    public static void main(String[] args) {
        String[] words = {"Java", "Spring", "SQL"};

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < words.length; i++) {
            sb.append(words[i]);

            if (i < words.length - 1) {
                sb.append(", ");
            }
        }

        System.out.println(sb.toString());
    }
}

실행 결과는 다음과 같습니다.

Java, Spring, SQL

마지막 값 뒤에는 쉼표가 붙지 않도록 i < words.length - 1 조건을 사용했습니다.

11. insert() 메서드

insert()는 원하는 위치에 문자열이나 값을 삽입할 때 사용합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java Study");

        sb.insert(5, "Basic ");

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

Java Basic Study

insert(5, "Basic ")은 5번 인덱스 위치에 "Basic "을 삽입합니다.

12. delete() 메서드

delete()는 특정 범위의 문자열을 삭제할 때 사용합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello Java Study");

        sb.delete(5, 10);

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

Hello Study

delete(5, 10)은 5번 인덱스부터 10번 인덱스 바로 전까지 삭제합니다. substring()처럼 끝 인덱스는 포함되지 않습니다.

13. deleteCharAt() 메서드

deleteCharAt()은 특정 위치의 문자 하나를 삭제할 때 사용합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java!");

        sb.deleteCharAt(4);

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

Java

인덱스 4 위치의 느낌표 !가 삭제되었습니다.

주의
deleteCharAt()에 잘못된 인덱스를 넣으면 오류가 발생할 수 있습니다. 인덱스는 0부터 length() - 1까지 사용해야 합니다.

14. replace() 메서드

replace()는 특정 범위의 문자열을 다른 문자열로 바꿀 때 사용합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello Java");

        sb.replace(6, 10, "Spring");

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

Hello Spring

replace(6, 10, "Spring")은 6번 인덱스부터 10번 인덱스 바로 전까지의 문자열을 "Spring"으로 바꿉니다.

15. reverse() 메서드

reverse()는 문자열 순서를 뒤집을 때 사용합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java");

        sb.reverse();

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

avaJ

문자열이 뒤집혀서 출력됩니다.

16. length() 메서드

length()는 현재 StringBuilder에 들어 있는 문자열의 길이를 반환합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java");

        System.out.println(sb.length());

        sb.append(" Study");

        System.out.println(sb.length());
    }
}

실행 결과는 다음과 같습니다.

4
10

처음 문자열 "Java"의 길이는 4이고, " Study"를 추가한 뒤 길이는 10이 됩니다.

17. setLength() 메서드

setLength()는 StringBuilder의 길이를 변경할 때 사용합니다. 길이를 줄이면 뒤쪽 문자열이 잘립니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java Study");

        sb.setLength(4);

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

Java

길이를 4로 줄였기 때문에 앞의 "Java"만 남습니다.

18. charAt()과 setCharAt()

charAt()은 특정 위치의 문자를 읽을 때 사용합니다. setCharAt()은 특정 위치의 문자를 변경할 때 사용합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java");

        System.out.println(sb.charAt(0));

        sb.setCharAt(0, 'j');

        System.out.println(sb);
    }
}

실행 결과는 다음과 같습니다.

J
java

0번 인덱스의 문자 Jj로 변경했습니다.

19. capacity() 메서드

capacity()는 StringBuilder가 내부적으로 확보한 저장 공간의 크기를 반환합니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        System.out.println(sb.length());
        System.out.println(sb.capacity());

        sb.append("Java");

        System.out.println(sb.length());
        System.out.println(sb.capacity());
    }
}

실행 결과는 다음과 비슷합니다.

0
16
4
16

length()는 실제 문자열 길이이고, capacity()는 내부 저장 공간 크기입니다. 처음 공부할 때는 capacity()를 깊게 외우기보다 StringBuilder가 내부 공간을 가지고 문자열을 조립한다 정도로 이해하면 충분합니다.

20. StringBuilder와 StringBuffer

자바에는 StringBuilder와 비슷한 StringBuffer도 있습니다. 둘 다 문자열을 변경할 수 있는 클래스입니다.

구분 StringBuilder StringBuffer
특징 동기화를 지원하지 않음 동기화를 지원함
속도 대체로 빠름 동기화 때문에 상대적으로 느릴 수 있음
주 사용 상황 일반적인 문자열 조립 여러 스레드가 동시에 접근할 가능성이 있을 때

입문 단계에서는 대부분 StringBuilder를 먼저 익히면 됩니다.

21. StringBuilder 주요 메서드 정리

자주 사용하는 StringBuilder 메서드를 정리하면 다음과 같습니다.

메서드 역할 예시
append() 뒤에 값 추가 sb.append("Java")
insert() 특정 위치에 삽입 sb.insert(0, "Hi")
delete() 특정 범위 삭제 sb.delete(0, 3)
deleteCharAt() 특정 문자 하나 삭제 sb.deleteCharAt(0)
replace() 특정 범위 바꾸기 sb.replace(0, 4, "Spring")
reverse() 문자열 뒤집기 sb.reverse()
length() 문자열 길이 확인 sb.length()
toString() String으로 변환 sb.toString()

22. StringBuilder 전체 예제

이번에는 여러 메서드를 함께 사용하는 예제를 보겠습니다.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        sb.append("Java");
        sb.append(" Study");

        System.out.println(sb);

        sb.insert(5, "Basic ");
        System.out.println(sb);

        sb.replace(5, 10, "Core");
        System.out.println(sb);

        sb.delete(5, 10);
        System.out.println(sb);

        sb.append("!");
        System.out.println(sb);

        String result = sb.toString();
        System.out.println("최종 결과: " + result);
    }
}

실행 결과는 다음과 같습니다.

Java Study
Java Basic Study
Java Core Study
Java Study
Java Study!
최종 결과: Java Study!

23. StringBuilder 사용 시 자주 하는 실수

StringBuilder를 처음 사용할 때는 아래와 같은 실수를 자주 합니다.

실수 문제점 해결 방법
최종 결과를 String으로 변환하지 않음 String 타입이 필요한 곳에서 불편할 수 있음 toString() 사용
인덱스 범위 실수 insert, delete, charAt에서 오류 가능 0부터 length() - 1 범위 확인
delete 끝 인덱스 포함으로 착각 원하는 범위와 다르게 삭제될 수 있음 끝 인덱스는 포함되지 않음
StringBuilder를 문자열 비교에 사용 문자열 내용 비교 의도가 흐려짐 비교가 필요하면 String으로 변환 후 비교
간단한 문자열에도 무조건 StringBuilder 사용 코드가 불필요하게 길어질 수 있음 간단한 연결은 String도 충분함

24. 직접 연습해보기

아래 코드를 직접 작성하고 실행해보세요.

public class Main {
    public static void main(String[] args) {
        String[] menus = {"홈", "게시판", "마이페이지", "로그아웃"};

        StringBuilder sb = new StringBuilder();

        sb.append("메뉴: ");

        for (int i = 0; i < menus.length; i++) {
            sb.append(menus[i]);

            if (i < menus.length - 1) {
                sb.append(" | ");
            }
        }

        System.out.println(sb);

        sb.insert(0, "[Java Site] ");
        System.out.println(sb);

        sb.append(" !");
        System.out.println(sb);

        String result = sb.toString();
        System.out.println("최종 문자열: " + result);
    }
}

실행 결과는 다음과 같습니다.

메뉴: 홈 | 게시판 | 마이페이지 | 로그아웃
[Java Site] 메뉴: 홈 | 게시판 | 마이페이지 | 로그아웃
[Java Site] 메뉴: 홈 | 게시판 | 마이페이지 | 로그아웃 !
최종 문자열: [Java Site] 메뉴: 홈 | 게시판 | 마이페이지 | 로그아웃 !

25. 이번 글 정리

이번 글에서는 문자열을 효율적으로 조립하는 StringBuilder에 대해 정리했습니다. 핵심 내용은 다음과 같습니다.

  • StringBuilder는 문자열을 효율적으로 수정하고 조립하기 위한 클래스이다.
  • String은 불변 객체이지만, StringBuilder는 내용을 변경할 수 있다.
  • 반복문 안에서 문자열을 계속 이어 붙일 때 StringBuilder를 사용하면 좋다.
  • append()는 문자열 뒤에 값을 추가한다.
  • insert()는 특정 위치에 값을 삽입한다.
  • delete()는 특정 범위의 문자열을 삭제한다.
  • replace()는 특정 범위의 문자열을 다른 문자열로 바꾼다.
  • reverse()는 문자열을 뒤집는다.
  • length()는 현재 문자열 길이를 반환한다.
  • toString()은 StringBuilder 결과를 String으로 변환한다.
  • 간단한 문자열 연결은 String으로도 충분하지만, 반복적인 조립은 StringBuilder가 더 적합하다.

한 줄 요약
StringBuilder는 문자열을 여러 번 이어 붙이거나 수정해야 할 때 사용하는 효율적인 문자열 조립 클래스입니다.

다음 글 예고
다음 글에서는 [Java 개념노트 40] Wrapper 클래스 이해하기라는 주제로 기본 자료형을 객체처럼 다루는 방법과 박싱, 언박싱 개념을 정리해보겠습니다.

GWDEVELBlog Java 개념노트 시리즈