Java Mid 05 - String 최적화

문자열 리터럴 최적화

컴파일 전

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초

    }
}

스크린샷 2024-09-18 오후 8 13 16

런타임에 연결한 문자열의 개수와 내용이 결정되기 때문에, 컴파일러는 실행직전에 어떤 상황이 벌어질줄 모른다.

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초

    }
}

image

성능차이가 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

인프런 김영한님의 실전 자바 강좌 + 나의 뇌



© 2022. by taewoo

Powered by taewoo