모범 사례 / 성능 : StringBuilder.append와 String.concat 혼합


86

모범 사례가 무엇이며 다른 경우에 문자열 리터럴과 변수를 연결하는 이유를 이해하려고합니다. 예를 들어 다음과 같은 코드가 있으면

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

이것이 그렇게하는 방법입니까? 에서 이 게시물에 , 나는 것으로 나타났습니다 +문자열에 운영자가, 모두 StringBuilder의 새로운 인스턴스를 생성 피연산자를 연결 한 후 바로 호출하는 것보다 더 많은 작업처럼 보이는 문자열 변환을 반환 .append(); 그래서 그것이 사실이라면 그것은 의문의 여지가 없습니다. 하지만 String.concat()어떨까요? .append()모든 연결 에 사용 하는 것이 적절 합니까? 또는 변수에 대해서만, 리터럴은 .concat()?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

이러한 상황에 대처하기위한 모범 사례 및 성능에 대한 일반적인 규칙은 무엇입니까? 내 가정이 정확 +하고 실제로 사용해서는 안됩니까?


나는 기본적으로 당신이 그것을 가지고 있다고 생각합니다. String + "정말 사용해서는 안된다"는 의견이 다릅니다. 요점은 당신이 결과를 이해한다는 것입니다
ControlAltDel

답변:


184

+ 운영자

String s = s1 + s2

뒤에서 이것은 다음으로 번역됩니다.

String s = new StringBuilder(s1).append(s2).toString();

s1 + s2여기에 추가 작업이 얼마나 추가되는지 상상해보십시오 .

stringBuilder.append(s1 + s2)

대신에:

stringBuilder.append(s1).append(s2)

여러 문자열 +

다음 사항에 유의할 가치가 있습니다.

String s = s1 + s2 + s3 + ... +sN

다음으로 번역됩니다.

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

String생성 char[]모두 들어갈 수 배열 s1s2. 복사 s1s2이 새로운 배열에 내용을 표시합니다. 실제로 +운영자 보다 적은 작업이 필요합니다 .

StringBuilder.append()

char[]필요할 때 확장 되는 내부 어레이를 유지 합니다. char[]내부가 충분히 크면 추가 로 생성 되지 않습니다 .

stringBuilder.append(s1.concat(s2))

s1.concat(s2)추가 char[]배열과 복사본을 s1만들고 s2내부에 새 배열 내용을 복사 하기 때문에 성능이 저하 StringBuilder char[]됩니다.

append(), 항상 사용하고 원시 문자열을 추가 해야합니다 (첫 번째 코드 스 니펫이 정확함).


귀하의 도움과 자세한 설명에 감사드립니다. 그것이 내가 정말로 필요로하는 것입니다.
Nick Rolando 2012

12
최신 버전의 컴파일러는 + 연산자를 문자열 작성기에 자동으로 최적화하지만 이전 버전은 그렇지 않으므로 반드시 그렇게 될 것이라고 가정하는 것이 좋은 것은 아닙니다. 이 전체 토론에서 무시되는 매우 중요한 주제가 있는데, 이는 실제로 문자열 풀인 StringBuilder의 주요 목적 중 하나입니다. 문자열 작성기를 사용하면 모든 것을 char []로 유지하고 컴파일러 최적화 이전에 + 연산자처럼 중간 문자열을 만들지 않습니다 (단지 연결을 수행하는 데 사용됨). concat을 사용하면 캐시되지만 사용되지 않는 중간 String 객체가 생성됩니다.
LINEMAN78

따라서 여러 다른 문자열에서 일회성 명령문 (메서드에 여러 명령문이 아닌) 연결을 수행하는 경우 . 기본적으로 똑같은 일을 할 것이기 때문에 이번 한 번 연결 +을 만드는 대신 String 객체 에서 사용 하는 것이 좋습니다 StringBuilder.
Nick Rolando 2012

1
그리고 문자 만 연결하려는 경우 .append ( "\ n") 대신 .append ( '\ n')를 사용하는 것이 더 낫습니까? 캐릭터가 기본 유형이고 문자열이 객체이기 때문에?
vrwim 2013 년

3
효과적인 Java 2nd edition : 문자열 연결 연산자를 반복적으로 사용하여 n 개의 문자열을 연결하려면 n에서 시간 2 차가 필요합니다. 그래서 여전히 관련이 있습니까?
gkiko 2015 년

16

컴파일러는 + 연결을 최적화합니다.

그래서

int a = 1;
String s = "Hello " + a;

로 변형됩니다

new StringBuilder().append("Hello ").append(1).toString();

+ 연산자를 사용해야하는 이유를 설명 하는 훌륭한 주제가 여기에 있습니다 .


3
컴파일러는 String s = "Hello World";리터럴을 사용하기 때문에 실제로이를 최적화합니다 .
ColinD

@ColinD : +1. 방금 내 스 니펫을 수정했습니다.

3

최적화는 컴파일러에 의해 자동으로 수행됩니다.

Java2 컴파일러는 다음을 자동으로 변환합니다.

String s = s1 + s2; 

...에

String s = (new StringBuffer()).append(s1).append(s2).toString();

Oracles 웹 사이트 의 Java Best Practices 에서 바로 가져옵니다 .


2

항상 append.

concat새 문자열을 만들어 제 +생각 과 비슷 합니다.

두 개의 최종 문자열을 concat사용하거나 사용 +하면 JVM이 최적화를 수행 할 수 있으므로이 경우 추가하는 것과 동일합니다.


1

정확히 두 개의 문자열을 연결하는 경우 String.concat을 사용합니다 (두 문자열에 맞는 새 문자 배열을 만들고 두 문자열의 문자 배열을 여기에 복사하여 새 문자열을 만듭니다).

여러 문자열을 한 줄에 연결하는 경우 + 또는 StringBuilder.append를 사용하면 컴파일러가 +를 StringBuilder.append로 변환하므로 중요하지 않습니다. 필요에 따라 증가하는 하나의 char 배열을 유지하기 때문에 여러 문자열에 유용합니다.

여러 줄에 걸쳐 여러 문자열을 연결하는 경우 하나의 StringBuilder를 만들고 append-method를 사용합니다. 결국 StringBuilder에 String을 추가하면 .toString () 메서드를 사용하여 String을 만듭니다. 여러 줄로 연결하는 경우 두 번째 방법이 두 번째 방법보다 빠릅니다. 두 번째 방법은 각 행에 새 StringBuilder를 만들고 문자열을 추가 한 다음 다시 String으로 캐스팅하는 반면 세 번째 방법은 전체에 대해 하나의 StringBuilder 만 사용하기 때문입니다.


0

+연산자 사용 이 모범 사례이며 간단하고 읽기 쉽습니다.

Java 언어는 문자열 연결 연산자 (+) 및 다른 객체를 문자열로 변환하는 특수 지원을 제공합니다. 문자열 연결은 StringBuilder (또는 StringBuffer) 클래스와 그 append 메소드를 통해 구현됩니다.

공식 문서 : https://docs.oracle.com/javase/8/docs/api/java/lang/String.html


0

바이트 코드 수준에서 다르지 않으며 우리는 거기에서 효율성을 손상시키지 않습니다. 바이트 코드 수준을 실행하는 경우 append를 호출하여 +에 대한 비 인라인 연산자 오버로딩 방법을 거쳐야합니다. 그런 다음 어셈블리 언어 수준에서 (Java는 C로 작성되고 C는 어셈블리와 유사한 어셈블리를 생성합니다. 스택에 + 메서드 호출을 저장하기위한 추가 레지스터 호출이 있으며 추가 푸시가 있습니다. 실제로 크로스 컴파일러는 + 연산자를 최적화 할 수 있습니다. 전화,이 경우 효율성에 차이가 없습니다.)

가독성을 높이는 한 가지 방법을 사용하는 것이 좋습니다. :)


0

개인적 Strings.format()으로 읽기 쉽고 읽기 쉬운 한 줄 문자열 포맷터 를 선호합니다 .

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F

0

모든 답변은 매우 훌륭하고 설명 적입니다. 그러나 Guava Joiner, Streams, String.format 등과 같은 다른 문자열 연결 기술에 대한 탐색도 도움이 될 것이라고 생각했습니다.

각 연결 기술의 성능에 대한 자세한 내용은 java-string-concatenation-which-way-is-best .

간단히 말해서 연결 성능은 아니오에 따라 다릅니다. 연결할 문자열 수. 예를 들어 1-10 개의 문자열을 연결하려면 이러한 기술이 가장 적합합니다 (StringBuilder, StringBuffer 및 Plus 연산자). 그리고 100 개의 문자열을 연결하기 위해-Guava Joiner, apache의 stringsUtils 라이브러리도 훌륭하게 작동합니다.

위의 블로그를 참조하십시오. 성능 효율성을 매우 잘 설명합니다.

감사.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.