
java.lang 패키지는 Java 프로그래밍 언어의 핵심 클래스를 포함하고 있는 패키지로, 자주 사용되는 기본 클래스들을 포함하고 있습니다. java.lang 패키지의 대표적인 클래스들로는 Object, String, 래퍼 클래스들(Integer, Boolean, 등), Class, System 등이 있습니다.lang 패키지에서 중요하게 다룰 수 있는 내용들이 상당히 많고 복잡하기 때문에 우선은 필요한 개념들을 하나씩 차례대로 정리해볼 예정입니다. Object 클래스String 클래스Integer, Double, Boolean, 등)Class, System, Math, 등) java.lang 패키지의 핵심 클래스 중 String 클래스에 대해 자세히 살펴보겠습니다.java.lang 패키지에 포함된 String 클래스는 Java 프로그래밍에서 가장 기본적이고 중요한 클래스 중 하나입니다. private final char[] value;로 정의됐었지만, 자바 9 이후엔 private final byte[] value;로 기본적으로 정의됩니다. (다만, Latin-1 인코딩처럼 영어나 숫자로만 정의된 경우에 해당하는 것이고, 만약 한글 등을 포함한 UTF-16으로 인코딩된 경우엔 기존대로 char타입으로 정의됩니다.)String 클래스는 참조형 데이터 타입입니다. int, char)과 달리, String 객체는 힙(Heap) 메모리 영역에 생성된 객체의 주소를 참조합니다.String s = "Hello";로 문자열을 선언한 후 s = s + " World";와 같이 문자열을 변경하면 새로운 객체가 생성됩니다.new 연산자로 선언한 경우엔 인스턴스로써 힙 영역에 저장됩니다. (아래에서 다시 설명합니다)String str1 = "Hello, World!";
"Hello, World!"는 문자열 풀에 저장되며, 동일한 리터럴이 다시 사용될 경우 새로운 객체를 생성하지 않고, 기존 객체를 재사용합니다.== 연산자로 비교하면 true가 반환됩니다.String str2 = new String("Hello, World!");
"Hello, World!"라는 문자열이 힙 메모리 내에 새로운 객체로 생성됩니다. 따라서 동일한 내용의 문자열이라도 == 연산자로 비교하면 다른 객체로 인식됩니다.String 객체를 생성할 수도 있습니다. String으로 변환할 때 유용합니다.char[] chars = {'H', 'e', 'l', 'l', 'o'};
String str3 = new String(chars);
chars를 이용해 "Hello"라는 문자열을 바로 생성합니다.String 객체를 생성할 수 있습니다. byte[] bytes = {72, 101, 108, 108, 111}; // ASCII 값
String str4 = new String(bytes); // "Hello" 출력
String str5 = new String(chars, 1, 3); // "ell" 출력 (부분 추출)
String 객체는 불변성(immutable)을 가지며, 이는 한 번 생성된 문자열은 수정될 수 없음을 의미합니다. String 객체는 안전하게 여러 스레드에서 공유될 수 있습니다.public class StringImmutableExample {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = str1;
// str1에 새로운 값을 할당
str1 = str1 + ", World!";
// str1과 str2의 값 출력
System.out.println("str1: " + str1); // "Hello, World!"
System.out.println("str2: " + str2); // "Hello"
}
}
str1이 "Hello, World!"로 변경되었지만, 원래의 str1이 가리키던 "Hello" 문자열은 변경되지 않습니다. 대신, str1은 이제 새로운 "Hello, World!" 객체를 참조하게 됩니다. 따라서 str2는 여전히 "Hello"를 참조합니다.String 객체를 비교할 때는 항상 equals() 메서드를 사용해야 합니다. == 연산자는 두 객체의 참조 주소를 비교합니다. String 객체가 동일한 내용을 가지고 있더라도 서로 다른 메모리 주소를 참조하면 == 연산자는 false를 반환합니다.String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2); // false, 서로 다른 객체 참조
equals() 메서드는 두 객체의 실제 문자열 값을 비교합니다. true를 반환합니다.Object 클래스의 equals() 메서드의 오버라이딩이 이미 된 메서드라서 굳이 다시 오버라이딩 할 필요가 없습니다.String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1.equals(s2)); // true, 문자열 내용이 동일
== 연산자도 true를 반환할 수 있습니다.String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // true, 동일한 객체 참조
String 객체를 비교할 때는 항상 equals() 메서드를 사용해야 합니다.length(): 문자열의 길이를 반환합니다.isEmpty(): 문자열이 비어있는지(길이가 0인지) 확인합니다.isBlank(): 문자열이 공백 문자로만 구성되어 있는지 확인합니다.isBlank()는 문자열이 비어있어도 true를 반환합니다.equals(Object another): 두 문자열이 동일한지 비교합니다.equalsIgnoreCase(String another): 대소문자를 무시하고 두 문자열이 동일한지 비교합니다.compareTo(String another): 두 문자열을 사전 순서로 비교합니다.compareTo()는 문자열 앞부터 비교해서 처음으로 달라지는 문자(char)의 ASCII코드 혹은 유니코드 값(정수)의 차이를 반환합니다. (완전히 같으면 0 반환) public class StringInfoExample {
public static void main(String[] args) {
String str = "Hello World";
String emptyStr = "";
String blankStr = " ";
// 문자열의 길이 및 상태 조회
System.out.println("str.length(): " + str.length()); // 11
System.out.println("emptyStr.isEmpty(): " + emptyStr.isEmpty()); // true
System.out.println("blankStr.isBlank(): " + blankStr.isBlank()); // true
// 문자열 비교
String anotherStr = "HELLO WORLD";
System.out.println("str.equals(anotherStr): " + str.equals(anotherStr)); // false
System.out.println("str.equalsIgnoreCase(anotherStr): " + str.equalsIgnoreCase(anotherStr)); // true
System.out.println("str.compareTo(anotherStr): " + str.compareTo(anotherStr)); // > 0 (사전순으로 더 크다)
}
}
charAt(int index): 지정한 인덱스에 위치한 문자를 반환합니다.substring(int beginIndex, int endIndex): 지정한 범위 내의 부분 문자열을 반환합니다.indexOf(String str): 특정 문자나 문자열이 처음으로 등장하는 위치를 반환합니다.lastIndexOf(String str): 특정 문자나 문자열이 마지막으로 등장하는 위치를 반환합니다.contains(CharSequence sequence): 특정 문자나 문자열이 포함되어 있는지 확인합니다.startsWith(String prefix): 문자열이 지정한 접두사로 시작하는지 확인합니다.endsWith(String suffix): 문자열이 지정한 접미사로 끝나는지 확인합니다.matches(String regex): 문자열이 지정한 정규 표현식과 일치하는지 확인합니다.public class StringSearchExample {
public static void main(String[] args) {
String str = "Hello, World!";
// 특정 문자 또는 부분 문자열 조회
System.out.println("str.charAt(7): " + str.charAt(7)); // W
System.out.println("str.substring(7, 12): " + str.substring(7, 12)); // World
// 문자열 내 위치 검색
System.out.println("str.indexOf('o'): " + str.indexOf('o')); // 4
System.out.println("str.lastIndexOf('o'): " + str.lastIndexOf('o')); // 8
// 문자열 포함 여부 및 패턴 일치
System.out.println("str.contains('World'): " + str.contains("World")); // true
System.out.println("str.startsWith('Hello'): " + str.startsWith("Hello")); // true
System.out.println("str.endsWith('!'): " + str.endsWith("!")); // true
System.out.println("str.matches('.*World.*'): " + str.matches(".*World.*")); // true (정규식으로 포함 여부 확인)
}
}
concat(String str): 두 문자열을 결합합니다.replace(CharSequence target, CharSequence replacement): 문자열 내의 특정 부분을 다른 문자열로 대체합니다.replaceAll(String regex, String replacement): 정규 표현식에 일치하는 모든 부분을 대체합니다.replaceFirst(String regex, String replacement): 정규 표현식에 일치하는 첫 번째 부분만 대체합니다.toLowerCase(): 문자열을 소문자로 변환합니다.toUpperCase(): 문자열을 대문자로 변환합니다.trim(): 문자열 양 끝의 공백을 제거합니다.strip(): 공백 문자(공백, 탭 등)를 제거합니다. Java 11에서 도입되었으며, trim()과 달리 모든 종류의 공백 문자를 다룹니다.public class StringManipulationExample {
public static void main(String[] args) {
String str = "Hello";
String additionalStr = " World";
// 문자열 조합 및 치환
String combinedStr = str.concat(additionalStr);
System.out.println("combinedStr: " + combinedStr); // Hello World
String replacedStr = combinedStr.replace("World", "Java");
System.out.println("replacedStr: " + replacedStr); // Hello Java
// 대소문자 변환 및 공백 제거
System.out.println("replacedStr.toUpperCase(): " + replacedStr.toUpperCase()); // HELLO JAVA
String paddedStr = " Trim me ";
System.out.println("paddedStr.trim(): " + paddedStr.trim()); // "Trim me"
System.out.println("paddedStr.strip(): " + paddedStr.strip()); // "Trim me" (Java 11+)
}
}
split(String regex): 정규 표현식을 기준으로 문자열을 분할하여 배열로 반환합니다.join(CharSequence delimiter, CharSequence... elements): 지정한 구분자를 사용해 여러 문자열을 하나로 결합합니다.public class StringSplitJoinExample {
public static void main(String[] args) {
String str = "apple,banana,cherry";
// 문자열 분할
String[] fruits = str.split(",");
for (String fruit : fruits) {
System.out.println(fruit);
}
// 출력: apple, banana, cherry (각각 줄바꿈)
// 문자열 조합
String joinedStr = String.join(" & ", fruits);
System.out.println("joinedStr: " + joinedStr); // apple & banana & cherry
}
}
format(String format, Object... args): 지정된 형식에 맞추어 문자열을 생성합니다.String.format() 메서드는 다양한 포맷 지정자를 사용하여 문자열을 지정된 형식에 맞게 변환할 수 있도록 도와줍니다. % 기호로 시작하며, 이후에 다양한 문자를 결합해 특정 타입의 데이터를 원하는 형태로 포맷팅할 수 있습니다.주요 format 지정자 (주로 쓰이는 것만 정리했습니다)
- 숫자 관련 포맷 지정자
%d: 정수형 데이터를 10진수로 포맷팅%f: 실수형 데이터를 표시 (기본적으로 소수점 아래 6자리까지)%.nf: 실수형 데이터를 소수점 아래 n자리까지 표시하며 포맷팅- 문자 및 문자열 관련 포맷 지정자
%s: 문자열을 포맷팅%b: 논리형(불리언)을 포맷팅%n: 줄 바꿈 문자. OS에 따라 적절한 줄 바꿈을 삽입- 날짜 및 시간 관련 포맷 지정자
%tY: 4자리 연도 (예: 2024)%tm: 2자리 월 (예: 08)%td: 2자리 일 (예: 25)%tH: 2자리 시간 (24시간제, 예: 14)%tM: 2자리 분 (예: 30)%tS: 2자리 초 (예: 45)- 플래그 및 너비 관련 지정자
%0nd: n자리 숫자로 포맷팅하며, 자리 수가 부족할 경우 앞에 0을 채웁%+d: 정수에 부호를 포함하여 포맷팅%-nd: n자리 숫자로 포맷팅하며, 왼쪽 정렬%,d: 정수를 3자리마다 쉼표로 구분하여 포맷팅
valueOf(Object obj): 다양한 데이터 타입을 문자열로 변환합니다.toCharArray(): 문자열을 char 배열로 변환합니다.public class StringFormatExample {
public static void main(String[] args) {
int number = 42;
String text = "apples";
// 포맷 지정
String formattedStr = String.format("I have %d %s.", number, text);
System.out.println("formattedStr: " + formattedStr); // I have 42 apples.
// 다른 데이터 타입으로 변환
char[] charArray = formattedStr.toCharArray();
for (char c : charArray) {
System.out.print(c + " "); // I h a v e 4 2 a p p l e s .
}
System.out.println();
String boolStr = String.valueOf(true);
System.out.println("boolStr: " + boolStr); // true
}
}
intern(): 문자열을 문자열 풀에 등록하고 해당 문자열을 반환합니다.hashCode(): 문자열의 해시코드를 반환합니다.codePointAt(int index): 지정한 인덱스의 유니코드 코드 포인트를 반환합니다.public class StringUtilityExample {
public static void main(String[] args) {
String str = "Hello";
String internedStr = str.intern();
// intern() 사용
System.out.println("str == internedStr: " + (str == internedStr)); // true (문자열 풀에서 동일 객체 참조)
// hashCode()와 codePointAt()
System.out.println("str.hashCode(): " + str.hashCode()); // 해시코드 출력
System.out.println("str.codePointAt(1): " + str.codePointAt(1)); // 101 ('e'의 유니코드 포인트)
}
}
StringBuilder 클래스는 Java에서 문자열을 조작하는 데 매우 유용한 클래스입니다. String 클래스와 달리, StringBuilder는 가변(mutable) 객체로, 문자열을 여러 번 수정하는 경우 String보다 훨씬 더 효율적입니다. StringBuilder를 사용하면 불필요한 객체 생성을 줄이고 성능을 향상시킬 수 있습니다.StringBuilder는 String과 달리 문자열을 수정할 수 있습니다. StringBuilder 객체에서 문자열을 수정해도 새로운 객체가 생성되지 않고, 기존 객체에서 바로 수정됩니다.StringBuilder를 사용하면 메모리와 성능을 최적화할 수 있습니다.StringBuilder는 동기화되지 않아 멀티스레드 환경에서 안전하지 않습니다. 멀티스레드 환경에서는 StringBuffer를 사용하는 것이 적합합니다.StringBuffer와 StringBuilder의 주요 메서드들은 거의 동일합니다.append(String str): 문자열을 StringBuilder 객체의 끝에 추가합니다.insert(int offset, String str): 지정한 위치에 문자열을 삽입합니다.delete(int start, int end): 지정한 범위의 문자열을 삭제합니다.reverse(): 문자열을 역순으로 만듭니다.toString(): StringBuilder 객체를 String 객체로 변환합니다.public class StringBuilderExample {
public static void main(String[] args) {
// StringBuilder 생성
StringBuilder sb = new StringBuilder("Hello");
// 문자열 추가
sb.append(" World");
System.out.println("After append: " + sb.toString()); // Hello World
// 문자열 삽입
sb.insert(6, "Beautiful ");
System.out.println("After insert: " + sb.toString()); // Hello Beautiful World
// 문자열 삭제
sb.delete(6, 16);
System.out.println("After delete: " + sb.toString()); // Hello World
// 문자열 역순
sb.reverse();
System.out.println("After reverse: " + sb.toString()); // dlroW olleH
// StringBuilder를 String으로 변환
String result = sb.toString();
System.out.println("Final result: " + result); // dlroW olleH
}
}
StringBuilder 사용: 앞서 설명한 것처럼, 문자열을 여러 번 변경해야 하는 경우 StringBuilder를 사용하는 것이 좋습니다. String처럼 불변 객체를 계속 생성하지 않아도 되어 메모리 사용을 줄이고 성능을 향상시킬 수 있습니다.String Pool 활용: 동일한 문자열 리터럴을 반복적으로 사용할 경우, JVM의 문자열 풀을 활용하여 메모리를 최적화할 수 있습니다. + 연산을 피하고, 필요한 경우 StringBuilder 또는 StringBuffer를 사용하는 것이 효율적입니다.return this와 같이 본인의 객체를 반환하도록 설계해야합니다.public class MethodChainingExample {
public static void main(String[] args) {
// StringBuilder를 이용한 메서드 체이닝
String result = new StringBuilder("Hello")
.append(" ")
.append("World")
.insert(6, "Beautiful ")
.delete(6, 16)
.reverse()
.toString();
System.out.println("Final result with method chaining: " + result); // dlroW olleH
}
}
StringBuilder 객체에 대해 여러 메서드를 연속적으로 호출하면서 체이닝 패턴을 사용하였습니다. 이 패턴은 코드의 간결함과 직관성을 높여줍니다.String 클래스의 특징과 구조, 주요 메서드, 최적화 기법 및 문자열 조작에 대한 내용을 다루었습니다.String 클래스는 가장 기본적이고 중요한 클래스 중 하나로, 문자열 데이터를 다루기 위해 널리 사용됩니다.String의 불변성, StringBuilder의 가변성, 그리고 메서드 체이닝과 같은 패턴들은 Java에서 문자열을 효율적으로 관리하고 조작하는 데 필수적인 요소들입니다. 이러한 개념들을 잘 이해하고 활용하면, 더욱 효율적이고 성능 좋은 Java 프로그램을 작성할 수 있을 것입니다.String.format() 메서드나 System.out.printf()에서 주로 활용되는 포멧 지정자에 대해서 정리해볼 예정이고, 이후엔 래퍼클래스와 Class클래스에 대해서 다루어볼 예정입니다.