String
1. String의 기본 개념
- 정의:
String
은 문자의 배열로, 문자열 클래스 - 자바의 String 클래스:
java.lang
패키지에 속하며, 기본적으로 import 없이 사용 가능 - 불변성: String 객체는 생성된 후 값을 변경할 수 없음. 값을 변경하면 새로운 객체가 생성
2. String 생성 방법
- 리터럴 방식
- 상수 풀(Constant Pool)에 저장
- 동일한 값이 있다면, 새로운 객체를 생성하지 않고 재사용
String str1 = "Hello";
- new 키워드 사용
- 힙 영역에 새 객체를 생성
- 값이 동일하더라도 새로운 객체 생성
String str2 = new String("Hello");
3. String의 주요 특징
- Immutable(불변): 문자열을 변경하는 작업은 새로운 객체를 생성
3.1참조 비교와 값 비교
==
: 참조값(객체의 메모리 주소)을 비교equals()
: 값 비교 (문자열 내용 비교)
Java의 String Pool, 리터럴과 객체 생성 방식의 차이, 참조값과 내용 비교 방법을 이해한다. 이를 통해 메모리 효율성과 동작 원리를 학습할 수 있다.
public class Main {
public static void main(String[] args) {
String s1 = "This is a Literal String test";
String s2 = "This is a Literal String test";
System.out.println("s1 == s2: " + s1 == s2); // false
System.out.println("s1 == s2: " + (s1 == s2)); // s1 == s2: true
System.out.println("s1.equals(s2): " + s1.equals(s2)); // s1.equals(s2): true
System.out.println(s1.getClass().getName() + "@"
+ Integer.toHexString(s1.hashCode()));// java.lang.String@544771c5
System.out.println(s2.getClass().getName() + "@"
+ Integer.toHexString(s2.hashCode()));// java.lang.String@544771c5
System.out.println(System.identityHashCode(s1)); // 51228289
System.out.println(System.identityHashCode(s2)); // 51228289
String s3 = new String("This is a Object String test");
String s4 = new String("This is a Object String test");
System.out.println("s3 == s4: " + s3 == s4); // false
System.out.println("s3 == s4: " + (s3 == s4)); // s3 == s4: false
System.out.println("s3.equals(s4): " + s3.equals(s4)); // s3.equals(s4): true
System.out.println(s3.getClass().getName() + "@"
+ Integer.toHexString(s3.hashCode())); // java.lang.String@a6fb9bd3
System.out.println(s4.getClass().getName() + "@"
+ Integer.toHexString(s4.hashCode())); // java.lang.String@a6fb9bd3
System.out.println(System.identityHashCode(s3)); // 455896770
System.out.println(System.identityHashCode(s4)); // 1323165413
String s5 = "This is a test";
String s6 = new String("This is a test");
System.out.println("s5 == s6: " + (s5 == s6)); // s5 == s6: false
System.out.println("s5 == s6: " + s5.equals(s6)); // s5 == s6: true
System.out.println(s5.getClass().getName() + "@"
+ Integer.toHexString(s5.hashCode())); // java.lang.String@544771c5
System.out.println(s6.getClass().getName() + "@"
+ Integer.toHexString(s6.hashCode())); // java.lang.String@544771c5
System.out.println(System.identityHashCode(s5)); // 511754216
System.out.println(System.identityHashCode(s6)); // 1721931908
}
}
3.2 Literal String 생성
문자열 리터럴은 String Pool에 저장되고, 동일한 내용의 리터럴(s2
)은 새로운 객체를 생성하지 않고 같은 객체를 참조할 수 있다. s1, s2
는 동일한 리터럴을 참조하므로 같은 메모리 공간을 공유한다.
String s1 = "This is a Literal String test";
String s2 = "This is a Literal String test";
3.3 연산자 우선순위
연산자 우선순위(Operator Priority)에 의해 반드시 소괄호()
를 작성해야만 한다. +
연산자는 ==
연산자보다 우선순위가 높기 때문에 의도와 다르게 s1 == s2
부터 실행되지 않고, "s1 == s2: " + s1
가 먼저 실행되어 원치 않은 수행 결과를 출력한다.
System.out.println("s1 == s2: " + s1 == s2); // false
3.4 == 연산자
==
연산자는 기본 자료형(Primitive Type)인 경우와 참조 자료형(Reference Type)인 경우에 비교 방식이 다르다.
- 기본 자료형
==
: 값을 비교 - 참조 자료형
==
: 참조값(객체의 메모리 주소)을 비교
System.out.println("s1 == s2: " + (s1 == s2)); // s1 == s2: true
두 문자열이 완전히 일치하는 문자열 리터럴을 ==
연산자로 비교하면 ture
이다.
3.5 equals() 메서드
equals()
메서드는 객체의 내용(값)을 비교한다. 기본적으로 Object
클래스에서 정의된 equals()
는 ==
와 동일하게 참조값을 비교한다. 하지만, String, Integer
등 일부 클래스에서는 equals()
가 내용(값) 비교로 오버라이드되어 있다.
System.out.println("s1.equals(s2): " + s1.equals(s2)); // s1.equals(s2): true
String
클래스 내부에 오버라이드된 equals()
메서드로s1, s2
두 문자열의 값이 동일한지 비교하면 true
이다.
3.6 Object.equals()
Object
클래스는 모든 클래스의 최상위 클래스이다. 기본적으로 Object
의 equals()
메서드는 참조값(메모리 주소)를 비교한다.
// Object 클래스 내부
public boolean equals(Object obj) {
return (this == obj); // 1단계: 참조 비교
}
여기서 this == obj
는 두 객체가 동일한 메모리 주소를 참조하는지 확인하는 연산이다. 따라서, Object
클래스의 equals()
는 기본적으로 값이 아니라 객체의 동일성(Identity)을 비교한다.
3.7 String.equals()
String
클래스는 Object
의 equals()
를 오버라이드했다. Object
클래스의 기본 구현은 참조 비교(this == obj
)만 수행하지만, String
클래스는 이를 오버라이드하여 타입과 값 비교를 수행하도록 동작을 변경했다. equals()
가 Object
의 메서드와 비슷해 보이지만, String
내부에서는 타입과 값을 확인하는 추가 논리가 포함되어 있다.
public boolean equals(Object anObject) {
if (this == anObject) { // 1단계: 참조 비교
return true;
}
// 2단계: 값 비교
return (anObject instanceof String aString) // 타입 확인
&& (!COMPACT_STRINGS || this.coder == aString.coder) // 내부 최적화 비교
&& StringLatin1.equals(value, aString.value); // 실제 값 비교
}
- 참조 비교 (
this == anObject
)
두 객체가 동일한 메모리 주소를 참조하면true
를 반환한다. - 타입 확인 (
anObject instanceof String
)anObject
가String
타입인지 확인한다. (타입이 다르면false
를 반환) - 값 비교 (
StringLatin1.equals(value, aString.value)
)
두String
객체의 내부 값 배열 (value
)을 비교한다.value
는char[]
또는byte[]
형태로 저장된 실제 문자열 데이터이다.
3.8 Object.toString()
Object
클래스의 toString()
메서드의 기본 hashCode()
구현은 데이터 값을 이용해 계산된 정수 값이다. 즉, 해시코드는 데이터 값에 기반하여 생성된 고유 값으로 메모리 주소, 참조값을 직접적으로 나타내지 않는다. 하지만, String
클래스에서 toString()
은 문자열 자체를 반환하도록 오버라이드되어 있다.
// Object 클래스 내부
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
3.9 String.toString()
String 클래스는 불변(Immutable)으로 설계되어 있다. 따라서 생성된 이후 상태를 변경할 수 없는 객체이므로, String 클래스의 toString()
은 객체의 데이터인 문자열 자체(this
)를 그대로 반환한다.
// String 클래스 내부
public String toString() {
return this;
}
3.10 String.toString() 실행 영역
아래 코드를 통해 String.toString()
의 실행에서 각 영역(메서드 영역, 힙 영역, 스택 영역)에 데이터가 어떻게 저장되는지, 그리고 순서를 자세히 알아보자. new 키워드로 생성된 String 인스턴스는 서로 전혀 다른 객체이기 때문에 서로 다른 힙 영역을 갖는다.
public class Main {
public static void main(String[] args) {
// Step 1: 힙 영역에 새로운 String 객체 생성
String str = new String("Hello");
// Step 2: toString() 호출 - 동일한 객체를 참조
String str1 = str.toString();
// Step 3: new String() 호출 - 새로운 객체 생성
String str2 = new String(str);
// Comparisons
System.out.println("str == str1: " + (str == str1)); // 참조 비교
System.out.println("str.equals(str1): " + str.equals(str1)); // 값 비교
System.out.println("str == str2: " + (str == str2)); // 참조 비교
System.out.println("str1 == str2: " + (str1 == str2)); // 참조 비교
System.out.println("str.equals(str2): " + str.equals(str2)); // 값 비교
}
}
// 실행 결과
str == str1: true
str.equals(str1): true
str == str2: false
str1 == str2: false
str.equals(str2): true
1. String str = new String("Hello");
"Hello"
문자열 리터럴이 String Pool에 저장된다.new String("Hello")
는 힙 영역에 새로운String
객체를 생성하고, 내부에"Hello"
값을 복사한다.- 스택 영역:
str
변수는 힙 객체를 참조한다.
2. String str1 = str.toString();
toString()
메서드는 현재 객체(this
)를 반환한다.- 따라서,
str1
은str
과 동일한 힙 객체를 참조한다. - 새로운 객체가 생성되지 않는다.
3. String str2 = new String(str);
new String(str)
는 힙 영역에 새로운String
객체를 생성한다.- 새 객체는
str
의 값을 복사하여 내부적으로 동일한 문자열 데이터를 저장한다. str2
는str
과 다른 힙 객체를 참조한다.
비교 결과 및 이유
비교 표현 | 결과 | 설명 |
---|---|---|
str == str1 |
true |
str1 은 str 과 동일한 객체를 참조 |
str.equals(str1) |
true |
equals() 는 문자열 내용을 비교하며, 두 객체의 내용이 동일 |
str == str2 |
false |
str2 는 new String(str) 로 생성된 새로운 객체 |
str1 == str2 |
false |
str1 과 str2 는 서로 다른 힙 객체를 참조 |
str.equals(str2) |
true |
equals() 는 문자열 내용을 비교하며, 두 객체의 내용이 동일 |
toString()
: 현재 객체(this
)를 반환하므로, 참조값이 동일new String()
: 항상 새로운 객체를 생성하므로 참조값이 다름==
와equals()
차이==
: 참조값(메모리 주소)을 비교equals()
: 문자열 내용을 비교
3.11 String.hashCode()
객체의 hashCode()
는 Object
클래스에 정의된 메서드로, 기본적으로 참조값 기반으로 해시코드를 반환한다. 하지만 String
, Integer
와 같은 클래스는 내용 기반으로 hashCode()
를 오버라이드하여, 동일한 내용(값)의 객체는 동일한 해시코드를 반환하도록 설계되었다. 그래서 String
클래스의 hashCode()
는 객체의 메모리 주소값이 아니라 문자열(값)을 기반으로 해시코드를 생성한다.
따라서 서로 다른 String
객체라 하더라도 문자열의 내용이 동일하다면 동일한 해시코드를 반환한다.
System.out.println(s1.getClass().getName() + "@"
+ Integer.toHexString(s1.hashCode()));// java.lang.String@544771c5
System.out.println(s2.getClass().getName() + "@"
+ Integer.toHexString(s2.hashCode()));// java.lang.String@544771c5
왜 String
은 내용 기반으로 hashCode()
를 계산할까?
1. 해시 기반 컬렉션의 활용HashMap
, HashSet
등 해시 기반 자료구조에서 키로 사용될 때, 동일한 문자열 값을 가진 String
객체들이 같은 해시코드를 가져야 제대로 작동한다.
Map<String, Integer> map = new HashMap<>();
map.put(new String("key"), 1);
System.out.println(map.get(new String("key"))); // 1 (내용 기반 비교)
2. 문자열 불변성String
은 불변(immutable) 객체이므로, 한 번 계산된 해시코드는 변경되지 않는다. 이는 효율적인 캐싱과 재사용을 가능하게 한다.
3.12 System.identityHashCode()
String
의 실제 참조값 기반 해시코드는 어떻게 확인할까?
객체의 참조값을 확인하려면 System.identityHashCode()
를 사용한다. s1, s2
는 동일한 문자열 리터럴을 참조하여 참조값이 동일하고, s3, s4
는 문자열(값)은 동일하더라도 참조하는 String 인스턴스가 서로 다르기 때문에 참조값이 다르다.
String s1 = "This is a Literal String test"; // Literal
String s2 = "This is a Literal String test"; // Literal
...
System.out.println(System.identityHashCode(s1)); // 51228289
System.out.println(System.identityHashCode(s2)); // 51228289
String s3 = new String("This is a Object String test"); // new String()
String s4 = new String("This is a Object String test"); // new String()
...
System.out.println(System.identityHashCode(s3)); // 455896770
System.out.println(System.identityHashCode(s4)); // 1323165413
3.13 요약
String은 불변(Immutable)
- 문자열을 변경하면 새로운 객체가 생성된다.
참조와 값 비교
==
: 참조값(메모리 주소)을 비교(동일성)equals()
: 문자열의 값을 비교(동등성)
리터럴과 객체 생성 방식
- 문자열 리터럴은 String Pool에 저장되어 메모리를 효율적으로 사용한다.
new String()
은 항상 새로운 객체를 생성한다.
연산자 우선순위 주의
+
연산자가==
보다 우선순위가 높으므로 괄호로 연산 순서를 명시해야 한다.
String의 equals()
Object
의equals()
를 오버라이드하여 값 비교를 수행한다.- 타입 확인 후 내부 데이터 배열을 비교한다.
toString() 동작
Object.toString()
: 클래스명과 해시코드 반환String.toString()
: 문자열 자체를 반환(데이터 그대로)String.toString()
은 현재 객체(this
)를 반환하여 동일한 참조값을 가짐
String 객체의 저장 영역
- 리터럴: String Pool에 저장, 동일한 문자열 리터럴은 동일한 객체를 참조
new String()
: 항상 새로운 힙 객체를 생성
hashCode()
String
클래스는 내용(값)을 기반으로 해시코드를 오버라이드- 동일한 내용의 문자열은 동일한 해시코드를 가짐
HashMap
,HashSet
에서 키로 사용 시, 동일한 내용의 문자열은 같은 해시코드를 반환해 올바르게 작동
System.identityHashCode()
- 객체의 실제 참조값 기반 해시코드를 확인
- 동일한 리터럴은 참조값이 동일,
new String()
은 참조값이 다름
4. String 메서드
String
클래스의 주요 메서드들을 시그니처와 함께 나열한 목록이다.
4.1 문자열 길이 및 정보
int length();
boolean isEmpty();
boolean isBlank();
char charAt(int index);
int codePointAt(int index);
int codePointBefore(int index);
int codePointCount(int beginIndex, int endIndex);
1. int length()
: 문자열의 길이를 반환
String str = "Hello";
System.out.println(str.length()); // 출력: 5
2. boolean isEmpty()
: 문자열이 비어있는지 확인. 문자열의 길이가 0이면 true
를 반환
String str1 = "";
String str2 = " ";
System.out.println(str1.isEmpty()); // 출력: true
System.out.println(str2.isEmpty()); // 출력: false
3. boolean isBlank()
: 문자열이 비어있거나 공백 문자(스페이스, 탭, 줄바꿈 등)로만 이루어져 있는지 확인
String str1 = "";
String str2 = " ";
String str3 = "\n\t";
System.out.println(str1.isBlank()); // 출력: true
System.out.println(str2.isBlank()); // 출력: true
System.out.println(str3.isBlank()); // 출력: true
4. char charAt(int index)
: 문자열에서 주어진 인덱스에 위치한 문자를 반환
(0부터 시작하는 인덱스를 사용. 범위를 벗어나면 IndexOutOfBoundsException
이 발생)
String str = "Hello";
System.out.println(str.charAt(0)); // 출력: H
System.out.println(str.charAt(4)); // 출력: o
5. int codePointAt(int index)
: 인덱스에서 Unicode 코드 포인트를 반환
(다중 바이트 문자에 대해 올바르게 처리)
String str = "A💖B";
System.out.println(str.codePointAt(1)); // 출력: 128150 (💖의 유니코드 값)
6. int codePointBefore(int index)
: 인덱스 앞에 있는 문자에 대한 Unicode 코드 포인트를 반환
String str = "A💖B";
System.out.println(str.codePointBefore(2)); // 출력: 128150 (💖의 유니코드 값)
7. int codePointCount(int beginIndex, int endIndex)
: 시작 인덱스부터 종료 인덱스까지의 수를 반환
String str = "A💖B";
System.out.println(str.codePointCount(0, str.length())); // 출력: 3 (A, 💖, B)
8. isEmpty
vs isBlank
차이점
메서드 | 동작 | 예제 |
---|---|---|
isEmpty |
문자열이 길이가 0인지 확인 ("" 만 true ) |
"".isEmpty() -> true |
isBlank |
문자열이 비어있거나 공백 문자만 포함 (" " , "\n\t" 등도 true ) |
" ".isBlank() -> true |
isEmpty
는 문자열 길이만 검사하며 공백은 포함된 것으로 간주isBlank
는 공백 문자가 포함된 문자열도 비어있는 것으로 간주
9. Unicode 코드 포인트
- 유니코드 코드 포인트는 각 문자를 전 세계적으로 고유하게 식별하는 정수 값(
U+0000
~U+10FFFF
) - 16진수로 표시 (
U+
접두사 사용.A
:U+0041
,한
:U+D55C
,💖
:U+1F496
)
Java에서는 UTF-16 인코딩을 사용하므로, 대부분의 문자(U+0000
~ U+FFFF
)는 1개의 코드 유닛으로 표현되고, U+10000
이상 문자(예: 이모지)는 2개의 코드 유닛(Surrogate Pair)으로 표현된다. 예를 들어 💖
(128150(U+1F496)
)는 UTF-16에서 D83D
와 DC96
두 개의 코드 유닛으로 저장된다.
문자 | Unicode 코드 포인트 | UTF-16 코드 유닛 |
---|---|---|
A |
U+0041 |
0041 |
한 |
U+D55C |
D55C |
💖 |
U+1F496 |
D83D DC96 (Surrogate Pair) |
- 다국어 지원: 다양한 언어의 문자를 고유하게 식별하여, 전 세계 언어를 지원
- 정확한 문자 처리: UTF-16에서는 하나의 문자(예: 이모지)가 여러 코드 유닛으로 표현될 수 있으므로, 정확한 문자 길이 계산과 비교를 위해 코드 포인트를 사용해야 함
4.2 문자열 검색
boolean contains(CharSequence s);
boolean startsWith(String prefix);
boolean startsWith(String prefix, int offset);
boolean endsWith(String suffix);
int indexOf(int ch);
int indexOf(int ch, int fromIndex);
int indexOf(String str);
int indexOf(String str, int fromIndex);
int lastIndexOf(int ch);
int lastIndexOf(int ch, int fromIndex);
int lastIndexOf(String str);
int lastIndexOf(String str, int fromIndex);
1. boolean contains(CharSequence s)
: 문자열에 지정된 문자 시퀀스(CharSequence
)가 포함되어 있는지 확인
String str = "Hello, World!";
System.out.println(str.contains("World")); // true
System.out.println(str.contains("Java")); // false
2. boolean startsWith(String prefix)
: 문자열이 지정된 접두사(prefix
)로 시작하는지 확인
String str = "Hello, World!";
System.out.println(str.startsWith("Hello")); // true
System.out.println(str.startsWith("World")); // false
3. boolean startsWith(String prefix, int offset)
:
문자열이 지정된 위치(offset
)에서 시작하여 특정 접두사(prefix
)와 일치하는지 확인
String str = "Hello, World!";
System.out.println(str.startsWith("World", 7)); // true
System.out.println(str.startsWith("Hello", 7)); // false
4. boolean endsWith(String suffix)
: 문자열이 지정된 접미사(suffix
)로 끝나는지 확인
String str = "Hello, World!";
System.out.println(str.endsWith("World!")); // true
System.out.println(str.endsWith("Hello")); // false
5. int indexOf(int ch)
: 문자열에서 지정된 문자(ch
)가 처음 등장하는 위치(인덱스)를 반환(없으면 -1
을 반환)
String str = "Hello, World!";
System.out.println(str.indexOf('o')); // 4
System.out.println(str.indexOf('z')); // -1
6. int indexOf(int ch, int fromIndex)
:
문자열에서 지정된 위치(fromIndex
)부터 시작하여 지정된 문자(ch
)가 처음 등장하는 위치를 반환
String str = "Hello, World!";
System.out.println(str.indexOf('o', 5)); // 8
System.out.println(str.indexOf('o', 9)); // -1
7. int indexOf(String str)
문자열에서 지정된 문자열(str
)이 처음으로 등장하는 위치(인덱스)를 반환(없으면 -1
을 반환)
String str = "Hello, World!";
System.out.println(str.indexOf("World")); // 7
System.out.println(str.indexOf("Java")); // -1
8. int indexOf(String str, int fromIndex)
문자열에서 지정된 위치(fromIndex
)부터 시작하여 지정된 문자열(str
)이 처음 등장하는 위치를 반환
String str = "Hello, Hello!";
System.out.println(str.indexOf("Hello", 1)); // 7
System.out.println(str.indexOf("Hello", 8)); // -1
9. int lastIndexOf(int ch)
:
문자열에서 지정된 문자(ch
)가 마지막으로 등장하는 위치(인덱스)를 반환(없으면 -1
을 반환)
String str = "Hello, World!";
System.out.println(str.lastIndexOf('o')); // 8
System.out.println(str.lastIndexOf('z')); // -1
10. int lastIndexOf(int ch, int fromIndex)
문자열에서 지정된 위치(fromIndex
)부터 역방향으로 검색하여 지정된 문자(ch
)가 마지막으로 등장하는 위치를 반환
String str = "Hello, World!";
System.out.println(str.lastIndexOf('o', 7)); // 4
System.out.println(str.lastIndexOf('o', 3)); // -1
11. int lastIndexOf(String str)
문자열에서 지정된 문자열(str
)이 마지막으로 등장하는 위치(인덱스)를 반환(없으면 -1
을 반환)
String str = "Hello, World! Hello!";
System.out.println(str.lastIndexOf("Hello")); // 14
System.out.println(str.lastIndexOf("Java")); // -1
12. int lastIndexOf(String str, int fromIndex)
문자열에서 지정된 위치(fromIndex
)부터 역방향으로 검색하여 지정된 문자열(str
)이 마지막으로 등장하는 위치를 반환
String str = "Hello, World! Hello!";
System.out.println(str.lastIndexOf("Hello", 13)); // 0
System.out.println(str.lastIndexOf("Hello", 5)); // 0
4.3 문자열 비교
boolean equals(Object anObject);
boolean equalsIgnoreCase(String anotherString);
int compareTo(String anotherString);
int compareToIgnoreCase(String str);
boolean matches(String regex);
boolean regionMatches(int toffset, String other, int ooffset, int len);
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len);
1. boolean equals(Object anObject)
: 문자열의 내용(값)이 주어진 객체와 동일한지 확인(대소문자를 구분)
String str1 = "Hello";
String str2 = "Hello";
String str3 = "hello";
System.out.println(str1.equals(str2)); // true
System.out.println(str1.equals(str3)); // false
2. boolean equalsIgnoreCase(String anotherString)
: 문자열의 내용이 주어진 문자열과 동일한지 확인(대소문자를 구분하지 않음)
String str1 = "Hello";
String str2 = "hello";
System.out.println(str1.equalsIgnoreCase(str2)); // true
System.out.println(str1.equalsIgnoreCase("HELLO")); // true
System.out.println(str1.equalsIgnoreCase("World")); // false
3. int compareTo(String anotherString)
: 사전 순서(lexicographical order)로 두 문자열을 비교
- 반환값
0
: 문자열이 같음1
: 현재 문자열이 비교 대상보다 큼-1
: 현재 문자열이 비교 대상보다 작음
String str1 = "apple";
String str2 = "banana";
System.out.println(str1.compareTo(str2)); // -1 (apple < banana)
System.out.println(str2.compareTo(str1)); // 1 (banana > apple)
System.out.println(str1.compareTo("apple")); // 0
4. int compareToIgnoreCase(String str)
: 사전 순서로 문자열을 비교하지만 대소문자를 구분하지 않음
String str1 = "apple";
String str2 = "Apple";
System.out.println(str1.compareToIgnoreCase(str2)); // 0
System.out.println("banana".compareToIgnoreCase("Apple")); // 1 (banana > apple)
System.out.println("apple".compareToIgnoreCase("Banana")); // -1 (apple < banana)
5. boolean matches(String regex)
: 문자열이 주어진 정규식(regex
)과 일치하는지 확인
String str = "abc123";
System.out.println(str.matches("[a-z]+\\d+")); // true (소문자 + 숫자 조합)
System.out.println(str.matches("\\d+")); // false (숫자만 포함되지 않음)
6. boolean regionMatches(int toffset, String other, int ooffset, int len)
현재 문자열과 다른 문자열의 지정된 영역이 동일한지 비교(대소문자를 구분)
toffset
: 현재 문자열의 시작 인덱스other
: 비교 대상 문자열ooffset
: 비교 대상 문자열의 시작 인덱스len
: 비교할 길이
String str1 = "HelloWorld";
String str2 = "World";
System.out.println(str1.regionMatches(5, str2, 0, 5)); // true (Hello**World**)
System.out.println(str1.regionMatches(0, str2, 0, 5)); // false
7. boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
현재 문자열과 다른 문자열의 지정된 영역이 동일한지 비교(대소문자를 무시할지 여부 설정이 가능)
ignoreCase
: 대소문자 구분 여부 설정 (true
이면 구분하지 않음)
String str1 = "HelloWorld";
String str2 = "world";
System.out.println(str1.regionMatches(true, 5, str2, 0, 5)); // true (대소문자 무시)
System.out.println(str1.regionMatches(false, 5, str2, 0, 5)); // false (대소문자 구분)
요약
equals
vsequalsIgnoreCase
: 대소문자 구분 여부compareTo
vscompareToIgnoreCase
: 사전 순 비교에서 대소문자 구분 여부matches
: 문자열과 정규식 비교regionMatches
: 문자열의 특정 영역 비교 (대소문자 구분 가능)
4.4 문자열 변환 및 복사
String substring(int beginIndex);
String substring(int beginIndex, int endIndex);
char[] toCharArray();
byte[] getBytes();
byte[] getBytes(Charset charset);
byte[] getBytes(String charsetName) throws UnsupportedEncodingException;
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
1. String substring(int beginIndex)
: 문자열에서 지정된 시작 인덱스(beginIndex
)부터 끝까지의 부분 문자열을 반환
String str = "Hello, World!";
System.out.println(str.substring(7)); // "World!"
2. String substring(int beginIndex, int endIndex)
:
문자열에서 지정된 시작 인덱스(beginIndex
)부터 종료 인덱스(endIndex
) 전까지의 부분 문자열을 반환
String str = "Hello, World!";
System.out.println(str.substring(0, 5)); // "Hello"
System.out.println(str.substring(7, 12)); // "World"
3. char[] toCharArray()
: 문자열을 char
배열로 변환하여 반환
String str = "Hello";
char[] charArray = str.toCharArray();
System.out.println(Arrays.toString(charArray)); // [H, e, l, l, o]
4. byte[] getBytes()
: 플랫폼의 기본 문자 인코딩을 사용하여 문자열을 바이트 배열로 변환
주의: 플랫폼 의존적이므로 특정 인코딩을 지정하는 것을 권장한다.
String str = "Hello";
byte[] byteArray = str.getBytes();
System.out.println(Arrays.toString(byteArray)); // [72, 101, 108, 108, 111] (ASCII 값)
5. byte[] getBytes(Charset charset)
: 지정된 Charset
을 사용하여 문자열을 바이트 배열로 변
String str = "Hello";
byte[] byteArray = str.getBytes(StandardCharsets.UTF_8);
System.out.println(Arrays.toString(byteArray)); // [72, 101, 108, 108, 111] (UTF-8 인코딩)
6. byte[] getBytes(String charsetName)
: 지정된 문자 인코딩(charsetName
)을 사용하여 문자열을 바이트 배열로 변환
try {
String str = "Hello";
byte[] byteArray = str.getBytes("UTF-16");
System.out.println(Arrays.toString(byteArray)); // UTF-16 인코딩 값 출력
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
7. void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
문자열의 특정 범위(srcBegin
~ srcEnd
)를 char
배열로 복사하여, 지정된 배열(dst
)의 특정 위치(dstBegin
)에 삽입
String str = "Hello, World!";
char[] dst = new char[5];
str.getChars(7, 12, dst, 0);
System.out.println(Arrays.toString(dst)); // [W, o, r, l, d]
요약
substring
: 문자열의 특정 부분을 추출toCharArray
: 문자열을char
배열로 변환getBytes
: 문자열을 바이트 배열로 변환 (인코딩 가능)getChars
: 문자열의 일부를char
배열에 복사
4.5 문자열 수정
String concat(String str);
String replace(char oldChar, char newChar);
String replace(CharSequence target, CharSequence replacement);
String replaceAll(String regex, String replacement);
String replaceFirst(String regex, String replacement);
String trim();
String strip();
String stripLeading();
String stripTrailing();
String repeat(int count);
1. String concat(String str)
: 주어진 문자열(str
)을 현재 문자열에 연결하여 새 문자열을 반환(원본 문자열은 변경되지 않음)
String str = "Hello";
String result = str.concat(", World!");
System.out.println(result); // "Hello, World!"
2. String replace(char oldChar, char newChar)
: 문자열 내의 모든 특정 문자(oldChar
)를 다른 문자(newChar
)로 대체
String str = "Hello, World!";
String result = str.replace('o', '0');
System.out.println(result); // "Hell0, W0rld!"
3. String replace(CharSequence target, CharSequence replacement)
:
문자열 내의 특정 시퀀스(target
)를 다른 시퀀스(replacement
)로 대체
String str = "Hello, World!";
String result = str.replace("World", "Java");
System.out.println(result); // "Hello, Java!"
4. String replaceAll(String regex, String replacement)
문자열에서 주어진 정규식(regex
)과 일치하는 모든 부분을 지정된 문자열(replacement
)로 대체
String str = "a1b2c3";
String result = str.replaceAll("\\d", "X"); // 숫자를 X로 대체
System.out.println(result); // "aXbXcX"
5. String replaceFirst(String regex, String replacement)
문자열에서 주어진 정규식(regex
)과 일치하는 첫 번째 부분만 대체
String str = "a1b2c3";
String result = str.replaceFirst("\\d", "X"); // 첫 번째 숫자만 X로 대체
System.out.println(result); // "aXb2c3"
6. String trim()
문자열의 양쪽 끝에서 공백(스페이스) 문자를 제거(중간의 공백은 제거되지 않음)
String str = " Hello, World! ";
System.out.println(str.trim()); // "Hello, World!"
7. String strip()
문자열의 양쪽 끝에서 모든 유니코드 공백을 제거
(Java 11부터 추가되었으며, trim()
과 비슷하지만 더 포괄적임)
String str = " Hello, World! ";
System.out.println(str.strip()); // "Hello, World!"
8. String stripLeading()
: 문자열의 왼쪽(시작 부분) 공백만 제거
String str = " Hello, World! ";
System.out.println(str.stripLeading()); // "Hello, World! "
9. String stripTrailing()
: 문자열의 오른쪽(끝 부분) 공백만 제거합
String str = " Hello, World! ";
System.out.println(str.stripTrailing()); // " Hello, World!"
10. String repeat(int count)
현재 문자열을 지정된 횟수(count
)만큼 반복하여 새로운 문자열을 반환(Java 11부터 추가)
String str = "Hi!";
System.out.println(str.repeat(3)); // "Hi!Hi!Hi!"
요약
concat
: 문자열 연결replace
: 특정 문자/문자열 대체replaceAll
&replaceFirst
: 정규식을 사용한 대체trim
&strip
: 문자열의 공백 제거 (차이:strip
은 유니코드 공백도 제거)stripLeading
&stripTrailing
: 좌/우 공백 제거repeat
: 문자열 반복
4.6 문자열 분리
String[] split(String regex);
String[] split(String regex, int limit);
1. String[] split(String regex)
: 문자열을 주어진 정규식(regex
)을 기준으로 분리하여 문자열 배열로 반환
- 분리 기준에 해당하는 문자열은 결과에 포함되지 않음
- 입력 문자열이 분리 기준에 맞지 않으면 원본 문자열을 포함하는 배열을 반환
String str = "apple,banana,grape";
String[] result = str.split(",");
System.out.println(Arrays.toString(result)); // [apple, banana, grape]
2. String[] split(String regex, int limit)
문자열을 주어진 정규식(regex
)을 기준으로 분리하여 문자열 배열로 반환(배열의 크기를 제한할 수 있음)
limit
동작:
limit > 0
: 최대limit
개의 문자열만 반환. 나머지는 마지막 요소에 포함limit == 0
: 모든 구분자를 기준으로 분리. 끝의 빈 문자열은 제거limit < 0
: 모든 구분자를 기준으로 분리. 끝의 빈 문자열도 포함
String str = "apple,banana,grape";
String[] result1 = str.split(",", 2);
System.out.println(Arrays.toString(result1)); // [apple, banana,grape]
String[] result2 = str.split(",", 0);
System.out.println(Arrays.toString(result2)); // [apple, banana, grape]
String[] result3 = str.split(",", -1);
System.out.println(Arrays.toString(result3)); // [apple, banana, grape]
추가 예제
1. 기본 분리
String str = "one two three";
String[] result = str.split(" ");
System.out.println(Arrays.toString(result)); // [one, two, three]
2. 정규식 사용
String str = "one1two2three";
String[] result = str.split("\\d"); // 숫자를 기준으로 분리
System.out.println(Arrays.toString(result)); // [one, two, three]
3. 빈 문자열 처리
String str = "apple,,,banana,,grape";
String[] result1 = str.split(",");
System.out.println(Arrays.toString(result1)); // [apple, , , banana, , grape]
String[] result2 = str.split(",", -1);
System.out.println(Arrays.toString(result2)); // [apple, , , banana, , grape, ]
4. limit
예제
String str = "apple,banana,grape";
System.out.println(Arrays.toString(str.split(",", 1))); // [apple,banana,grape]
System.out.println(Arrays.toString(str.split(",", 2))); // [apple, banana,grape]
System.out.println(Arrays.toString(str.split(",", 3))); // [apple, banana, grape]
System.out.println(Arrays.toString(str.split(",", 0))); // [apple, banana, grape]
요약
split(String regex)
: 주어진 정규식을 기준으로 문자열을 분리split(String regex, int limit)
: 분리 후 반환 배열의 크기(limit
)를 설정 가능limit > 0
: 최대limit
개의 문자열 반환limit == 0
: 모든 구분자로 분리하며, 끝의 빈 문자열 제거limit < 0
: 모든 구분자로 분리하며, 끝의 빈 문자열 포함
4.7 문자열 대소문자 변환
String toLowerCase();
String toLowerCase(Locale locale);
String toUpperCase();
String toUpperCase(Locale locale);
1. String toLowerCase()
: 문자열을 소문자로 변환한 새로운 문자열을 반환(기본적으로 기본 로케일을 사용)
String str = "Hello, World!";
System.out.println(str.toLowerCase()); // "hello, world!"
2. String toLowerCase(Locale locale)
: 문자열을 소문자로 변환한 새로운 문자열을 반환(지정된 로케일을 기반으로 변환)
특정 언어 및 지역 설정에 따라 다른 결과를 반환할 수 있음
String str = "HELLO, WORLD!";
// 터키어 로케일에서는 'I'가 'ı'로 변환됨
System.out.println(str.toLowerCase(Locale.forLanguageTag("tr"))); // "hello, world!"
3. String toUpperCase()
: 문자열을 대문자로 변환한 새로운 문자열을 반환(기본적으로 기본 로케일을 사용)
String str = "hello, world!";
System.out.println(str.toUpperCase()); // "HELLO, WORLD!"
4. String toUpperCase(Locale locale)
: 문자열을 대문자로 변환한 새로운 문자열을 반환(지정된 로케일을 기반으로 변환)
특정 언어 및 지역 설정에 따라 다른 결과를 반환할 수 있음
String str = "i̇stanbul";
주요 차이점
기본 로케일 vs 지정된 로케일
- 기본 메서드 (
toLowerCase()
및toUpperCase()
)는 시스템의 기본 로케일을 사용 - 로케일을 지정하면 해당 로케일에 맞는 문자 규칙을 따름
- 예: 터키어 로케일(
Locale.forLanguageTag("tr")
)에서는I
→ı
,i
→İ
로 변환
4.8 문자열 포맷팅
static String format(String format, Object... args);
static String format(Locale l, String format, Object... args);
1. static String format(String format, Object... args)
지정된 형식 문자열(format
)과 전달된 인수(args
)를 사용하여 서식화된 문자열을 반환
- 형식 지정자를 사용하여 문자열, 숫자, 날짜 등을 서식화할 수 있다.
- 기본 로케일을 사용한다.
- 형식 지정자 주요 예
%s
: 문자열%d
: 10진수 정수%f
: 부동소수점%n
: 줄바꿈%t
: 날짜/시간
String name = "Alice";
int age = 25;
double height = 165.5;
String result = String.format("Name: %s, Age: %d, Height: %.2f cm", name, age, height);
System.out.println(result); // 출력: Name: Alice, Age: 25, Height: 165.50 cm
2. static String format(Locale l, String format, Object... args)
- 지정된 로케일(
l
)과 형식 문자열(format
), 전달된 인수(args
)를 사용하여 서식화된 문자열을 반환한다. 로케일을 지정하면 숫자, 날짜 등 로케일 특유의 형식으로 서식화된다.
import java.util.Locale;
double number = 1234567.89;
// 기본 로케일
String resultDefault = String.format("Number: %,f", number);
System.out.println(resultDefault); // 출력: Number: 1,234,567.890000 (기본 로케일)
// 독일 로케일
String resultGerman = String.format(Locale.GERMANY, "Number: %,f", number);
System.out.println(resultGerman); // 출력: Number: 1.234.567,890000 (독일식)
// 프랑스 로케일
String resultFrench = String.format(Locale.FRANCE, "Number: %,f", number);
System.out.println(resultFrench); // 출력: Number: 1 234 567,890000 (프랑스식)
추가 예제
1. 문자열 서식화
String firstName = "John";
String lastName = "Doe";
System.out.println(String.format("Hello, %s %s!", firstName, lastName)); // 출력: Hello, John Doe!
2. 숫자 서식화
int quantity = 5;
double price = 10.5;
System.out.println(String.format("Total: %d items for $%.2f", quantity, price)); // 출력: Total: 5 items for $10.50
3. 날짜 서식화
import java.util.Date;
Date now = new Date();
System.out.println(String.format("Today is %tA, %<tB %<td, %<tY", now));
// 출력: Today is (요일), (월) (날짜), (연도)
4. 로케일 지정
import java.util.Locale;
double amount = 1234567.89;
System.out.println(String.format(Locale.US, "US: %,.2f", amount)); // US: 1,234,567.89
System.out.println(String.format(Locale.GERMANY, "Germany: %,.2f", amount)); // Germany: 1.234.567,89
System.out.println(String.format(Locale.FRANCE, "France: %,.2f", amount)); // France: 1 234 567,89
요약
String.format(String format, Object... args)
:- 문자열을 서식화하여 반환
- 기본 로케일 사용
String.format(Locale l, String format, Object... args)
:- 문자열을 서식화하며, 지정된 로케일을 사용
주요 활용:
- 숫자 및 날짜 포맷 지정
- 로케일에 따른 출력 형식 변경
- 간결하고 직관적인 서식화 지원
4.9 문자열 유틸리티
static String valueOf(boolean b);
static String valueOf(char c);
static String valueOf(char[] data);
static String valueOf(char[] data, int offset, int count);
static String valueOf(double d);
static String valueOf(float f);
static String valueOf(int i);
static String valueOf(long l);
static String valueOf(Object obj);
1. static String valueOf(boolean b)
: boolean
값을 문자열로 변환하여 반환
boolean flag = true;
String result = String.valueOf(flag);
System.out.println(result); // "true"
2. static String valueOf(char c)
: 단일 문자(char
)를 문자열로 변환하여 반환
char ch = 'A';
String result = String.valueOf(ch);
System.out.println(result); // "A"
3. static String valueOf(char[] data)
: 문자 배열 전체를 문자열로 변환하여 반환
char[] chars = {'H', 'e', 'l', 'l', 'o'};
String result = String.valueOf(chars);
System.out.println(result); // "Hello"
4. static String valueOf(char[] data, int offset, int count)
문자 배열의 지정된 범위(offset
부터 count
길이)를 문자열로 변환하여 반환
char[] chars = {'H', 'e', 'l', 'l', 'o'};
String result = String.valueOf(chars, 1, 3);
System.out.println(result); // "ell"
5. static String valueOf(double d)
: double
값을 문자열로 변환하여 반환
double num = 10.5;
String result = String.valueOf(num);
System.out.println(result); // "10.5"
6. static String valueOf(float f)
: float
값을 문자열로 변환하여 반환
float num = 5.75f;
String result = String.valueOf(num);
System.out.println(result); // "5.75"
7. static String valueOf(int i)
: int
값을 문자열로 변환하여 반환
int num = 42;
String result = String.valueOf(num);
System.out.println(result); // "42"
8. static String valueOf(long l)
: long
값을 문자열로 변환하여 반환
long num = 123456789L;
String result = String.valueOf(num);
System.out.println(result); // "123456789"
9. static String valueOf(Object obj)
: 객체의 toString()
결과를 문자열로 반환(객체가 null
이면 "null"
문자열을 반환)
Object obj = new Object();
System.out.println(String.valueOf(obj)); // "java.lang.Object@..."
System.out.println(String.valueOf(null)); // "null"
4.10 문자열 정규화
String intern();
1. String intern()
: 문자열 객체를 String Pool에 등록하거나, 이미 존재하는 경우 동일한 객체를 반환(메모리 효율성을 위해 사용)
String str1 = new String("Hello");
String str2 = "Hello";
String str3 = str1.intern();
System.out.println(str1 == str2); // false (str1은 힙에 생성)
System.out.println(str2 == str3); // true (str3은 String Pool에 있는 "Hello"를 참조)
4.11 기타 메서드
int hashCode();
String toString();
Object clone();
1. int hashCode()
: 문자열의 해시코드를 반환
문자열의 내용(값)을 기반으로 계산되며, 같은 내용을 가진 문자열은 동일한 해시코드를 가짐
String str = "Hello";
System.out.println(str.hashCode()); // "Hello"의 해시코드 출력
2. String toString()
: 문자열의 내용을 반환String
클래스에서 오버라이드되어 객체의 참조값이 아닌 문자열 자체를 반환
String str = "Hello";
System.out.println(str.toString()); // "Hello"
3. Object clone()
: String
클래스는 불변(immutable) 특성으로 인해, 클론을 호출하면 동일한 객체를 반환
String str = "Hello";
String cloneStr = (String) str.clone();
System.out.println(str == cloneStr); // true (같은 객체)
요약
valueOf
: 다양한 데이터 타입을 문자열로 변환intern
: 문자열을 String Pool에 등록하거나 기존 문자열 참조 반환hashCode
: 문자열의 내용을 기반으로 해시코드 반환toString
: 문자열 자체 반환clone
: 동일한 객체를 반환 (불변 특성으로 인해)
5. StringBuilder
StringBuilder
는 Java의 문자열 처리 클래스로, 변경 가능한 문자열(mutable string)을 다룰 때 사용StringBuilder
는 가변(mutable). (문자열을 수정할 때 새로운 객체를 생성하지 않음)- 따라서 문자열 연결, 삽입, 삭제 등 작업에서 메모리와 성능이 효율적
5.1 String vs StringBuilder 비교
특징 | String |
StringBuilder |
---|---|---|
불변/가변 | 불변 (Immutable) | 가변 (Mutable) |
수정 시 동작 | 새로운 객체 생성 | 같은 객체에서 변경 |
성능 | 수정 작업이 많으면 비효율적 | 수정 작업에 최적화 |
멀티스레드 환경 | 안전하지 않음 | 안전하지 않음 (동기화 필요 시 StringBuffer 사용) |
5.2 StringBuilder 주요 메서드
메서드 | 설명 |
---|---|
append(String str) |
문자열을 끝에 추가 |
insert(int offset, String str) |
특정 위치에 문자열 삽입 |
replace(int start, int end, String str) |
특정 범위를 다른 문자열로 대체 |
delete(int start, int end) |
특정 범위의 문자열 삭제 |
reverse() |
문자열을 뒤집음 |
capacity() |
내부 버퍼의 크기 반환 |
ensureCapacity(int minimumCapacity) |
내부 버퍼 크기를 최소값으로 확장 |
length() |
문자열의 현재 길이 반환 |
setLength(int newLength) |
문자열의 길이를 지정 |
charAt(int index) |
지정된 인덱스의 문자 반환 |
toString() |
StringBuilder 를 String 으로 변환 |
public StringBuilder append(String str);
public StringBuilder insert(int offset, String str);
public StringBuilder replace(int start, int end, String str);
public StringBuilder delete(int start, int end);
public StringBuilder reverse();
public int capacity();
public void ensureCapacity(int minimumCapacity);
public int length();
public void setLength(int newLength);
public String toString();
public class Main {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
// append
sb.append(", World!");
System.out.println(sb); // "Hello, World!"
// insert
sb.insert(6, "Beautiful ");
System.out.println(sb); // "Hello Beautiful World!"
// replace
sb.replace(6, 15, "Amazing");
System.out.println(sb); // "Hello Amazing World!"
// delete
sb.delete(5, 7);
System.out.println(sb); // "HelloAmazing World!"
// reverse
sb.reverse();
System.out.println(sb); // "!dlroW gnizamAolleH"
// capacity and ensureCapacity
sb.ensureCapacity(50);
System.out.println("Capacity: " + sb.capacity());
// setLength
sb.setLength(10);
System.out.println(sb); // "olleHgniza"
// toString
String result = sb.toString();
System.out.println("Final String: " + result);
}
}
5.3 StringBuilder의 내부 동작
- 내부 버퍼:
StringBuilder
는 내부적으로 버퍼(기본 크기: 16)를 사용해 문자열을 저장- 문자열 길이가 버퍼 크기를 초과하면 버퍼 크기가 자동으로 확장
- 가변성:
- 문자열 변경 시 기존 객체에서 직접 수정이 이루어지며, 새로운 객체를 생성하지 않음
언제 사용해야 할까?
- 문자열 변경이 빈번할 때
- 문자열 연결, 삽입, 삭제 작업이 많은 경우
String
대신StringBuilder
를 사용하면 성능이 향상
- 문자열 연결, 삽입, 삭제 작업이 많은 경우
- 멀티스레드 환경이 아닐 때
StringBuilder
는 동기화가 없으므로 멀티스레드 환경에서는StringBuffer
를 고려
5.4 StringBuilder를 사용하지 않을 경우
- 다음과 같은 코드는 성능에 영향을 미칠 수 있음
String result = "";
for (int i = 0; i < 100; i++) {
result += i; // 매번 새로운 객체 생성
}
StringBuilder
를 사용하면 효율적으로 작성할 수 있음
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
sb.append(i);
}
String result = sb.toString(); // 최종 문자열 생성
정리
StringBuilder
는 가변 문자열 작업에 최적화된 클래스append
,insert
,delete
등으로 문자열을 효율적으로 수정이 가능- 멀티스레드 환경에서는 동기화가 가능한
StringBuffer
를 고려
6. StringBuffer
StringBuffer
는 Java의 가변 문자열 클래스로, 문자열을 동적으로 수정할 수 있도록 설계StringBuffer
는 멀티스레드 환경에서 안전(Thread-safe)하게 문자열을 처리할 수 있도록 내부 메서드들이 동기화(synchronized)되어 있음- 불변 객체인 String과 달리, 문자열을 변경할 때 새로운 객체를 생성하지 않고 기존 객체에서 작업이 수행
6.1 StringBuffer의 주요 특징
특징 | String | StringBuilder | StringBuffer |
---|---|---|---|
가변성 | 불변 (Immutable) | 가변 (Mutable) | 가변 (Mutable) |
수정 시 동작 | 새로운 객체 생성 | 같은 객체에서 변경 | 같은 객체에서 변경 |
멀티스레드 환경 | 안전하지 않음 | 안전하지 않음 | 안전 (Thread-safe) |
성능 | 수정 작업이 많으면 비효율적 | 단일 스레드 환경에서 빠름 | 멀티스레드 환경에서는 느림 |
주요 사용 환경 | 변경이 적은 문자열 처리 | 단일 스레드에서 자주 변경되는 문자열 | 멀티스레드에서 자주 변경되는 문자열 |
6.2 StringBuffer의 주요 메서드
메서드 | 설명 |
---|---|
append(String str) |
문자열을 끝에 추가 |
insert(int offset, String str) |
특정 위치에 문자열 삽입 |
replace(int start, int end, String str) |
특정 범위를 다른 문자열로 대체 |
delete(int start, int end) |
특정 범위의 문자열 삭제 |
reverse() |
문자열을 뒤집음 |
capacity() |
내부 버퍼의 크기 반환 |
ensureCapacity(int minimumCapacity) |
내부 버퍼 크기를 최소값으로 확장 |
length() |
현재 문자열의 길이 반환 |
setLength(int newLength) |
문자열 길이를 설정 |
charAt(int index) |
지정된 인덱스의 문자 반환 |
toString() |
StringBuffer 객체를 String 으로 변환 |
public synchronized StringBuffer append(String str);
public synchronized StringBuffer insert(int offset, String str);
public synchronized StringBuffer replace(int start, int end, String str);
public synchronized StringBuffer delete(int start, int end);
public synchronized StringBuffer reverse();
public synchronized int capacity();
public synchronized void ensureCapacity(int minimumCapacity);
public synchronized int length();
public synchronized void setLength(int newLength);
public synchronized char charAt(int index);
public synchronized String toString();
public class Main {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello");
// append
sb.append(", World!");
System.out.println(sb); // "Hello, World!"
// insert
sb.insert(6, "Beautiful ");
System.out.println(sb); // "Hello Beautiful World!"
// replace
sb.replace(6, 15, "Amazing");
System.out.println(sb); // "Hello Amazing World!"
// delete
sb.delete(5, 7);
System.out.println(sb); // "HelloAmazing World!"
// reverse
sb.reverse();
System.out.println(sb); // "!dlroW gnizamAolleH"
// capacity and ensureCapacity
System.out.println("Capacity: " + sb.capacity()); // 현재 버퍼 크기
sb.ensureCapacity(50);
System.out.println("New Capacity: " + sb.capacity()); // 최소 50 이상
// length
System.out.println("Length: " + sb.length()); // 현재 문자열 길이
// setLength
sb.setLength(10);
System.out.println(sb); // "olleHgniza"
// charAt
System.out.println("Char at 1: " + sb.charAt(1)); // 'l'
// toString
String result = sb.toString();
System.out.println("Final String: " + result);
}
}
6.3 StringBuffer의 내부 동작
- 내부 버퍼:
StringBuffer
는 문자열을 저장하기 위해 내부 버퍼를 사용- 버퍼 크기가 문자열 길이를 초과하면 수정 작업이 버퍼 내에서 수행
- 버퍼 크기를 초과하면 새로운 크기의 버퍼가 생성되며 기존 내용을 복사
- 동기화:
StringBuffer
의 모든 메서드는 synchronized로 선언되어 있어, 멀티스레드 환경에서도 안전- 그러나 동기화로 인해 단일 스레드 환경에서는
StringBuilder
보다 느림
6.4 StringBuffer vs StringBuilder
특징 | StringBuffer |
StringBuilder |
---|---|---|
멀티스레드 환경 | 안전 (Thread-safe) | 안전하지 않음 |
성능 | 동기화로 인해 느림 | 단일 스레드에서 더 빠름 |
사용 목적 | 멀티스레드 환경 | 단일 스레드 환경 |
언제 사용해야 할까?
- 멀티스레드 환경:
- 여러 스레드가 문자열을 동시에 수정해야 할 때
StringBuffer
를 사용 - 동기화 덕분에 스레드 간 충돌을 방지
- 여러 스레드가 문자열을 동시에 수정해야 할 때
- 단일 스레드 환경에서는 비추천:
- 단일 스레드 환경에서는 동기화가 필요 없으므로 성능이 더 빠른
StringBuilder
를 사용하는 것이 좋음
- 단일 스레드 환경에서는 동기화가 필요 없으므로 성능이 더 빠른
정리
StringBuffer
는 가변 문자열 처리를 위한 클래스- 멀티스레드 환경에서 안전하게 문자열 작업을 수행할 수 있도록 동기화가 적용
- 문자열을 동적으로 수정해야 하는 멀티스레드 애플리케이션에서 유용
- 단일 스레드 환경에서는
StringBuilder
를 사용하는 것이 성능 면에서 더 적합
7. Arrays
Arrays
클래스는 배열을 조작하기 위한 다양한 유틸리티 메서드를 제공- 배열을 정렬, 검색, 복사, 비교, 변환 등의 작업을 효율적으로 수행
7.1 Arrays의 주요 메서드
메서드 | 설명 |
---|---|
sort() |
배열을 오름차순으로 정렬 |
binarySearch() |
정렬된 배열에서 이진 검색으로 값을 검색 |
equals() |
두 배열의 내용이 같은지 비교 |
fill() |
배열을 지정된 값으로 초기화 |
copyOf() |
배열을 복사하여 새 배열을 생성 |
copyOfRange() |
배열의 지정된 범위를 복사 |
toString() |
배열의 내용을 문자열로 변환 |
asList() |
배열을 List 로 변환 |
import java.util.Arrays;
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
// 1. sort
int[] numbers = {5, 2, 8, 3, 1};
Arrays.sort(numbers);
System.out.println("Sorted: " + Arrays.toString(numbers)); // [1, 2, 3, 5, 8]
// 2. binarySearch
int index = Arrays.binarySearch(numbers, 3);
System.out.println("Index of 3: " + index); // 2
// 3. equals
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
System.out.println("Arrays equal: " + Arrays.equals(arr1, arr2)); // true
// 4. fill
int[] filledArray = new int[5];
Arrays.fill(filledArray, 7);
System.out.println("Filled: " + Arrays.toString(filledArray)); // [7, 7, 7, 7, 7]
// 5. copyOf
int[] copiedArray = Arrays.copyOf(numbers, 7);
System.out.println("Copied: " + Arrays.toString(copiedArray)); // [1, 2, 3, 5, 8, 0, 0]
// 6. toString
System.out.println("Array as String: " + Arrays.toString(numbers)); // [1, 2, 3, 5, 8]
// 7. asList
String[] fruits = {"apple", "banana", "cherry"};
System.out.println("List: " + Arrays.asList(fruits)); // [apple, banana, cherry]
}
}
1. sort
메서드 (배열 정렬)
오름차순 정렬
int[] numbers = {5, 2, 8, 3, 1};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers)); // [1, 2, 3, 5, 8]
부분 정렬
int[] numbers = {5, 2, 8, 3, 1};
Arrays.sort(numbers, 1, 4);
System.out.println(Arrays.toString(numbers)); // [5, 2, 3, 8, 1]
객체 배열 정렬
String[] words = {"banana", "apple", "cherry"};
Arrays.sort(words);
System.out.println(Arrays.toString(words)); // [apple, banana, cherry]
사용자 정의 정렬 (Comparator)
String[] words = {"banana", "apple", "cherry"};
Arrays.sort(words, Comparator.reverseOrder());
System.out.println(Arrays.toString(words)); // [cherry, banana, apple]
2. binarySearch
메서드 (이진 검색)
정렬된 배열에서 값 검색
int[] numbers = {1, 2, 3, 5, 8};
int index = Arrays.binarySearch(numbers, 5);
System.out.println(index); // 3 (5의 인덱스)
값이 없을 경우
int[] numbers = {1, 2, 3, 5, 8};
int index = Arrays.binarySearch(numbers, 4);
System.out.println(index); // -4 (찾는 값이 없음을 나타냄)
3. equals
메서드 (배열 비교)
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
int[] arr3 = {3, 2, 1};
System.out.println(Arrays.equals(arr1, arr2)); // true
System.out.println(Arrays.equals(arr1, arr3)); // false
4. fill
메서드 (배열 값 채우기)
int[] numbers = new int[5];
Arrays.fill(numbers, 7);
System.out.println(Arrays.toString(numbers)); // [7, 7, 7, 7, 7]
부분 채우기
int[] numbers = new int[5];
Arrays.fill(numbers, 1, 4, 9); // 1~3 인덱스에 9로 채움
System.out.println(Arrays.toString(numbers)); // [0, 9, 9, 9, 0]
5. copyOf
메서드 (배열 복사)
int[] numbers = {1, 2, 3};
int[] copy = Arrays.copyOf(numbers, 5); // 길이를 5로 확장
System.out.println(Arrays.toString(copy)); // [1, 2, 3, 0, 0]
6. copyOfRange
메서드 (부분 복사)
int[] numbers = {1, 2, 3, 4, 5};
int[] rangeCopy = Arrays.copyOfRange(numbers, 1, 4); // 1~3 인덱스 복사
System.out.println(Arrays.toString(rangeCopy)); // [2, 3, 4]
7. toString
메서드 (배열 출력)
int[] numbers = {1, 2, 3};
System.out.println(Arrays.toString(numbers)); // [1, 2, 3]
다차원 배열 출력
int[][] matrix = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepToString(matrix)); // [[1, 2], [3, 4]]
8. asList
메서드 (배열을 리스트로 변환)
String[] fruits = {"apple", "banana", "cherry"};
List<String> list = Arrays.asList(fruits);
System.out.println(list); // [apple, banana, cherry]
주의:
Arrays.asList
로 생성된 리스트는 고정 크기입니다.
list.add("grape"); // UnsupportedOperationException 발생
9. parallelSort
메서드 (병렬 정렬 - Java 8 이상)
병렬 정렬 사용
int[] numbers = {5, 2, 8, 3, 1};
Arrays.parallelSort(numbers);
System.out.println(Arrays.toString(numbers)); // [1, 2, 3, 5, 8]
10. 기타 메서드
hashCode
메서드 (배열의 해시코드 생성)
int[] numbers = {1, 2, 3};
System.out.println(Arrays.hashCode(numbers)); // 배열의 해시코드 출력
deepHashCode
메서드 (다차원 배열의 해시코드 생성)
int[][] matrix = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepHashCode(matrix)); // 다차원 배열의 해시코드 출력
'자바 > 개인 정리' 카테고리의 다른 글
자바 암기 노트1 (1) | 2024.12.26 |
---|---|
JDK, JRE, JVM 총정리(feat. 자바 컴파일 과정) (1) | 2024.12.26 |
자바(Java): 자바 프로그램의 실행 과정(feat. 컴파일 타임 환경, 런타임 환경, JVM) (1) | 2024.09.09 |