학습목표
· String은 클래스 선언에 따라 메모리에 저장되는 방식이 다르다
· String은 immutable(불변)하다
· StringBuilder와 StringBuffer
· StringBuilder와 StringBuffer
· StringJoiner
· Collectors 클래스의 joining 메서드
String은 클래스 선언에 따라 메모리에 저장되는 방식이 다르다.
String str1 = new String("abc"); //인스턴스로 생성된다.
String str2 = "abc"; //상수풀에 있는 문자열을 가르킨다.
JVM(Java Virtual Machine)에서는 아래와 같은 구조로 데이터를 저장한다.
String은 선언 방식에 따라 아래와 같이 힙메모리 또는 상수 풀(Runtime Constant Pool)에 저장된다.
즉, 상수 풀에 저장된 데이터는 같은 값을 선언하면 같은 메모리를 공유하지만, 힙메모리에 생성된 데이터는 같은 값을 선언하더라도 서로 다른 인스턴스에 저장된다.
따라서 아래 코드를 작성하면,
public class StringTest
{
public static void main(String[] args)
{
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2);
String str3 = "abc";
String str4 = "abc";
System.out.println(str3 == str4);
}
}
String은 immutable(불변)하다.
한번 선언되거나 생성된 문자열을 변경할 수 없다. String 클래스의 concat() 메서드 혹은 "+"을 이용하여 String을 연결하는 경우 문자열은 변경되는 것이 아니라 새로 생성된다.
아래 코드 처럼 상수형 char 배열 value에 값이 저장되는 것을 볼 수 있다.
그림으로 표현하면 다음과 같다.
String 클래스는 불변하기 때문에 멀티 쓰레드 환경에서 동기화를 신경 쓰지 않아도 된다는 장점이 있다. 하지만 문자열이 계속 변하는 상황에서 concat() 메서드 혹은 "+"을 계속 이용하면 1. 새로운 문자열을 만드는 오버헤드, 2. 기존 문자열이 가비지 컬렉터에 의해 제거되는 오버헤드가 추가적으로 발생하여 비효율적이다.
이럴 때는 StringBuilder와 StringBuffer를 사용할 수 있다.
StringBuilder와 StringBuffer
둘다 가변적인 char[] 배열을 멤버변수로 갖는 클래스다. 문자열을 변경하거나 연결할때 사용하면 효율적으로 문자열을 처리할 수 있다. apend() 메소드를 통해 문자열을 추가한다.
· 맨 앞 또는 중간에 문자열을 추가하려면 insert() 메서드 사용
· 문자열을 삭제하려면 delete() 메서드 사용
StringBuffer는 StringBuilder와 다르게 멀티 쓰레드프로그래밍에서 동기화(Synchronization)가 보장된다.
StringBuilder는 oracle 문서(https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)에서 따르면 대부분의 환경에서 StringBuffer보다 빠르기 때문에 멀티 쓰레드 환경이 아니라면 해당 클래스를 사용하는 것이 좋다.
StringBuilder와 StringBuffer
StringJoiner
· 순차적으로 나열되는 문자열을 처리할 때 사용
· java.util 패키지에 포함
▶ 예시 - StringJoiner가 유용한 케이스
다음과 같이 순차적으로 나열된 문자열을 처리한다고 가정하자.
String[] strArr = new String[] {"서울","부산","대구","전주"};
위 배열을 아래와 같이 콤마로 연결한 하나의 문자열로 만들어보자.
String cities = "서울, 부산, 대구, 전주";
이때 String에 계속 더하거나 StringBuilder나 StringBuffer를 사용하면, 맨 마지막 콤마를 처리하기 위해 if문 또는 substring 메서드를 사용하는 등 불편함이있다. 이러한 단점을 보완하기 위해 StringJoiner가 만들어졌다.
아래 코드와 같이 StringJoiner를 사용할 수 있으며, 생성자로 문자열 맨 앞에 들어갈 prefix와 뒤에 들어갈 suffix를 지정할 수도 있다.
import java.util.StringJoiner;
public class StringJoinerDemo {
public static void main(String[] args){
String[] strArr = new String[] {"서울","부산","대구","전주"};
StringJoiner joiner = new StringJoiner(" ,");
for(String str: strArr)
joiner.add(str);
System.out.println(joiner);
StringJoiner joiner2 = new StringJoiner(" ,","(",")"); //prefix, suffix 지정
for(String str: strArr)
joiner2.add(str);
System.out.println(joiner2);
}
}
Collectors 클래스의 joining 메서드
· StringJoiner의 기능을 Collector 클래스의 joining 메서드를 사용하여 스트림과 람다 표현식으로 나타낼 수 있음
import java.util.Arrays;
import java.util.stream.Collectors;
public class CollectorsJoiningDemo {
public static void main(String[] args){
String[] strArr = new String[] {"서울","부산","대구","전주"};
String cities = Arrays.stream(strArr)
.collect(Collectors.joining(","));
System.out.println(cities);
String cities2 = Arrays.stream(strArr)
.collect(Collectors.joining(",","(",")")); //prefix, suffix 지정
System.out.println(cities2);
}
}
출처
자바의신
패스트캠퍼스 강의
https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html
https://cjh5414.github.io/why-StringBuffer-and-StringBuilder-are-better-than-String/
'자바' 카테고리의 다른 글
J2EE 디자인 패턴 - Business Delegate Pattern (0) | 2021.12.03 |
---|---|
[Java] 자바 8에 추가/변경된 사항 (0) | 2021.09.29 |
[Java] NIO2란? (0) | 2021.09.24 |
[Java] 자바의 Serializable (0) | 2021.09.14 |
[Java] 자바의 Input과 Output (입출력, i/o) (0) | 2021.09.10 |
댓글