루프 후 문자열 버퍼 / 빌더 지우기


122

루프 후 Java에서 문자열 버퍼를 지우는 방법은 다음 반복에서 명확한 문자열 버퍼를 사용합니까?


2
또 다른 질문 : 왜 한 번의 루프 반복에만 SB를 사용합니까? 또 다른 내부 반복이 있습니까? 단순히 A + B + C + D를 수행하려는 경우 SB는 가치가 없습니다 (Java 컴파일러는 내부적으로 SB를 사용합니다). 조건부로 문자열의 일부를 추가하려는 경우 도움이되지만 그렇지 않으면 단순히 "+"를 사용하십시오.
helios

답변:


135

한 가지 옵션은 다음과 같이 삭제 방법을 사용하는 것입니다.

StringBuffer sb = new StringBuffer();
for (int n = 0; n < 10; n++) {
   sb.append("a");

   // This will clear the buffer
   sb.delete(0, sb.length());
}

또 다른 옵션 (비트 클리너)은 setLength (int len) 사용합니다 .

sb.setLength(0);

자세한 정보는 Javadoc 을 참조하십시오 .


15
조금 덜 쓰레기는 루프 내부에 StringBuffer를 선언하는 것입니다.
Mark Elliot

11
아, sb.setLength (0); 루프 내부에서 선언하는 것보다 더 깨끗하고 효율적입니다. 솔루션이 StringBuffer 사용의 성능 이점에 위배됩니다 ...
Jon

6
성능상의 이점은 인스턴스화를 저장하는 것이 아니라 문자열 변경 가능성에서 비롯된 것이라고 생각합니다. 다음은 1e8 반복에 대한 빠른 테스트입니다. 내부 루프 (2.97s) : ideone.com/uyyTL14w , 외부 루프 (2.87s) : ideone.com/F9lgsIxh
Mark Elliot

6
성능에 대해 말하자면 : 다중 스레드 시나리오에서 코드에 액세스하지 않는 한 StringBuffer 대신 StringBuilder를 사용해야합니다. javadoc을 참조하십시오. "가능한 경우이 클래스를 StringBuffer보다 우선적으로 사용하는 것이 좋습니다. 대부분의 구현 ".
Rahel Lüthy

4
외부에서 SB를 만드는 유일한 이점은 내부 (잠재적으로 긴) char []를 잃지 않는 것입니다. 첫 번째 반복자에서 충분히 성장했다면 두 번째 루프는 char []의 크기를 조정할 필요가 없습니다. 그러나 이점을 얻기 위해 "명확한 방법"은 내부 배열의 크기를 보존해야합니다. setLength는이를 수행하지만 SB에서 사용되지 않은 모든 문자를 \ u0000으로 설정하므로 초기 용량이 좋은 새 SB를 만드는 것보다 성능이 떨어집니다. 루프 내부에서 선언하는 것이 좋습니다.
helios

48

를 재사용하는 가장 쉬운 방법 StringBuffer은 방법을 사용하는 것입니다.setLength()

public void setLength(int newLength)

다음과 같은 경우가있을 수 있습니다.

StringBuffer sb = new StringBuffer("HelloWorld");
// after many iterations and manipulations
sb.setLength(0);
// reuse sb

2
@MMahmoud는 코드 예제에서는 읽어야 setLength대신 setlength.
OnaBai

setLength 코드 소스를 볼 때 어떻게 작동 합니까 ( gist.github.com/ebuildy/e91ac6af2ff8a6b1821d18abf2f8c9e1 ) 여기서 카운트는 항상 newLength (0)보다 니까?
Thomas Decaux 2018

20

두 가지 옵션이 있습니다.

사용 :

sb.setLength(0);  // It will just discard the previous data, which will be garbage collected later.  

또는 다음을 사용하십시오.

sb.delete(0, sb.length());  // A bit slower as it is used to delete sub sequence.  

노트

루프 내에서 StringBuffer또는 StringBuilder객체를 선언하지 마십시오. 그렇지 않으면 반복 할 때마다 새 객체가 생성됩니다. 개체를 만들려면 시스템 리소스와 공간이 필요하며 시간도 걸립니다. 따라서 장기적으로 가능하면 루프 내에서 선언하지 마십시오.



5

각 반복마다 새 StringBuffer(또는 더 나은 StringBuilder)를 만드는 것이 좋습니다 . 성능 차이는 정말 미미하지만 코드는 더 짧고 간단합니다.


2
이러한 성능 차이에 대한 증거가 있으면 공유하십시오. (I 자바 주로 사용되는 경우도의 통계를보고 기뻐하고 있습니다 "대부분"의 어느 정의에서.)
엘리 Acherkan

1
할당 (자바의 새 키워드)이 동일한 객체의 일부 필드를 변경하는 것보다 더 비싸다는 것은 잘 알려져 있습니다. 대체 할 수있는 "대부분"의 경우, 모두 Java를 사용하는 15 억 개 이상의 Android 기기가 있습니다.
Louis CAD

1
어떤 경우에는 코드 가독성이 성능보다 더 중요하다는 데 동의하지만이 경우 코드 한 줄에 불과합니다! 그리고 할당 및 객체 생성과 함께 가비지 수집이 전혀 수행하지 않는 것보다 더 비싸다는 것을 증명하는 벤치 마크를 실행할 수 있습니다. 우리가 루프에 있기 때문에 관련성 이상입니다.
Louis CAD

1
나는 또한 Knuth의 견해를 구독했지만 그의 견해가 항상 사실은 아닙니다. 잠재적으로 CPU 사이클과 메모리를 얻기 위해 한 줄만 추가하는 것은 절대로 악의가 아닙니다. 당신은 너무 똑바로 생각하고 있습니다. 루프는 일반적으로 여러 번 반복됩니다. 루프는 수천 번 반복 될 수 있으며 신중하게 최적화하지 않으면 모바일 (및 서버 또는 컴퓨터)에서 귀중한 메가 바이트를 먹을 수 있습니다.
Louis CAD

1
나는 우리 둘 다 우리의 관점을 충분히 명확하게 언급했다고 생각하며, 더 이상의 논의는이 코멘트 섹션에 도움이되지 않을 것이라고 생각합니다. 내 답변이 잘못되었거나 오해의 소지가 있거나 불완전하다고 생각되면 귀하 또는 누구든지 편집 및 / 또는 반대 투표를 할 수 있습니다.
Eli Acherkan 2015

5
public void clear(StringBuilder s) {
    s.setLength(0);
}

용법:

StringBuilder v = new StringBuilder();
clear(v);

가독성을 위해 이것이 최선의 해결책이라고 생각합니다.


2

이미 좋은 대답입니다. StringBuffer 및 StringBuild 성능 차이에 대한 벤치 마크 결과를 추가하면 루프에서 새 인스턴스를 사용하거나 루프에서 setLength (0)을 사용합니다.

요약 : 큰 루프에서

  • StringBuilder는 StringBuffer보다 훨씬 빠릅니다.
  • 루프에서 새 StringBuilder 인스턴스를 만드는 것은 setLength (0)과 차이가 없습니다. (setLength (0)은 새 인스턴스를 만드는 것보다 매우 작은 이점이 있습니다.)
  • StringBuffer는 루프에서 새 인스턴스를 생성하여 StringBuilder보다 느립니다.
  • StringBuffer의 setLength (0)은 루프에서 새 인스턴스를 만드는 것보다 매우 느립니다.

매우 간단한 벤치 마크 (수동으로 코드를 변경하고 다른 테스트를 수행함) :

public class StringBuilderSpeed {
public static final char ch[] = new char[]{'a','b','c','d','e','f','g','h','i'};

public static void main(String a[]){
    int loopTime = 99999999;
    long startTime = System.currentTimeMillis();
    StringBuilder sb = new StringBuilder();
    for(int i = 0 ; i < loopTime; i++){
        for(char c : ch){
            sb.append(c);
        }
        sb.setLength(0);
    }
    long endTime = System.currentTimeMillis();
    System.out.println("Time cost: " + (endTime - startTime));
}

}

루프의 새 StringBuilder 인스턴스 : 시간 비용 : 3693, 3862, 3624, 3742

StringBuilder setLength : 시간 비용 : 3465, 3421, 3557, 3408

루프의 새 StringBuffer 인스턴스 : 시간 비용 : 8327, 8324, 8284

StringBuffer setLength 시간 비용 : 22878, 23017, 22894

다시 StringBuilder setLength는 내 labtop이 StringBuffer setLength에 대해 그렇게 오래 사용하는 데 문제가 있는지 확인합니다. :-) 시간 비용 : 3448


0
StringBuffer sb = new SringBuffer();
// do something wiht it
sb = new StringBuffer();

이 코드가 더 빠르다고 생각합니다.


3
성능 문제가 있습니다. 매 반복마다 새 객체를 생성합니다.
Aditya Singh

@AdityaSingh 완벽하게 합리적인 접근 방식입니다. 증거없이 성능 문제를 가정하지 마십시오.
shmosel

무슨 일이 일어나고 있는지에 대한 이해를 바탕으로 사물을 가정하는 것이 지능의 기초입니다.
rghome
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.