Post

Integer.toString(int) vs String.valueOf(int) vs "" + int

Integer.toString(3) vs String.valueOf(3) vs “” + 3

자바에서 int를 문자열로 변환하는 방법은 여러가지가 있는데, 각 방식에 따라 차이점이 존재한다. Integer.toString(3), String.valueOf(3), 그리고 "" + 3는 모두 int를 문자열로 바꾸는 방법이지만, 미묘한 성능 차이내부 구현 차이가 있다. 이 세 가지를 성능, 내부 동작, 메모리, JIT 최적화 관점에서 하나씩 살펴보았다.


1. Integer.toString(int i)

🔧 내부 동작

1
2
3
4
5
6
7
8
9
10
11
12
public static String toString(int i) {
    int size = DecimalDigits.stringSize(i); // 자리수 계산
    if (COMPACT_STRINGS) {
        byte[] buf = new byte[size]; // Latin1 버퍼
        StringLatin1.getChars(i, size, buf);
        return new String(buf, LATIN1);
    } else {
        byte[] buf = new byte[size * 2]; // UTF16 버퍼
        StringUTF16.getChars(i, size, buf);
        return new String(buf, UTF16);
    }
}

💡 상세 요약

항목설명
동작 방식숫자의 자리수 계산 → byte 배열에 직접 숫자 문자 삽입 → String 생성
인코딩Latin1 또는 UTF-16 선택 (자바 9+ 기준)
성능가장 빠름 (중간 객체 없음, 최적화 경로 직접)
JIT 최적화COMPACT_STRINGSstatic final이라 constant-folding 가능
메모리Latin1 사용 시 1 byte/char → 절반 메모리 사용

📌 결론: 성능과 메모리 측면에서 가장 우수한 방식. 특히 성능 민감한 코드에서는 이 방식이 유리하다.


2. String.valueOf(int i)

🔧 내부 동작

1
2
3
public static String valueOf(int i) {
    return Integer.toString(i); // 그대로 toString 호출
}

➡️ 그냥 Integer.toString(i)의 thin wrapper이다. 하지만 null을 처리하는 공통 로직이 포함되어있어서 null에 대해서 런타임 에러에 대해서 비교적 안전하다.

💡 상세 요약

항목설명
동작 방식내부적으로 Integer.toString(i) 호출
장점오버로드 많아서 Object, null 등에도 유연
성능거의 동일하지만 미세하게 느릴 수 있음 (호출 depth 1단계 증가)
JIT 최적화컴파일러가 인라인 처리하므로 큰 차이 없음

📌 결론: null이 올 수 있는 경우나 모든 타입을 처리해야 할 때는 이걸 쓰는 게 더 안전함.


3. "" + int (문자열 연결)

🔧 내부 동작

컴파일 시 다음처럼 변환된다.

1
String s = new StringBuilder().append("").append(3).toString();

이건 어떤 리터럴이나 표현식과 +를 쓸 때 생기는 공통된 컴파일 최적화 방식입니다.

💡 상세 요약

항목설명
동작 방식StringBuilder 생성 → append("")append(3) (→ 내부적으로 Integer.toString(3)) → toString()
객체 생성최소 2개 (StringBuilder, String)
성능가장 느림 (GC 부담 증가, 메서드 호출 많음)
JIT 최적화제한적 최적화 가능. 반복문 안에서는 성능 저하 심각해짐
가독성간편해 보이지만 성능 손해 있음

📌 결론: 간단한 디버깅 용도로는 괜찮지만, 반복 루프나 성능 민감한 코드에서는 피해야 한다.


4. 최종 비교

방식내부 처리성능메모리 효율권장 상황
Integer.toString(i)직접 byte[] 조작 (최적화 경로)🥇 최고🥇 최고 (Latin1 사용)성능 최우선 상황
String.valueOf(i)Integer.toString(i) 호출🥈 거의 동일🥇 동일범용 처리 (Object, null 등 포함)
"" + iStringBuilder로 문자열 결합🥉 느림🥉 추가 객체 생성디버깅용, 단순 로그 출력 정도만

✨ JDK 9 이후의 String 메모리 구조

자바 8까지는 문자열이 내부적으로 char[] (2 byte per char)를 사용했지만, 자바 9부터는 byte[] + coder 구조로 바뀌었다.

1
2
3
// Java 9+
final byte[] value; // 실제 문자열
final byte coder;   // LATIN1(0) or UTF16(1)

이 덕분에 Latin1만 쓰면 메모리 절반으로 줄어들고, 캐시 효율도 좋아졌다. 그리고 그 최적화를 활용한 대표적인 예가 바로 Integer.toString()이다.

This post is licensed under CC BY 4.0 by the author.