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


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.