문자열 연결: concat() 대 &&&;+&&; 연산자

문자열 a와 b를 가정합니다:

a += b
a = a.concat(b)

내부적으로는 같은 것일까요?

다음은 참조용으로 디컴파일된 컨캣입니다. '+' 연산자도 디컴파일하여 그 기능을 확인할 수 있으면 좋겠습니다.

public String concat(String s) {

    int i = s.length();
    if (i == 0) {
        return this;
    }
    else {
        char ac[] = new char[count + i];
        getChars(0, count, ac, 0);
        s.getChars(0, i, ac, count);
        return new String(0, count + i, ac);
    }
}
질문에 대한 의견 (4)
해결책

아니, 꼭 그런 것만은 아닙니다.

첫째, there& # 39 의 근소한 차이로 시맨틱스를. 만약 'a' 는 'null', 'a' a+ '하지만' 다음 '앨콩카트 던지는 누얼포인터렉세페시옹 (b) = b' 는 원래 값인 것처럼 'a' 치료 'null'. 또 '만' 방법을 사용할 수 있는 동안 concat () '+' 는 'String' 값을 자동으로 연산자입니다 변환하십시오 문자열으로 인수 (toString () '' 방법을 사용하여 객체에는). 따라서 'concat ()' 이 어떤 방식이 더 엄격한 받아들입니다.

'= a + b 클래스에 여바바 후드 아래에 쓰기 위해 간단한.'

public class Concat {
    String cat(String a, String b) {
        a += b;
        return a;
    }
}

이제 자바프 - 'c' 로 분해 (Sun JDK 에 포함). 다음과 같은 열거합니다 볼 수 있습니다.

java.lang.String cat(java.lang.String, java.lang.String);
  Code:
   0:   new     #2; //class java/lang/StringBuilder
   3:   dup
   4:   invokespecial   #3; //Method java/lang/StringBuilder."":()V
   7:   aload_1
   8:   invokevirtual   #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   11:  aload_2
   12:  invokevirtual   #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   15:  invokevirtual   #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/    String;
   18:  astore_1
   19:  aload_1
   20:  areturn

따라서 '= a + b' 는 같습니다

a = new StringBuilder()
    .append(a)
    .append(b)
    .toString();

Concat '방법' 이 더 빠를 것이다. 그러나 이 방법은 더욱 문장열 스트라이베이더 '승' 최소한 성능 면에서.

'소스 코드' 와 '문자열이어야 스트라이베이더' (및 그 패키지 pbs. (base class) 를 사용할 수 있는 세르히오치프 of the sun 에서 jdk. 보시다시피 틀렸다니까 구축에 챨 어레이입니다 (크기조정 필요한 경우) 를 만들 때 던진 후 거두어 최종 'String'. 실제 메모리 할당은 의외로 빨리 찾아온다.

  • Update:* 파블 아담 스키 등 유라유라테이코쿠, 성능 변경되었습니까 더 최근에 하스팟. '코드' 가 있지만 여전히 바이트코드 컴파일러 자바스 똑같이 입으면. 본문 전체를 완전히 단순한 테스트를 실패할 의 코드는 던져진다. 합산 '코드' 가 아닌 '스테링스하시코드') '은' 시스템.이덴티티아시코드 스트라이버퍼 근소한 우위를 확보할 수 있습니다. 변경될 수 있습니다 다음 업데이트 때 사용하는 경우, 또는 다른 JVM 은 릴리즈됨. [@Lukaseder] 에서 1, 바뀌엇어요 하스팟 JVM 의 내장.
해설 (11)

[니야즈][1]가 맞지만, 특수 + 연산자는 Java 컴파일러에 의해 더 효율적인 것으로 변환될 수 있다는 점도 주목할 가치가 있습니다. Java에는 스레드에 안전하지 않고 변경 가능한 문자열을 나타내는 StringBuilder 클래스가 있습니다. 여러 문자열 연결을 수행할 때 Java 컴파일러는 다음과 같이 자동으로 변환합니다.

String a = b + c + d;

String a = new StringBuilder(b).append(c).append(d).toString();

로 변환하는 것이 큰 문자열의 경우 훨씬 더 효율적입니다. 제가 알기로는 컨캣 메서드를 사용할 때는 이런 일이 발생하지 않습니다.

그러나 빈 문자열을 기존 문자열에 연결할 때는 concat 메서드가 더 효율적입니다. 이 경우 JVM은 새 String 객체를 생성할 필요가 없으며 기존 객체를 반환하기만 하면 됩니다. 이를 확인하려면

해설 (3)

내가 대신 다음 루프 뿐만 아니라 비슷한 실행했음 @marcio 테스트입니다.

String c = a;
for (long i = 0; i < 100000L; i++) {
    c = c.concat(b); // make sure javac cannot skip the loop
    // using c += b for the alternative
}

내가 던진 스트라이버일드리아펜드 () '에서', 딱 좋은 주옵니다 잘 알려져 있다. 각 시험은 각 10 배, 연파란색은 실행하십시오 100k 담당자 실행하십시오. 결과가 나타납니다.

  • '승' 스트라이베이더 명백하게. 대부분의 경우 0 이 실행되고 있는 시계를 결과: 는 가장 긴 16ms 했다. '-' = a + b (40) 에서 각 실행하십시오 40000ms 정도가 걸린다. '-' 만 单捞磐啊 concat (10) 당 10000ms 실행하십시오.

39, 내가 haven& 디 컴파일 또는 내부 정보를 볼 수 없는 클래스 a + b '투데이' 의심이 통해 이를 실행하십시오 프로필러 않습니다만, 대부분의 시간 동안 스트라이베이더 의 새로운 개체를 만드는 '=' 다음 '다시' 문자열 변환.

해설 (3)

다음은 가장 대답 (2008년). 그 시간에 따라 변하는 것을 보입니다. 내 주위에 있는 것을 알 수 있는 '+' 는 Java 최신값 벤치마크 브라운아저씨의 제마흐 2 배나 빠른 속도로 concat '8'.

내 벤치마트:

@Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)
public class StringConcatenation {

    @org.openjdk.jmh.annotations.State(Scope.Thread)
    public static class State2 {
        public String a = "abc";
        public String b = "xyz";
    }

    @org.openjdk.jmh.annotations.State(Scope.Thread)
    public static class State3 {
        public String a = "abc";
        public String b = "xyz";
        public String c = "123";
    }

    @org.openjdk.jmh.annotations.State(Scope.Thread)
    public static class State4 {
        public String a = "abc";
        public String b = "xyz";
        public String c = "123";
        public String d = "!@#";
    }

    @Benchmark
    public void plus_2(State2 state, Blackhole blackhole) {
        blackhole.consume(state.a+state.b);
    }

    @Benchmark
    public void plus_3(State3 state, Blackhole blackhole) {
        blackhole.consume(state.a+state.b+state.c);
    }

    @Benchmark
    public void plus_4(State4 state, Blackhole blackhole) {
        blackhole.consume(state.a+state.b+state.c+state.d);
    }

    @Benchmark
    public void stringbuilder_2(State2 state, Blackhole blackhole) {
        blackhole.consume(new StringBuilder().append(state.a).append(state.b).toString());
    }

    @Benchmark
    public void stringbuilder_3(State3 state, Blackhole blackhole) {
        blackhole.consume(new StringBuilder().append(state.a).append(state.b).append(state.c).toString());
    }

    @Benchmark
    public void stringbuilder_4(State4 state, Blackhole blackhole) {
        blackhole.consume(new StringBuilder().append(state.a).append(state.b).append(state.c).append(state.d).toString());
    }

    @Benchmark
    public void concat_2(State2 state, Blackhole blackhole) {
        blackhole.consume(state.a.concat(state.b));
    }

    @Benchmark
    public void concat_3(State3 state, Blackhole blackhole) {
        blackhole.consume(state.a.concat(state.b.concat(state.c)));
    }

    @Benchmark
    public void concat_4(State4 state, Blackhole blackhole) {
        blackhole.consume(state.a.concat(state.b.concat(state.c.concat(state.d))));
    }
}

결과:

Benchmark                             Mode  Cnt         Score         Error  Units
StringConcatenation.concat_2         thrpt   50  24908871.258 ± 1011269.986  ops/s
StringConcatenation.concat_3         thrpt   50  14228193.918 ±  466892.616  ops/s
StringConcatenation.concat_4         thrpt   50   9845069.776 ±  350532.591  ops/s
StringConcatenation.plus_2           thrpt   50  38999662.292 ± 8107397.316  ops/s
StringConcatenation.plus_3           thrpt   50  34985722.222 ± 5442660.250  ops/s
StringConcatenation.plus_4           thrpt   50  31910376.337 ± 2861001.162  ops/s
StringConcatenation.stringbuilder_2  thrpt   50  40472888.230 ± 9011210.632  ops/s
StringConcatenation.stringbuilder_3  thrpt   50  33902151.616 ± 5449026.680  ops/s
StringConcatenation.stringbuilder_4  thrpt   50  29220479.267 ± 3435315.681  ops/s
해설 (1)

톰 올바른지 + 연산자 있는 것이 무엇인지 정확히 설명하는 않습니다. '임시' 을 (를) '및 마감, 부품, 첨부됩니다 e-lab 은 스트라이베이더 toString ()'.

그러나 지금까지 모든 답을 효과가 하스팟 런타임용으로 개발하십시오 최적화 외면당하고 있다. 특히 이러한 임시 작업은 보다 효율적인 기계어 실행 시 일반 패턴과 대체되었는지 평가받고 있다.

@marcio: # 39, ve you& 만든 마이크로 벤치마트. # 39 의 현대적 JVM& 이 올바르지 프로필링하려면 운행에서어떠한 코드.

그 이유는 런타임 최적화 문제는 이러한 많은 차이가 있다 하더라도 한 번 더 하스팟 객체 생성 등 코드 - - 완전히 다른 것입니다. 확실하게 알 수 있는 유일한 방법은,,) 는 &lt 프로필링 코드에 i&gt situ&lt /i&gt.

마지막으로, 이 모든 방법을 실제로 매우 빠르다. 이렇게 될 경우 아직 최적화합니다. 코드가 있을 경우 그 문자열을 연결합니다 많이 방법은 아마도 알고리즘을 선택할 수 있는 최대 속도 아무런 상관이 없고 대신 you& # 39, re 연산자를 사용하여!

해설 (1)

몇 가지 간단한 테스트를 어때? 사용되는 코드는 아래와 같습니다.

long start = System.currentTimeMillis();

String a = "a";

String b = "b";

for (int i = 0; i < 10000000; i++) { //ten million times
     String c = a.concat(b);
}

long end = System.currentTimeMillis();

System.out.println(end - start);
  • 이 ',' 에서, a + b&quot &quot 버전 실행됨을 2500ms . 이 '-' 1200ms 앨콩카트 (b) 에서 처형되었다.

여러 차례 테스트되었습니다. Concat () '이' 가 버전 엑서큐션 반단면 시간이 있는 것으로 나타났다.

그 때문에 항상 새로운 방법을 concat () '이 나를 놀라게 했다' 는 문자열 (String (결과) ',' new it 가 &quot ". # 39 의 it& 것은 널리 알려진:

String a = new String("a") // more than 20 times slower than String a = "a"

왜 wasn& # 39 에서 작성, 컴파일러, a + b&quot 구체화하십시오 최적화합니다 &quot 수 없다. 그 결과 알고 항상 동일한 코드를 문자열? 피할 수 있다는 점에서 새로운 구체화하십시오 계시노라

39 위에 기술서임을 don& 경우, t believe the test for your self.

해설 (0)

기본적으로 두 가지 중요한 차이점을 + '와' concat 메서드입니다.

      • 방법을 사용하는 경우 연결 될 수 있는 동안 문장열 이벤트여야만 concat 그런 경우 연결 문자열을 모든 데이터 형식을 통해 작동자 + 수도 있습니다.
  • 더 Example:*

문자열 s = 10 + &quot Hello";;

이 경우 출력입니다 10Hello 합니다.

문자열 s = &quot I";; 구체화하십시오 s1 (am&quot ";) = s.콩카트 이콩카트 이콩카트 (boy&quot ";), (good&quot ";) 시스템지우트리프린틀린 (s1).

위의 경우 두 문장열 제공하기 위해 필수.

  1. 두 번째 및 주요 차이점은 + concat 에로남이네:
  • 사례 1: 예를 들어, 내가 이런 식으로 concat * operator 와 같은 문장열 concat

문자열 s = &quot I";; 구체화하십시오 s1 (am&quot ";) = s.콩카트 이콩카트 이콩카트 (boy&quot ";), (good&quot ";) 시스템지우트리프린틀린 (s1).

이 경우 총 7 명) 에 작성된 객체에는 풀마다 다음과 같습니다.

난 키워봤지 좋은 보이 Iam 야마구드 리엄 굿보이

  • 사례 2:*

지금 난 것 같은 문장열 콩카티나티 통해 작동자 +

S = &quot +&quot am&quot +";;;;; I&quot 문자열이어야 good&quot boy&quot +";; 시스템지우트리프린틀린 (s).

위의 경우 총 5 만 작성된 객체에는 있다.

실제로 그런 유지보수합니다 스트라이버퍼 를 통해 하나님이 콩카티나티 + 동일한 작업을 수행할 수 있는 것처럼 문장열 연산자입니다 클래스용 inet6.0 -

스트라이버퍼 sb = new 스트라이버퍼 (I&quot ";). 스발라펜드 (am&quot ";). 스발라펜드 (good&quot ";). 스발라펜드 (boy&quot ";). 시스템지우트리프린틀린 (sb).

이런 식으로 불과 5 객체에는 생깁니다.

그래서 보세요들 그것은꿈의 기본 차이점 및 + concat 메서드입니다. 경험하십시오:)

해설 (3)

생각해서라도 정의를 & # 39 +& 완성도, 내가 하고 싶은 것을 추가 # 39;; 연산자입니다 [JLS SE8 15.18.1] [1] 에서 볼 수 있다.

&gt. 만약 오직 하나의 피연산자를 표현식에서는 형식은 구체화하십시오 관심용 구체화하십시오 &gt. 변환 (& # 167. 5.1.11) 을 수행한 다른 피연산자 만들기 위해 &gt. 구체화하십시오 런타임에. &gt. &gt. 그 결과 연결 문자열을 string 객체에 대한 참조입니다 &gt. 즉 연결은 두 피연산자를 써줬지 문자 &gt. 이 문자는 오른쪽 왼쪽 피연산자 앞장서니까요 있다. &gt. 피연산자) 에 새로 만들어진 구체화하십시오. &gt. &gt. String 객체가 새로 만든 (& # 167, 12.5) 는 한 표현식에서는 &gt. 상수입니다 표현식에서는 (& # 167, 15.28).

그 다음 구축현 대한 JLS 밝혔습니다.

&gt. 변환 및 연결 실행하십시오 구현 선택할 수 있습니다. &gt. 한 번에 그리곤요 만들지 않도록 중간 취소 &gt. String 객체에. 연속된 문자열이어야 성능을 향상시키는 &gt. 연결, 자바 컴파일러는 클래스 또는 스트라이버퍼 사용할 수 있습니다. &gt. 이와 유사한 방법을 중간 구체화하십시오 개체 수를 줄일 수 있습니다. &gt. 평가를 통해 만들어진 충족되었으며 expression. &gt. &gt. 더 프리미티브 유형, 구축할 수 있는 빼냅니다 최적화합니다 수도 있습니다. &gt. 래퍼 (wrapper) 에서 직접 객체 생성 변환하여 프리미티브 &gt. 맞추기바인딩 string. 유형

그래서 & # 39 를 볼 때, 자바 컴파일러는 클래스 또는 이와 비슷한 방법을 사용할 수 있습니다, 다른 컴파일러에도 스트라이버퍼 reduce& # 39, 다른 바이트 코드 생산할 수 있다.

[1]: http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html # jls-15.18.1

해설 (0)

연산자**는 문자열과 문자열, 문자, 정수, 이중 또는 부동 소수점 데이터 유형 값 사이에서 작동할 수 있습니다. 연결하기 전에 값을 해당 문자열 표현으로 변환하기만 하면 됩니다.

연결 연산자**는 문자열에 대해서만 사용할 수 있습니다. 데이터 유형 호환성을 검사하고 일치하지 않으면 오류를 발생시킵니다.

이 점을 제외하면 제공한 코드도 동일한 작업을 수행합니다.

해설 (0)

그렇지 않다고 생각합니다.

a.concat(b)는 문자열로 구현되며 초기 자바 머신 이후 구현이 크게 변경되지 않았다고 생각합니다. 연산+구현은 자바 버전과 컴파일러에 따라 다릅니다. 현재+는 가능한 한 빠른 연산을 위해 [StringBuffer][1]를 사용하여 구현됩니다. 향후에는 변경될 수도 있습니다. 이전 버전의 Java에서는 문자열에 대한+` 연산이 중간 결과를 생성하기 때문에 훨씬 더 느렸습니다.

나는 +=+를 사용하여 구현되고 비슷하게 최적화되었다고 생각합니다.

해설 (2)

S # 39 를 사용할 때 속도를 줄일 수 있지만, +, concat 사용할 때, 길이 캐시-코어 string& 속도는 더욱 안정적인, 그리고 최고의 옵션은 스트라이베이더 클래스를 사용하여 작업을 하기 위해서는 안정적인 속도용 디스크입니다. diskid iqn.

뭐 이유를 이해할 수 있다. 그러나 완전히 만들기 위한 최선의 방법을 사용하고 있고, 속도는 이보다 긴 문장열 스트라이베이더 덮어쓰기/추가 () () 와 용납될 수 없다.

해설 (1)