[Java] String 클래스

jinsung·약 20시간 전

Java

목록 보기
3/5
post-thumbnail

1. String 클래스 - 기본

String 클래스 구조

public final class String //자바 21 기준
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {

    @Stable
    private final byte[] value; // 문자열 보관
    // ... 여러 필드
    
    // ... 여러 생성자
    
    // ... 여러 메서드
    public String concat(String str){...}
    public String replace(char oldChar, char newChar){...}
    ...
}

String 클래스는 직접 다루기 불편한 char[ ]을 내부에 감추고 String 문자열로 다룰 수 있도록 제공한다.

기능(메서드)

String 클래스는 문자열로 처리할 수 있는 다양한 기능을 제공한다.

length()

  • 문자열 길이 반환

charAt(int index)

  • 특정 index의 문자 반환

subString(int beginIndex, int endIndex)

  • 문자열의 부분 문자열 반환

indexOf(String str)

  • 특정 문자열이 시작되는 인덱스 반환

toLowerCase(), toUpperCase()

  • 문자열을 소문자나 대문자로 반환

trim()

  • 문자열 양 끝의 공백을 제거

concat(String str)

  • 문자열 병합

2. String 클래스 - 비교

String 클래스 비교할 때는 항상 equals() 비교를 해야 한다.

String 을 비교할 때 new String()으로 생성됐는지 리터널로 생성됐는지 알 수 없기 때문에 equals()로 동등성 비교를 해야 한다.

String str = "hello";

위와 같이 문자열 리터널을 사용하는 경우 자바는 메모리 효율성과 성능 최적화를 위해 String Pool을 사용한다.

  • JVM이 클래스를 로딩하고 문자열 리터럴을 처리하는 과정에서 String Pool에 해당 문자열을 등록하거나 기존 문자열을 재사용한다. (같은 문자열이 있으면 만들지 않음) : 캐싱

  • "hello" 문자열 리터널을 사용하므로 문자열 풀에서 str과 같은 참조를 사용한다.

  • 문자열 풀 덕분에 문자를 사용하는 경우 메모리 사용을 줄이고 문자를 만드는 시간도 줄어 성능도 최적화된다.

정리

문자열 리터럴은 String Pool에서 관리된다.
같은 내용의 문자열 리터럴이 이미 존재하면 새로운 객체를 만들지 않고 기존 객체의 참조를 재사용한다.
이를 통해 메모리 사용량과 문자열 객체 생성 비용을 줄일 수 있다.


3. String 클래스 - 불변 객체

String 은 불변객체이다.
변경이 필요한 경우는 기존 값을 변경하지 않고 새로운 결과를 반환해 할당해야 한다.

String 왜 불변으로 설계됐을까?

만약 String 내부의 값을 변경할 수있다면, 기존에 String Pool에서 같은 문자를 참조하는 변수의 모든 문자가 함께 변경돼 버리는 문제가 발생한다.

strA가 참조하는 문자를 변경하면 strB의 문자도 함께 변경돼 사이드 이펙트 문제가 발생한다.


4. String 클래스 - 주요 메서드

문자열 정보 조회

length()

  • 문자열의 길이를 반환

isEmpty()

  • 문자열이 비어 있는지 확인

isBlank()

  • 문자열이 비어 있는지 확인

charAt(int index)

  • 지정된 인덱스에 있는 문자를 반환

문자열 비교

equals(Object anObject)

  • 두 문자열이 동일한지 비교

equalsIgnoreCase(String anotherString)

  • 두 문자열을 대소문자 구분 없이 비교

compareTo(String anotherString)

  • 두 문자열을 사전 순으로 비교

compareToIgnoreCase(String str)

  • 두 문자열을 대소문자 구분 없이 사전적으로 비교

startsWith(String prefix)

  • 문자열이 특정 접두사로 시작하는지 확인

endsWith(String suffix)

  • 문자열이 특정 접미사로 끝나는지 확인

문자열 검색

contains(CharSequence s)

  • 문자열이 특정 문자열을 포함하고 있는지 확인

indexOf(String ch) / indexOf(String ch, int fromIndex)

  • 문자열이 처음 등장하는 위치를 반환

lastIndexOf(String ch)

  • 문자열이 마지막으로 등장하는 위치를 반환

문자열 조작 / 변환

substring(int beginIndex) / substring(int beginIndex, int endIndex)

  • 문자열의 부분 문자열을 반환

concat(String str)

  • 문자열의 끝에 다른 문자열을 붙임

replace(CharSequence target, CharSequence replacement)

  • 특정 문자열을 새 문자열로 대체

replaceAll(String regex, String replacement)

  • 문자열에서 정규 표현식과 일치하는 부분을 새 문자열로 대체

replaceFirst(String regex, String replacement)

  • 문자열에서 정규 표현식과 일치하는 첫 번째 부분을 새 문자열로 대체

toLowerCase() / toUpperCase()

  • 문자열을 소문자나 대문자로 변환

trim()

  • 문자열 양쪽 끝의 공백을 제거

strip()

  • Whitespace 와 유니코드 공백을 포함해서 제거

문자열 분할 / 조합

split(String regex)

  • 문자열을 정규 표현식을 기준으로 분할

join(CharSequence delimiter, CharSequence... elements)

  • 주어진 구분자로 여러 문자열을 결합

기타 유틸리티

valueOf(Object obj)

  • 다양한 타입을 문자열로 변환

toCharArray()

  • 문자열을 문자 배열로 변환

format(String format, Object... args)

  • 형식 문자열과 인자를 사용하여 새로운 문자열을 생성

matches(String regex)

  • 문자열이 주어진 정규 표현식과 일치하는지 확인

참고

CharSequence는 String, StringBuilder의 상위 타입으로,
다양한 객체를 받을 수 있다.


5. StringBuilder - 가변 String

불변인 String 클래스의 단점은 문자를 더하거나 변경할 때마다 새로운 객체를 생성해야 한다는 점이다.

문자를 자주 변경해야 하는 상황이면 String 객체를 만들고 GC 해야한다.
결과적으로 CPU, 메모리 자원을 더 많이 사용하게 된다.

StringBuilder

이런 문제를 해결하기 위해 자바는 StringBuilder 라는 가변 Strin을 제공한다.

public final class StringBuilder
        extends AbstractStringBuilder
        implements java.io.Serializable, 
        			Comparable<StringBuilder>, 
                    CharSequence {
}
        
abstract class AbstractStringBuilder 
	implements Appendable, CharSequence {
    
	byte[] value;
}

StringBuilder은 AbstaractStringBuilder를 상속해 value를 사용한다.
가변이므로 final이 안 붙어있다.

StringBuilder sb = new StringBuilder();

sb.append("1");
sb.insert(1, "2");
sb.delete(0,1);
sb.reverse();

StringBuilder은 보통 문자열을 변경하는 동안만 사용하다가 문자열 변경이 끝나면 안전한 불변 String으로 변환하는 것이 좋다.


6. String 최적화

String 리터럴 최적화

String ab = "a" + "b" ; 

자바는 문자열 리터럴끼리 + 할시 문자열 결합 연산을 하지 않고 자동으로 합쳐준다.
연산이 일어나지 않기 때문에 성능이 향상된다.

String 변수 최적화

String a = "a";
String b = "b";
String ab = a + b;

컴파일 시점에는 변수에 어떤 값이 들어있는지 알수 없기 때문에 단순하게 합칠 수 없다.

String ab = new StringBuidler().append(a).append(b).toString();

자바에서 StringBuilder로 변환하여 문자열을 더한 뒤 다시 불변 String으로 변환하여 최적화한다.

StringBuilder를 직접 사용하는 것이 더 좋은 경우

  • 반복문에서 반복해서 문자를 연결할 때
  • 조건문을 통해 동적으로 문자열을 조합할 때
  • 복잡한 문자열의 특정 부분을 변경해야 할 때
  • 매우 긴 대용량 문자열을 다룰 때

참고: StringBuilder vs StringBuffer

StrinBuilder 와 똑같은 기능을 수행하는 StringBuffer 클래스도 있다.

  • StringBuffer 는 내부에 동기화가 되어 있어서, 멀티 스레드 상황에서 안전하지만 동기화 오버헤드로 인해 성능이 느리다.
  • StringBuilder 는 멀티 쓰레드 상황에서 안전하지 않지만 동기화 오버헤드가 없으므로 속도가 빠르다.

7. Method Chaining

public Number plus(int plusNum) {
	num += plusNum;
    return this;
}

plus 메서드를 보면 자기 자신(this)의 참조값을 반환한다.

Number num1 = new Number();
num1.add(1);
num1.add(2);
num1.add(3);

num2.add(1).add(2).add(3);

아래 num2처럼 메서드 호출 결과로 자기 자신의 참조값을 반환하면, 반환돼 참조값을 사용해 메서드 호출을 계속 이어나갈 수 있다.
이런 기법을 Method Chaining 이라고 한다.

profile
Backend Engineer

0개의 댓글