https://school.programmers.co.kr/learn/courses/30/lessons/81301
프로그래머스에서 문제를 풀다가 String.valueOf()를 써서 문자열을 이을 때와 +""를 써서 문자열을 이을 때 실행시간이 꽤 많이 차이나는 것을 발견했다(나말고 다른 팀원이 발견함ㅎ).
다른 코드를 제외하고 딱 문자열을 잇는 부분만 바꿨는데 시간차이가 많이나길래 왜그런가 싶어서 이것저것 찾아봤다.
아래의 글을 가장 먼저 확인했다.
https://stackoverflow.com/questions/7752347/string-valueof-vs-concatenation-with-empty-string
String valueOf vs concatenation with empty string
I am working in Java code optimization. I'm unclear about the difference between String.valueOf or the +"" sign: int intVar = 1; String strVar = intVar + ""; String strVar = String.valueOf(intVar);
stackoverflow.com
이 글에서는 Java의 바이트코드를 구성하는 명령어를 통해 두 방법의 차이점을 보여준다.
이 답변만 보고서는,
컴파일에 필요한 코드가 빈문자열로 concat하는 과정에 더 많이 필요하니까 String.valueOf()보다 더 느릴 수 밖에 없네!
라고 판단하고 검색을 그만둘 뻔 했는데 그럴 수가 없었다.
이 글의 작성일자가 약 12년 전이였기 때문이다.
그래서 다른 글도 확인해봤다.
https://www.baeldung.com/java-string-concatenation-invoke-dynamic
스택오버플로우에서 보이는 빈문자열 concat 방식은 StringBuilder를 이용한 방식인데 이 방식은 Java8까지만 사용된 방식이다. 하지만 이 방식은 loop 안에서 concat을 진행하면 StringBuilder 객체가 계속 생기는 문제점이 있었기에 Java9부터는 Invokedynamic 방식을 사용하도록 바뀌었다고 한다.
+ java compiler에서 내보낸 바이트 코드를 추가로 변경하지 않고도 문자열 연결의 최적화를 활성화시키기 위함(?)
https://wedul.site/710
https://www.guardsquare.com/blog/string-concatenation-java-9-untangling-invokedynamic
(얘는 참고하려고 봤는데 무슨 말인지 잘 모르겠다,,ㅜㅜ)
현재 사용 중인 Java의 바이트코드를 확인하기 위해 intellij에서 java 파일을 작성하고 compile한 후 javap -c 명령어를 통해 코드를 확인해봤다.
//Main.java
public class Main {
public static void main(String[] args) {
int i = 1;
String s1 = i + "";
String s2 = String.valueOf(i);
}
}
// Bytecode
1: istore_1
2: iload_1
3: invokedynamic #7, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
8: astore_2
9: iload_1
10: invokestatic #11 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
13: astore_3
14: return
Java17에서도 Invokedynamic을 통해 int값을 String과 결합시키는 것을 확인할 수 있었다.
여기까지의 내용으로는 그냥 두 가지 방식에 어떤 차이점이 있다?정도만 알게 된 것 같은데, 이 때 팀원분이 혼란스러운 내용을 공유해주셨다.
프로그래머스에서는 String.valueOf()가 훨씬 빠르게 동작하는데, intellij에서는 +""가 훠얼씬 빠르게 동작한다는 것이였다.
그래서 얼렁 테스트를 진행해봤다.
public class Main {
public static void main(String[] args) {
long start = 0, end = 0;
start = System.currentTimeMillis();
test02();
end = System.currentTimeMillis();
long diffTime = (end-start)/1000;
System.out.println("Concatenation with String.valueOf(): " + diffTime + "s");
start = System.currentTimeMillis();
test01();
end = System.currentTimeMillis();
diffTime = (end-start)/1000;
System.out.println("Concatenation with empty string: " + diffTime + "s");
}
private static void test01() {
String s = "";
for (int i = 1; i < 200000; i++) {
s += i + "";
}
}
private static void test02() {
String s = "";
for (int i = 1; i < 200000; i++) {
s += String.valueOf(i);
}
}
}
각각의 방식을 이용해 빈 문자열 s에 1~200,000까지의 수를 하나씩 이어붙이는 메서드들이다.
Intellij에서는 빈문자열로 concat하는 방법이 2배 이상 빨랐다.
뭐지..??
프로그래머스의 Java compiler가 혹시나 8 이하인가 싶어서 확인을 슬쩍 해봤는데 아닌 듯 했다.
그래서 프로그래머스에 문의를 넣어버렸다.
제가 잘못 생각하고 있거나 프로그래머스의 어떤 환경문제이거나 둘 중 하나겠죠..?🙂
답변 기다리는 중,,