Java Mid 05 - String 최적화
in Programming Language on Java
문자열 리터럴 최적화
컴파일 전
String helloWorld = "Hello, World!";
런타임에 별도의 문자열을 결합하지 않기 때문에 성능은 향상된다.
String 변수 최적화
문자열의 경우에는 그 안에 어떤 값이 들어있는지 컴파일 시점에는 알 수가 없어서 단순하게 합칠 수 있다.
String result = str1 + str2;
//최적화
String result = new StringBuilder().append(str1_.append(str2).toString();
String 최적화가 어려운 경우
문자열을 루프안에서 문자열을 더하는 경우에는 최적화가 이루어지지 않는다.
public class LoopStringMain {
public static void main(String[] args) {
/*
startTime ~ endTime 사이의 시간을 구한다.
*/
long startTime = System.currentTimeMillis(); //system에서 현재 밀리세컨드 시간을 얻는다.
String result = "";
for (int i = 0; i < 100000; i++) {
result += "Hello java";
}
long endTime = System.currentTimeMillis();
System.out.println( "result = " + result );
System.out.println( "time = " + (endTime - startTime) + "ms" ); //ms 1/1000초 2.3초
}
}
런타임에 연결한 문자열의 개수와 내용이 결정되기 때문에, 컴파일러는 실행직전에 어떤 상황이 벌어질줄 모른다.
10만번의 String객체가 생겼을 것이다. (메모리 낭비가 심해진다.)
StringBuilder로 최적화
public class LoopStringBuilderMain {
public static void main(String[] args) {
/*
startTime ~ endTime 사이의 시간을 구한다.
*/
long startTime = System.currentTimeMillis(); //system에서 현재 밀리세컨드 시간을 얻는다.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) {
sb.append( "Hello java" );
}
long endTime = System.currentTimeMillis();
String result = sb.toString();
System.out.println( "result = " + result );
System.out.println( "time = " + (endTime - startTime) + "ms" ); //ms 1/1000초 2.3초
}
}
성능차이가 7,800배 차이가 나는 것을 확인할 수 있다.
그러면 Builder를 언제써야할까?
반복문의 횟수가 너무 많을때 ex) 10만번 정도 돌거나, 문자가 크게 누적될 때 사용하게 된다.
메서드 체이닝
public class MethodChainingMain3 {
public static void main(String[] args) {
ValueAdder adder = new ValueAdder();
//x001.add(1) -> this 반환 -> x001.add(2) -> this 반환 -> x001.add(3) -> this 반환
int result = adder.add( 1 ).add( 2 ).add( 3 ).getValue(); //add호출 -> this 반환
System.out.println( "result = " + result );
}
}
메서드 체이닝 기법은 코드를 간결하고 읽기 쉽게 만들어 준다.
메서드 호출의 결과로 자기 자신의 참조값을 반환하면, 반환된 참조값을 사용해서 메서드 호출을 계속 이어나갈 수 있다. 코드를 보면 메서드 체이닝 방식은 메서드가 끝나는 시점에 바로 .을 찍어서 변수명을 생략할 수 있다.
메서드 체이닝이 가능한 이유는 자기 자신의 참조값을 반환하기 때문이다. 접근연산자를 찍어서 바로 자기 자신의 메서드를 호출할 수 있다.
이 코드를 chaining으로 바꿔보자
public class StringBuilderMain1_2 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append( "A" );
sb.append( "B" );
sb.append( "C" );
sb.append( "D" );
System.out.println( "sb = " + sb );
sb.insert( 4, "Java" );
System.out.println( "sb = " + sb );
sb.delete( 4, 8 );
System.out.println( "sb = " + sb );
StringBuilder reverse = sb.reverse();
System.out.println( "reverse = " + reverse );
//StringBuilder -> String
String string = sb.toString();
System.out.println(string);
}
}
public class StringBuilderMain1_2 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
String string1 = sb.append( "A" ).append( "B" ).append( "C" ).append( "D" )
.insert( 4, "Java" )
.delete( 4, 8 )
.reverse()
.toString();
System.out.println( "string1 = " + string1 );
}
}
참고로 자바의 라이브러리와 오픈 소스들은 메서드 체이닝 방식을 종종 사용한다고 한다.(나중에 찾아봐야 겠다.)
Reference
인프런 김영한님의 실전 자바 강좌 + 나의 뇌