[java] String, StringBuffer 및 StringBuilder

비교 나에게 실시간으로 상황을 알려주십시오 String, StringBuffer그리고 StringBuilder?



답변

변이성 차이 :

String이다 불변 당신이 그 값을 변경하려고하면, 또 다른 목적은 반면, 작성되는, StringBuffer그리고 StringBuilder있습니다 가변 그들의 값을 변경할 수 있습니다.

스레드 안전성 차이 :

의 차이 StringBuffer와는 StringBuilderStringBuffer스레드 안전합니다. 따라서 응용 프로그램을 단일 스레드에서만 실행해야하는 경우 사용하는 것이 좋습니다 StringBuilder. StringBuilder보다 효율적 StringBuffer입니다.

상황 :

  • 문자열이 변경되지 않으면 String객체는 변경할 수 없으므로 String 클래스를 사용하십시오 .
  • 문자열이 변경 될 수 있고 (예 : 문자열 구성시 많은 논리와 연산) 단일 스레드에서만 액세스 할 수 있다면 a를 사용하는 StringBuilder것으로 충분합니다.
  • 문자열이 변경되어 여러 스레드에서 액세스되는 경우 동기를 사용하므로 스레드 안전성을 갖기 StringBuffer때문에를 사용하십시오 StringBuffer.

답변

  • 당신은 사용 String불변의 구조가 적합한 경우; 에서 새로운 문자 시퀀스를 얻는 것은 StringCPU 시간 또는 메모리에서 허용 할 수없는 성능 저하를 가져올 수 있습니다 (데이터가 복사되지 않기 때문에 서브 스트링을 얻는 것이 CPU 효율적이지만, 이는 잠재적으로 훨씬 많은 양의 데이터가 할당 된 상태로 남아있을 수 있음).
  • StringBuilder일반적으로 여러 문자 시퀀스를 연결하기 위해 가변 문자 시퀀스를 만들어야 할 때 사용 합니다.
  • 당신이 사용하는 StringBuffer당신이 사용하는 것과 같은 상황에서 StringBuilder, 그러나 기본 문자열로 변경하는 경우 (여러 개의 스레드가 읽기 때문에 / modifyind 문자열 버퍼)를 동기화해야합니다.

여기 예를 참조 하십시오 .


답변

기본 사항 :

String불변의 클래스이므로 변경할 수 없습니다.
StringBuilder, 추가 문자를 교체하거나 제거하고 궁극적으로 변환 할 수있는 가변 클래스는 String
StringBuffer원래 동기화 버전StringBuilder

StringBuilder객체에 액세스하는 단일 스레드 만있는 모든 경우를 선호해야 합니다.

세부 사항 :

또한 StringBuilder/Buffers마술이 아니라 배열을 백업 개체로 사용하기 때문에 배열이 가득 차면 배열을 다시 할당해야합니다. 호출 StringBuilder/Buffer될 때마다 지속적으로 크기를 조정할 필요가없는 원래 충분히 큰 객체를 작성하십시오 .append().

크기 조정은 매우 저하 될 수 있습니다. 기본적으로 확장해야 할 때마다 기본 배열의 크기를 현재 크기의 2 배로 조정합니다. 이로 인해 많은 양의 RAM이 할당되고 StringBuilder/Buffer클래스가 커지기 시작할 때 사용되지 않을 수 있습니다.

자바 String x = "A" + "B";에서는 StringBuilder배후를 사용 합니다. 따라서 간단한 경우에는 자신을 선언해도 이점이 없습니다. 그러나 String4k 미만의 큰 객체를 빌드하는 경우 선언하는 StringBuilder sb = StringBuilder(4096);것이 연결 또는 16자인 기본 생성자 를 사용하는 것보다 훨씬 효율적 입니다. 당신이 경우 String적은 10K보다가 될 것입니다 후 안전을 위해 10K에 생성자를 초기화합니다. 그러나 10k로 초기화되면 10k보다 큰 1자를 쓰면 다시 할당되고 20k 배열로 복사됩니다. 따라서 높은 초기화는 낮은 것보다 낫습니다.

자동 크기 조정의 경우, 17 번째 문자에서 백업 배열이 재배치되어 32 자로 복사되고, 33 번째 문자에서 다시 발생하고 배열을 64 문자로 다시 할당하고 복사하게됩니다. 이 방법이 많은 재 할당 및 사본으로 어떻게 퇴보되는지 확인할 수 있습니다 StringBuilder/Buffer.

AbstractStringBuilder의 JDK 6 소스 코드에서 가져온 것입니다.

   void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
        value = Arrays.copyOf(value, newCapacity);
    }

가장 좋은 방법은 StringBuilder/Buffer손이 얼마나 큰지 알지 String못하지만 추측 할 수있는 경우 필요한 것보다 조금 크게 초기화하는 것 입니다. 필요한 것보다 약간 더 많은 메모리를 할당하는 것이 많은 재 할당 및 사본보다 낫습니다.

또한 String + 16 문자의 크기 만 할당 StringBuilder/Buffer하는 Stringas를 사용 하여 a 를 초기화하는 것을주의하십시오 . 대부분의 경우 피하려고하는 퇴화 재 할당 및 복사주기 만 시작합니다. 다음은 Java 6 소스 코드와 동일합니다.

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }

우연히 StringBuilder/Buffer생성하지 않았고 호출 된 생성자를 제어 할 수없는 인스턴스가 생길 경우, 재 할당 및 복사 동작의 변형을 피할 수있는 방법이 있습니다. .ensureCapacity()결과 String가 나아지도록 원하는 크기로 전화 하십시오 .

대안 :

참고로, 실제로 무거운 String 건물과 조작을 수행하는 경우 Ropes 라는 훨씬 성능 지향적 인 대안이 있습니다.

또 다른 대안은 StringList서브 클래 싱을 통해 구현 을 생성하고 ArrayList<String>카운터를 추가 .append()하여 목록의 모든 돌연변이 작업에서 문자 수를 추적 한 다음 재정 의하여 필요한 정확한 크기 .toString()를 생성 StringBuilder하고 목록을 반복하여 빌드하는 것입니다. 출력을 StringBuilder통해 인스턴스 변수를 만들고 결과를 ‘캐시’하고 .toString()무언가가 변경 될 때만 다시 생성해야합니다.

또한 String.format()고정 형식의 출력을 빌드 할 때 잊지 말고 컴파일러가 더 나은 결과를 얻을 수 있도록 최적화하십시오.


답변

연결을 의미합니까?

실제 예 : 많은 다른 문자열 중에서 새 문자열을 만들려고합니다 .

예를 들어 메시지를 보내려면 :

String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm  " + user.age + "yrs. old too"

StringBuilder

String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
          .append(" I saw your profile and got interested in you.<br>")
          .append(" I'm  " ).append( user.age ).append( "yrs. old too")
          .toString()

또는

String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as  fuzzy lollipop points out.

StringBuffer (구문은 StringBuilder와 동일하며 효과가 다릅니다)

StringBuffer vs. StringBuilder

전자는 동기화되고 나중에는 동기화되지 않습니다.

따라서 단일 스레드 (경우의 90 %)에서 여러 번 호출 하면 스레드 잠금을 소유하고 있는지 확인하지 않기 때문에 훨씬 빠르게 StringBuilder실행 됩니다.

따라서 사용하는 것이 좋습니다 StringBuilder(물론 동시에 두 개 이상의 스레드에 액세스하지 않는 한 드문 경우입니다)

String연결 ( + 연산자 사용 )은 StringBuilder아래에서 사용하도록 컴파일러에 의해 최적화 될 수 있으므로 Java의 초기에는 더 이상 걱정할 것이 없습니다. 새로운 String 객체를 작성했습니다. 최신 컴파일러는 더 이상이 작업을 수행하지 않지만 StringBuilder“오래된”컴파일러를 사용하는 경우를 대비 하여 사용하는 것이 좋습니다 .

편집하다

호기심이 많은 사람을 위해이 클래스에서 컴파일러가 수행하는 작업은 다음과 같습니다.

class StringConcatenation {
    int x;
    String literal = "Value is" + x;
    String builder = new StringBuilder().append("Value is").append(x).toString();
}

javap -c StringConcatenation

Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;

java.lang.String literal;

java.lang.String builder;

StringConcatenation();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   new #2; //class java/lang/StringBuilder
   8:   dup
   9:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   12:  ldc #4; //String Value is
   14:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   17:  aload_0
   18:  getfield    #6; //Field x:I
   21:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   24:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   27:  putfield    #9; //Field literal:Ljava/lang/String;
   30:  aload_0
   31:  new #2; //class java/lang/StringBuilder
   34:  dup
   35:  invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   38:  ldc #4; //String Value is
   40:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   43:  aload_0
   44:  getfield    #6; //Field x:I
   47:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   50:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   53:  putfield    #10; //Field builder:Ljava/lang/String;
   56:  return

}

숫자 5-27은 “literal”이라는 문자열입니다.

번호 31-53은 “builder”라는 문자열입니다.

차이점은 없습니다 . 두 문자열에 대해 정확히 동일한 코드가 실행됩니다.


답변

-------------------------------------------------- --------------------------------
                  String StringBuffer StringBuilder
-------------------------------------------------- --------------------------------
저장 영역 | 상수 문자열 풀 힙 힙
수정 가능 | 아니오 (불변) 예 (변동 가능) 예 (변동 가능)
스레드 안전 | 예 예 아니요
 성과 | 매우 빠름
-------------------------------------------------- --------------------------------


답변

끈 가족

String class문자열을 나타냅니다. Java 프로그램의 모든 문자열 리터럴 "abc"은이 클래스의 인스턴스로 구현됩니다.

String 객체는 불변 그들은 우리가 변경할 수 없습니다 생성되면. ( 문자열은 상수입니다 )

  • 생성자 또는 메소드를 사용하여 문자열을 작성하면 해당 문자열은 힙 메모리 에도 저장 됩니다 SringConstantPool. 그러나 풀에 저장하기 전에 intern()equals 메소드를 사용하여 풀의 동일한 컨텐츠로 오브젝트 가용성을 확인하는 메소드를 호출합니다 . 풀에서 문자열 복사를 사용할 수 있으면 참조를 반환합니다. 그렇지 않으면 String 객체가 풀에 추가되고 참조를 반환합니다.

    • Java 언어는 문자열 연결 연산자 ( +) 및 다른 객체를 문자열로 변환 하는 데 특별한 지원을 제공합니다 . 문자열 연결은 StringBuilder (또는 StringBuffer) 클래스와 해당 append 메서드를 통해 구현됩니다.
    String heapSCP = new String("Yash");
    heapSCP.concat(".");
    heapSCP = heapSCP + "M";
    heapSCP = heapSCP + 777;
    
    // For Example: String Source Code 
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
  • 문자열 리터럴은에 저장됩니다 StringConstantPool.

    String onlyPool = "Yash";

StringBuilderStringBuffer 는 변경 가능한 문자 시퀀스입니다. 즉, 이러한 객체의 값을 변경할 수 있습니다. StringBuffer는 StringBuilder와 동일한 메소드를 갖지만 StringBuffer의 각 메소드는 동기화되어 스레드로부터 안전합니다.

  • StringBuffer 및 StringBuilder 데이터는 new 연산자를 사용해서 만 만들 수 있습니다. 따라서 힙 메모리에 저장됩니다.

  • StringBuilder 인스턴스는 여러 스레드에서 사용하기에 안전하지 않습니다. 이러한 동기화가 필요한 경우 StringBuffer를 사용하는 것이 좋습니다.

    StringBuffer threadSafe = new StringBuffer("Yash");
    threadSafe.append(".M");
    threadSafe.toString();
    
    StringBuilder nonSync = new StringBuilder("Yash");
    nonSync.append(".M");
    nonSync.toString();
  • StringBuffer를하고 모두 StringBuilder 같은. 특별 방법을 가지고,된다
    replace(int start, int end, String str)하고 reverse().

    참고 : StringBuffer 및 SringBuilder는 구현을 제공하므로 변경할 수 Appendable Interface있습니다.


어느 것을 사용할 때.

  • 매번 값을 변경하지 않으려면 사용하는 것이 좋습니다 String Class. Comparable<T>값 을 정렬 하거나 비교 하려면 Generics의 일부로 이동하십시오 String Class.

    //ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
    Set<StringBuffer> set = new TreeSet<StringBuffer>();
    set.add( threadSafe );
    System.out.println("Set : "+ set);
  • 매번 값을 수정하려면 StringBuffer보다 빠른 StringBuilder를 사용하십시오. 여러 스레드가 값을 수정하는 경우 StringBuffer로 이동하십시오.


답변

또한 StringBuffer스레드 안전하지만 StringBuilder그렇지 않습니다.

따라서 다른 스레드가 액세스하는 실시간 상황 StringBuilder에서는 결정적이지 않은 결과가 발생할 수 있습니다.