JDK 8 의 문자열 맞 춤 법 에 대한 자세 한 설명

머리말
자바 개발 자 들 사이 에서 문자열 의 조합 이 자원 을 차지 하 는 것 은 종종 화제 가 된다.
왜 높 은 자원 을 점용 하 는 지 깊이 토론 합 시다.
자바 에서 문자열 대상 은 가 변 적 이지 않 습 니 다.만 들 면 더 이상 바 꿀 수 없다 는 뜻 입 니 다.그래서 우리 가 문자열 을 맞 출 때 새 문자열 을 만 들 었 습 니 다.오래된 쓰레기 수 거 기 는 표 시 됩 니 다.

만약 우리 가 수백 만 개의 문자열 을 처리 한 후에,우 리 는 수백 만 개의 추가 문자열 을 쓰레기 회수 기 에 의 해 처리 할 것 이다.
대부분의 튜 토리 얼 에 서 는+번호 로 문자열 을 맞 추 면 여러 개의 String 을 생 성하 여 성능 이 떨 어 지 는 것 을 볼 수 있 습 니 다.StringBuffer/stringBuilder 를 사용 하 는 것 을 권장 합 니 다.
근 데 진짜 그런 거 예요?
본 고 는 JDK 8 에서 다음 과 같은 실험 을 했다.

public static void main(String[] args) {
 String result = "";
 result += "some more data";
 System.out.println(result);
 }
javap-c 를 통 해 역 컴 파일 할 수 있 습 니 다:

Code:
 0: aload_0  // Push 'this' on to the stack
 1: invokespecial #1 // Invoke Object class constructor
    // pop 'this' ref from the stack
 4: return  // Return from constructor

 public static void main(java.lang.String[]);
 Code:
 0: ldc  #2 // Load constant #2 on to the stack
 2: astore_1  // Create local var from stack (pop #2)
 3: new  #3 // Push new StringBuilder ref on stack
 6: dup  // Duplicate value on top of the stack
 7: invokespecial #4 // Invoke StringBuilder constructor
    // pop object reference
 10: aload_1  // Push local variable containing #2
 11: invokevirtual #5 // Invoke method StringBuilder.append()
    // pop obj reference + parameter
    // push result (StringBuilder ref)
 14: ldc  #6 // Push "some more data" on the stack
 16: invokevirtual #5 // Invoke StringBuilder.append
    // pop twice, push result
 19: invokevirtual #7 // Invoke StringBuilder.toString:();
 22: astore_1  // Create local var from stack (pop #6)
 23: getstatic #8 // Push value System.out:PrintStream
 26: aload_1  // Push local variable containing #6
 27: invokevirtual #9 // Invoke method PrintStream.println()
    // pop twice (object ref + parameter)
 30: return  // Return void from method
자바 컴 파일 러 가 생 성 된 바이트 코드 를 최적화 시 켜 StringBuilder 를 자동 으로 만 들 고 append 작업 을 하 는 것 을 볼 수 있 습 니 다.
최종 문자열 을 구축 하 는 하위 문자열 은 컴 파일 할 때 이미 알 고 있 기 때문에 이러한 상황 에서 자바 컴 파일 러 는 위 와 같은 최 적 화 를 할 수 있 습 니 다.이러한 최 적 화 는 a static string concatenation optimization 이 라 고 하 는데 JDK 5 때 부터 사용 되 었 습 니 다.
그러면 JDK 5 이후 에 우 리 는 더 이상 StringBuilder 를 수 동 으로 생 성하 지 않 고+번 호 를 통 해 같은 성능 을 얻 을 수 있다 는 것 을 설명 할 수 있 습 니까?
동적 연결 문자열 을 시도 해 보 겠 습 니 다:
동적 연결 문자열 은 실행 할 때 만 최종 문자열 을 알 수 있 는 하위 문자열 을 말 합 니 다.예 를 들 어 순환 에 문자열 을 추가 합 니 다:

public static void main(String[] args) {
 String result = "";
 for (int i = 0; i < 10; i++) {
  result += "some more data";
 }
 System.out.println(result);
 }
같은 역 컴 파일:

Code:
 0: aload_0  // Push 'this' on to the stack
 1: invokespecial #1 // Invoke Object class constructor
    // pop 'this' ref from the stack
 4: return  // Return from constructor

 public static void main(java.lang.String[]);
 Code:
 0: ldc  #2 // Load constant #2 on to the stack
 2: astore_1  // Create local var from stack, pop #2
 3: iconst_0  // Push value 0 onto the stack
 4: istore_2  // Pop value and store it in local var
 5: iload_2  // Push local var 2 on to the stack
 6: i2d  // Convert int to double on
    // top of stack (pop + push)
 7: ldc2_w  #3 // Push constant 10e6 on to the stack
 10: dcmpg  // Compare two doubles on top of stack
    // pop twice, push result: -1, 0 or 1
 11: ifge  40 // if value on top of stack is greater
    // than or equal to 0 (pop once)
    // branch to instruction at code 40
 14: new  #5 // Push new StringBuilder ref on stack
 17: dup  // Duplicate value on top of the stack
 18: invokespecial #6 // Invoke StringBuilder constructor
    // pop object reference
 21: aload_1  // Push local var 1 (empty String)
    // on to the stack
 22: invokevirtual #7 // Invoke StringBuilder.append
    // pop obj ref + param, push result
 25: ldc  #8 // Push "some more data" on the stack
 27: invokevirtual #7 // Invoke StringBuilder.append
    // pop obj ref + param, push result
 30: invokevirtual #9 // Invoke StringBuilder.toString
    // pop object reference
 33: astore_1  // Create local var from stack (pop)
 34: iinc  2, 1 // Increment local variable 2 by 1
 37: goto  5 // Move to instruction at code 5
 40: getstatic #10 // Push value System.out:PrintStream
 43: aload_1  // Push local var 1 (result String)
 44: invokevirtual #11 // Invoke method PrintStream.println()
    // pop twice (object ref + parameter)
 47: return  // Return void from method
14 시 에 new 가 StringBuilder 를 만 든 것 을 볼 수 있 지만 37 시 에 goto 가 5 가 되 었 고 순환 과정 에서 최적화 되 지 않 아 새로운 StringBuilder 를 계속 만 들 고 있다.
그래서 상기 코드 는 유사 합 니 다.

String result = "";
for (int i = 0; i < 10; i++) {
 StringBuilder tmp = new StringBuilder();
 tmp.append(result);
 tmp.append("some more data");
 result = tmp.toString();
}
System.out.println(result);
새로운 StringBuilder 가 계속 생 성 되 고 tostring 을 통 해 원래 의 StringBuilder 는 더 이상 인용 되 지 않 으 며 쓰레기 로 서 GC 비용 도 증가 합 니 다.
따라서 실제 사용 에 서 는 문자열 이 정적 연결 인지 동적 연결 인지 구분 할 수 없 을 때 StringBuilder 를 사용 하 세 요.
Reference:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기