Java의 toString ()에서 StringBuilder 대 문자열 연결
toString()
아래 두 가지 구현을 고려할 때 어느 것이 선호되는지 :
public String toString(){
return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}
또는
public String toString(){
StringBuilder sb = new StringBuilder(100);
return sb.append("{a:").append(a)
.append(", b:").append(b)
.append(", c:").append(c)
.append("}")
.toString();
}
?
더 중요한 것은 속성이 3 개뿐이라면 차이가 없을 수도 있지만 어떤 지점에서 +
concat에서 StringBuilder
?
버전 1이 더 짧고 컴파일러가 실제로 버전 2로 전환하므로 성능 차이가 전혀 없기 때문에 선호 됩니다 .
더 중요한 것은 속성이 3 개뿐이라는 점을 감안할 때 차이가 없을 수도 있지만 어느 시점에서 연결에서 빌더로 전환합니까?
루프에서 연결하는 지점에서 일반적으로 컴파일러 StringBuilder
가 자체적으로 대체 할 수없는 경우 입니다.
핵심은 단일 연결을 모두 한곳에 작성하는지 또는 시간이 지남에 따라 누적하는지 여부입니다.
당신이 준 예의 경우 StringBuilder를 명시 적으로 사용하는 것은 의미가 없습니다. (첫 번째 경우 컴파일 된 코드를보십시오.)
그러나 예를 들어 루프 내부에서 문자열을 작성하는 경우 StringBuilder를 사용하십시오.
명확히하기 위해 hugeArray에 수천 개의 문자열이 포함되어 있다고 가정하면 다음과 같이 코드를 작성합니다.
...
String result = "";
for (String s : hugeArray) {
result = result + s;
}
다음과 비교할 때 매우 시간과 메모리를 낭비합니다.
...
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
sb.append(s);
}
String result = sb.toString();
나는 선호한다:
String.format( "{a: %s, b: %s, c: %s}", a, b, c );
... 짧고 읽을 수 있기 때문입니다.
나는 것 없는 당신은 매우 높은 반복 횟수와 루프 내부에 그것을 사용하지 않는 한 속도에 대해이 작업을 최적화 하고 성능 차이를 측정했다.
많은 매개 변수를 출력해야하는 경우이 양식이 혼란 스러울 수 있다는 데 동의합니다 (댓글 중 하나가 말한 것처럼). 이 경우 더 읽기 쉬운 형식으로 전환하고 (아마도 apache-commons의 ToStringBuilder 사용 -matt b의 답변에서 가져옴) 성능을 다시 무시합니다.
대부분의 경우 두 접근 방식의 실제 차이는 보이지 않지만 다음과 같은 최악의 시나리오를 구성하는 것은 쉽습니다.
public class Main
{
public static void main(String[] args)
{
long now = System.currentTimeMillis();
slow();
System.out.println("slow elapsed " + (System.currentTimeMillis() - now) + " ms");
now = System.currentTimeMillis();
fast();
System.out.println("fast elapsed " + (System.currentTimeMillis() - now) + " ms");
}
private static void fast()
{
StringBuilder s = new StringBuilder();
for(int i=0;i<100000;i++)
s.append("*");
}
private static void slow()
{
String s = "";
for(int i=0;i<100000;i++)
s+="*";
}
}
출력은 다음과 같습니다.
slow elapsed 11741 ms
fast elapsed 7 ms
문제는 문자열에 + = 추가하면 새 문자열이 재구성되므로 문자열 길이 (둘 다 합산)에 비례하는 비용이 든다는 것입니다.
그래서-귀하의 질문에 :
두 번째 접근 방식은 더 빠르지 만 읽기가 어렵고 유지 관리가 더 어렵습니다. 내가 말했듯이, 귀하의 특정 경우에는 아마도 차이를 보지 못할 것입니다.
또한 Append 또는 +를 사용할지 여부에 대해 상사와 충돌했습니다. Append를 사용함에 따라 (새 개체가 생성 될 때마다 말하는 것처럼 여전히 알 수 없습니다). 그래서 R & D를 좀 해보고 싶었는데, Michael Borgwardt의 설명을 좋아하지만 누군가가 정말로 알아야 할 경우 설명을 보여주고 싶었습니다.
/**
*
* @author Perilbrain
*/
public class Appc {
public Appc() {
String x = "no name";
x += "I have Added a name" + "We May need few more names" + Appc.this;
x.concat(x);
// x+=x.toString(); --It creates new StringBuilder object before concatenation so avoid if possible
//System.out.println(x);
}
public void Sb() {
StringBuilder sbb = new StringBuilder("no name");
sbb.append("I have Added a name");
sbb.append("We May need few more names");
sbb.append(Appc.this);
sbb.append(sbb.toString());
// System.out.println(sbb.toString());
}
}
위 클래스의 분해는 다음과 같이 나옵니다.
.method public <init>()V //public Appc()
.limit stack 2
.limit locals 2
met001_begin: ; DATA XREF: met001_slot000i
.line 12
aload_0 ; met001_slot000
invokespecial java/lang/Object.<init>()V
.line 13
ldc "no name"
astore_1 ; met001_slot001
.line 14
met001_7: ; DATA XREF: met001_slot001i
new java/lang/StringBuilder //1st object of SB
dup
invokespecial java/lang/StringBuilder.<init>()V
aload_1 ; met001_slot001
invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
ldc "I have Added a nameWe May need few more names"
invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
aload_0 ; met001_slot000
invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
astore_1 ; met001_slot001
.line 15
aload_1 ; met001_slot001
aload_1 ; met001_slot001
invokevirtual java/lang/String.concat(Ljava/lang/String;)Ljava/lang/Strin\
g;
pop
.line 18
return //no more SB created
met001_end: ; DATA XREF: met001_slot000i ...
; ===========================================================================
;met001_slot000 ; DATA XREF: <init>r ...
.var 0 is this LAppc; from met001_begin to met001_end
;met001_slot001 ; DATA XREF: <init>+6w ...
.var 1 is x Ljava/lang/String; from met001_7 to met001_end
.end method
;44-1=44
; ---------------------------------------------------------------------------
; Segment type: Pure code
.method public Sb()V //public void Sb
.limit stack 3
.limit locals 2
met002_begin: ; DATA XREF: met002_slot000i
.line 21
new java/lang/StringBuilder
dup
ldc "no name"
invokespecial java/lang/StringBuilder.<init>(Ljava/lang/String;)V
astore_1 ; met002_slot001
.line 22
met002_10: ; DATA XREF: met002_slot001i
aload_1 ; met002_slot001
ldc "I have Added a name"
invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
pop
.line 23
aload_1 ; met002_slot001
ldc "We May need few more names"
invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
pop
.line 24
aload_1 ; met002_slot001
aload_0 ; met002_slot000
invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
pop
.line 25
aload_1 ; met002_slot001
aload_1 ; met002_slot001
invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
pop
.line 28
return
met002_end: ; DATA XREF: met002_slot000i ...
;met002_slot000 ; DATA XREF: Sb+25r
.var 0 is this LAppc; from met002_begin to met002_end
;met002_slot001 ; DATA XREF: Sb+9w ...
.var 1 is sbb Ljava/lang/StringBuilder; from met002_10 to met002_end
.end method
;96-49=48
; ---------------------------------------------------------------------------
위의 두 코드에서 Michael이 옳다는 것을 알 수 있으며 각 경우에 하나의 SB 객체 만 생성됩니다.
Java 1.5부터 "+"및 StringBuilder.append ()를 사용한 간단한 한 줄 연결은 정확히 동일한 바이트 코드를 생성합니다.
따라서 코드 가독성을 위해 "+"를 사용하십시오.
2 가지 예외 :
- 다중 스레드 환경 : StringBuffer
- 루프에서 연결 : StringBuilder / StringBuffer
최신 버전의 Java (1.8)를 사용하여 disassembly ( javap -c
)는 컴파일러에 의해 도입 된 최적화를 보여줍니다. +
또한 sb.append()
매우 유사한 코드를 생성합니다. 그러나 +
for 루프에서 사용 하는 경우 동작을 검사하는 것이 좋습니다 .
for 루프에서 +를 사용하여 문자열 추가
자바:
public String myCatPlus(String[] vals) {
String result = "";
for (String val : vals) {
result = result + val;
}
return result;
}
ByteCode :( for
루프 발췌)
12: iload 5
14: iload 4
16: if_icmpge 51
19: aload_3
20: iload 5
22: aaload
23: astore 6
25: new #3 // class java/lang/StringBuilder
28: dup
29: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
32: aload_2
33: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: aload 6
38: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: astore_2
45: iinc 5, 1
48: goto 12
stringbuilder.append를 사용하여 문자열 추가
자바:
public String myCatSb(String[] vals) {
StringBuilder sb = new StringBuilder();
for(String val : vals) {
sb.append(val);
}
return sb.toString();
}
ByteCdoe :( for
루프 발췌)
17: iload 5
19: iload 4
21: if_icmpge 43
24: aload_3
25: iload 5
27: aaload
28: astore 6
30: aload_2
31: aload 6
33: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: pop
37: iinc 5, 1
40: goto 17
43: aload_2
그래도 약간의 눈부신 차이 가 있습니다. 처음 사용 된 경우에는 for 루프 반복마다 +
new StringBuilder
가 생성되고 생성 된 결과는 toString()
call (29 ~ 41) 을 수행하여 저장됩니다 . 따라서 루프 +
에서 연산자 를 사용하는 동안 실제로 필요하지 않은 중간 문자열을 생성하고 있습니다 for
.
Java 9에서 버전 1은 invokedynamic
호출 로 변환되기 때문에 더 빠릅니다 . 자세한 내용은 JEP-280 에서 확인할 수 있습니다 .
아이디어는 전체 StringBuilder 추가 댄스를 java.lang.invoke.StringConcatFactory에 대한 간단한 invokedynamic 호출로 대체하는 것입니다.이 호출은 연결이 필요한 값을 허용합니다.
Apache Commons-Lang에는 사용하기 매우 쉬운 ToStringBuilder 클래스가 있습니다. 그것은 당신이 원하는 toString의 모양을 지정하는 것뿐만 아니라 append-logic을 처리하는 좋은 일을합니다.
public void toString() {
ToStringBuilder tsb = new ToStringBuilder(this);
tsb.append("a", a);
tsb.append("b", b)
return tsb.toString();
}
다음과 같은 출력을 반환합니다 com.blah.YourClass@abc1321f[a=whatever, b=foo]
.
또는 체이닝을 사용하여보다 압축 된 형태로 :
public void toString() {
return new ToStringBuilder(this).append("a", a).append("b", b").toString();
}
또는 리플렉션을 사용하여 클래스의 모든 필드를 포함하려는 경우 :
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
원하는 경우 ToString의 스타일을 사용자 지정할 수도 있습니다.
성능상의 이유로 +=
( String
연결) 사용은 권장되지 않습니다. 그 이유는 다음과 같습니다. Java String
는 변경 불가능하며, 새 연결이 수행 될 때마다 새 항목 String
이 생성됩니다 ( 새 항목 은 이미 String 풀에있는 이전 지문과 다른 지문을 가짐 ). 새로운 문자열을 생성하면 GC에 부담을주고 프로그램 속도가 느려집니다. 객체 생성은 비용이 많이 듭니다.
아래 코드는 동시에 더 실용적이고 명확해야합니다.
public static void main(String[] args)
{
// warming up
for(int i = 0; i < 100; i++)
RandomStringUtils.randomAlphanumeric(1024);
final StringBuilder appender = new StringBuilder();
for(int i = 0; i < 100; i++)
appender.append(RandomStringUtils.randomAlphanumeric(i));
// testing
for(int i = 1; i <= 10000; i*=10)
test(i);
}
public static void test(final int howMany)
{
List<String> samples = new ArrayList<>(howMany);
for(int i = 0; i < howMany; i++)
samples.add(RandomStringUtils.randomAlphabetic(128));
final StringBuilder builder = new StringBuilder();
long start = System.nanoTime();
for(String sample: samples)
builder.append(sample);
builder.toString();
long elapsed = System.nanoTime() - start;
System.out.printf("builder - %d - elapsed: %dus\n", howMany, elapsed / 1000);
String accumulator = "";
start = System.nanoTime();
for(String sample: samples)
accumulator += sample;
elapsed = System.nanoTime() - start;
System.out.printf("concatenation - %d - elapsed: %dus\n", howMany, elapsed / (int) 1e3);
start = System.nanoTime();
String newOne = null;
for(String sample: samples)
newOne = new String(sample);
elapsed = System.nanoTime() - start;
System.out.printf("creation - %d - elapsed: %dus\n\n", howMany, elapsed / 1000);
}
실행 결과는 다음과 같습니다.
builder - 1 - elapsed: 132us
concatenation - 1 - elapsed: 4us
creation - 1 - elapsed: 5us
builder - 10 - elapsed: 9us
concatenation - 10 - elapsed: 26us
creation - 10 - elapsed: 5us
builder - 100 - elapsed: 77us
concatenation - 100 - elapsed: 1669us
creation - 100 - elapsed: 43us
builder - 1000 - elapsed: 511us
concatenation - 1000 - elapsed: 111504us
creation - 1000 - elapsed: 282us
builder - 10000 - elapsed: 3364us
concatenation - 10000 - elapsed: 5709793us
creation - 10000 - elapsed: 972us
1 개의 연결에 대한 결과를 고려하지 않고 (JIT가 아직 작업을 수행하지 않음) 10 개의 연결에 대해서도 성능 패널티가 관련됩니다. 수천 개의 연결의 경우 차이가 큽니다.
이 매우 빠른 실험에서 배운 교훈 (위의 코드로 쉽게 재현 가능) : +=
몇 개의 연결이 필요한 매우 기본적인 경우에도를 사용하여 문자열을 함께 연결 하지 마십시오 (말했듯이 새 문자열을 만드는 것은 어쨌든 비용이 많이 들고 GC).
toString 메서드를 가능한 한 읽기 쉽게 만드십시오!
내 책에서 이것에 대한 유일한 예외 는 그것이 상당한 자원을 소비한다는 것을 나에게 증명할 수 있다면 :) (예, 이것은 프로파일 링을 의미합니다)
또한 Java 5 컴파일러는 이전 버전의 Java에서 사용 된 "StringBuffer"방식보다 더 빠른 코드를 생성합니다. "+"를 사용하면이 기능과 향후 개선 사항이 무료로 제공됩니다.
현재 컴파일러에서 StringBuilder 사용이 여전히 필요한지에 대한 논쟁이있는 것 같습니다. 그래서 2 센트의 경험을 줄 것이라고 생각했습니다.
JDBC
10k 레코드 의 결과 집합이 있습니다 (예, 모두 하나의 일괄 처리에 필요합니다.) + 연산자를 사용하면 컴퓨터에서 Java 1.8
. stringBuilder.append("")
동일한 쿼리에 대해 사용하는 데 1 초도 걸리지 않습니다.
그래서 그 차이는 엄청납니다. 루프 내부 StringBuilder
는 훨씬 빠릅니다.
아래 예를 참조하십시오.
//java8
static void main(String[] args) {
case1();//str.concat
case2();//+=
case3();//StringBuilder
}
static void case1() {
List<Long> savedTimes = new ArrayList();
long startTimeAll = System.currentTimeMillis();
String str = "";
for (int i = 0; i < MAX_ITERATIONS; i++) {
long startTime = System.currentTimeMillis();
str = str.concat(UUID.randomUUID()+"---");
saveTime(savedTimes, startTime);
}
System.out.println("Created string of length:"+str.length()+" in "+(System.currentTimeMillis()-startTimeAll)+" ms");
}
static void case2() {
List<Long> savedTimes = new ArrayList();
long startTimeAll = System.currentTimeMillis();
String str = "";
for (int i = 0; i < MAX_ITERATIONS; i++) {
long startTime = System.currentTimeMillis();
str+=UUID.randomUUID()+"---";
saveTime(savedTimes, startTime);
}
System.out.println("Created string of length:"+str.length()+" in "+(System.currentTimeMillis()-startTimeAll)+" ms");
}
static void case3() {
List<Long> savedTimes = new ArrayList();
long startTimeAll = System.currentTimeMillis();
StringBuilder str = new StringBuilder("");
for (int i = 0; i < MAX_ITERATIONS; i++) {
long startTime = System.currentTimeMillis();
str.append(UUID.randomUUID()+"---");
saveTime(savedTimes, startTime);
}
System.out.println("Created string of length:"+str.length()+" in "+(System.currentTimeMillis()-startTimeAll)+" ms");
}
static void saveTime(List<Long> executionTimes, long startTime) {
executionTimes.add(System.currentTimeMillis()-startTime);
if(executionTimes.size()%CALC_AVG_EVERY == 0) {
out.println("average time for "+executionTimes.size()+" concatenations: "+
NumberFormat.getInstance().format(executionTimes.stream().mapToLong(Long::longValue).average().orElseGet(()->0))+
" ms avg");
executionTimes.clear();
}
}
산출:
10000 회씩 연결에 대한 평균 시간 : 0.096 MS는 평균
10,000 회씩 연결 평균 시간 : 0.185 MS는 평균
10,000 회씩 연결 평균 시간 : 0.327 MS는 평균
10,000 회씩 연결 평균 시간 : 0.501 MS는 평균
10,000 회씩 연결 평균 시간 : 0.656 MS는 평균
길이가 만든 문자열을 : 1950000에서 17,745 MS
10000 회씩 연결에 대한 평균 시간 : 0.21 밀리 평균
10000 회씩 연결 평균 시간 : 0.652 MS는 평균
10,000 회씩 연결 평균 시간 : 1.129 MS는 평균
10,000 회씩 연결 평균 시간 : 1.727 MS는 평균
10,000 회씩 연결 평균 시간 : 2.302 MS가 및 평균
만든 길이 문자열 : 1950000 ( 60279ms)
10000 연결에 대한 평균 시간 : 평균 0.002ms
10000 연결에 대한 평균 시간 : 0.002 ms 평균
10000 연결에 대한 평균 시간 : 0.002 ms 평균
10000 연결에 대한 평균 시간 : 0.002 ms 평균
10000 연결에 대한 평균 시간 : 0.002 ms avg
생성 된 문자열 길이 : 1950000 in 100 ms
문자열 길이가 늘어 나면 연결 시간도 늘어납니다.
그것이 StringBuilder
확실히 필요한 곳입니다.
보시다시피 연결 : UUID.randomUUID()+"---"
은 실제로 시간에 영향을주지 않습니다.
추신 : Java에서 StringBuilder를 사용할 때 실제로 이것의 복제 라고 생각하지 않습니다 .
이 질문은 toString()
대부분의 경우 거대한 문자열의 연결을 수행하지 않는 것에 대해 이야기 합니다.
'+'를 사용한 성능 현명한 문자열 연결은 문자열이 Java에서 변경 불가능하기 때문에 완전히 새로운 String 복사본을 만들어야하기 때문에 비용이 많이 듭니다. 이것은 연결이 매우 빈번한 경우에 특히 역할을합니다 (예 : 루프 내부). 다음은 내가 그러한 일을 시도 할 때 내 IDEA가 제안하는 것입니다.
일반적인 규칙:
- 단일 문자열 할당 내에서 문자열 연결을 사용하는 것이 좋습니다.
- 큰 문자 데이터 블록을 만들기 위해 반복하는 경우 StringBuffer로 이동하십시오.
- 문자열에 + =를 사용하는 것은 항상 StringBuffer를 사용하는 것보다 덜 효율적이므로 경고 벨을 울려 야합니다. 그러나 특정 경우에 얻은 최적화는 가독성 문제에 비해 무시할 수있을 것이므로 상식을 사용하십시오.
다음은 이 주제에 대한 Jon Skeet 블로그 입니다.
컬렉션을 반복하고 StringBuilder를 사용하려는 경우 Apache Commons Lang 및 StringUtils.join () (다른 풍미로) 을 확인하고 싶을 수 있습니다 .
성능에 관계없이 StringBuilders 및 for 루프를 생성해야하는 시간을 백만 번째로 줄일 수 있습니다 .
성능을 비교하기 위해 네 가지 접근 방식을 비교했습니다. 나는 gc에게 무슨 일이 일어나는지 정확히 모르지만, 나에게 중요한 것은 시간입니다. 여기서 컴파일러는 중요한 요소이며 window8.1 플랫폼에서 jdk1.8.0_45를 사용했습니다.
concatWithPlusOperator = 8
concatWithBuilder = 130
concatWithConcat = 127
concatStringFormat = 3737
concatWithBuilder2 = 46
public class StringConcatenationBenchmark {
private static final int MAX_LOOP_COUNT = 1000000;
public static void main(String[] args) {
int loopCount = 0;
long t1 = System.currentTimeMillis();
while (loopCount < MAX_LOOP_COUNT) {
concatWithPlusOperator();
loopCount++;
}
long t2 = System.currentTimeMillis();
System.out.println("concatWithPlusOperator = " + (t2 - t1));
long t3 = System.currentTimeMillis();
loopCount = 0;
while (loopCount < MAX_LOOP_COUNT) {
concatWithBuilder();
loopCount++;
}
long t4 = System.currentTimeMillis();
System.out.println("concatWithBuilder = " + (t4 - t3));
long t5 = System.currentTimeMillis();
loopCount = 0;
while (loopCount < MAX_LOOP_COUNT) {
concatWithConcat();
loopCount++;
}
long t6 = System.currentTimeMillis();
System.out.println("concatWithConcat = " + (t6 - t5));
long t7 = System.currentTimeMillis();
loopCount = 0;
while (loopCount < MAX_LOOP_COUNT) {
concatStringFormat();
loopCount++;
}
long t8 = System.currentTimeMillis();
System.out.println("concatStringFormat = " + (t8 - t7));
long t9 = System.currentTimeMillis();
loopCount = 0;
while (loopCount < MAX_LOOP_COUNT) {
concatWithBuilder2();
loopCount++;
}
long t10 = System.currentTimeMillis();
System.out.println("concatWithBuilder2 = " + (t10 - t9));
}
private static void concatStringFormat() {
String s = String.format("%s %s %s %s ", "String", "String", "String", "String");
}
private static void concatWithConcat() {
String s = "String".concat("String").concat("String").concat("String");
}
private static void concatWithBuilder() {
StringBuilder builder=new StringBuilder("String");
builder.append("String").append("String").append("String");
String s = builder.toString();
}
private static void concatWithBuilder2() {
String s = new StringBuilder("String").append("String").append("String").append("String").toString();
}
private static void concatWithPlusOperator() {
String s = "String" + "String" + "String" + "String";
}
}
다음은 Java8에서 확인한 내용입니다.
- 문자열 연결 사용
StringBuilder 사용
long time1 = System.currentTimeMillis(); usingStringConcatenation(100000); System.out.println("usingStringConcatenation " + (System.currentTimeMillis() - time1) + " ms"); time1 = System.currentTimeMillis(); usingStringBuilder(100000); System.out.println("usingStringBuilder " + (System.currentTimeMillis() - time1) + " ms"); private static void usingStringBuilder(int n) { StringBuilder str = new StringBuilder(); for(int i=0;i<n;i++) str.append("myBigString"); } private static void usingStringConcatenation(int n) { String str = ""; for(int i=0;i<n;i++) str+="myBigString"; }
많은 수의 문자열에 문자열 연결을 사용하는 것은 정말 악몽입니다.
usingStringConcatenation 29321 ms
usingStringBuilder 2 ms
StringBuilder 추가 접근 방식을 사용해야한다고 생각합니다. 이유는
String 연결은 매번 새 문자열 객체를 생성하므로 (String은 변경 불가능한 객체이므로) 3 개의 객체를 생성합니다.
문자열 빌더를 사용하면 하나의 개체 만 생성되고 [StringBuilder는 변경 가능] 추가 문자열이 추가됩니다.
내가 선호하는 간단한 문자열의 경우
"string".concat("string").concat("string");
순서대로 문자열을 구성하는 선호되는 방법은 StringBuilder, String # concat (), 오버로드 된 + 연산자를 사용하는 것입니다. StringBuilder는 + 연산자를 사용하면 성능이 크게 저하되는 것처럼 큰 문자열을 작업 할 때 성능이 크게 향상됩니다 (문자열 크기가 증가함에 따라 기하 급수적으로 크게 감소). .concat () 사용의 한 가지 문제점은 NullPointerExceptions를 던질 수 있다는 것입니다.
'development' 카테고리의 다른 글
Android에서 투명한 활동을 어떻게 생성합니까? (0) | 2020.09.28 |
---|---|
JavaScript 앞에 CSS를 포함하라는 권장 사항이 유효하지 않습니까? (0) | 2020.09.28 |
$ scope. $ emit 및 $ scope. $ on 작업 (0) | 2020.09.28 |
값으로 목록 요소를 삭제하는 간단한 방법이 있습니까? (0) | 2020.09.28 |
자바 8 목록 (0) | 2020.09.28 |