
Javaの文字列の結合は、+演算子が良いのか、StringBuilder(or StringBuffer)が良いのか、これもよく聞く問題です
先に結論言っちゃうと、コンパイル時に最適化されるので、+演算子を積極的に使うと良いです
むしろ、StringBuilderにしてると最適化が効かず効率が悪いこともあります
とは言え、全ての場面で+演算子を使えばいいかと言うとそうでもないんですよねぇ~
StringBuilderを使う方が良い場面もあります
この記事では、javap.exeを使って、文字連結時に使う+演算子とStringBuilderの使い分け方の根本的な考え方を示します
ちょっと記事の文量が多いように見えますが、読むべき量は意外と少ないので、良かったら最後まで見てあげてください
StringBuilderとStringBufferについてStringBuilderもStringBufferも使い方は同じですしそれほど大きな違いは無いため、本記事ではStringBuilderのみを取り上げます
ちなみに、StringBuilderとStringBufferとの違いは
StringBuilder
スレッド処理なし
処理早いStringBuffer
スレッド処理あり
処理遅い
現実的にはスレッド云々は別途対応して、StringBuilderを使えばいいのかなと思います
※StringBufferを使うメリットがあまり無い?
- Javaの文字列の結合は
+演算子さえ使っておけばいいと思っている人 - Javaの文字列の結合は
StringBuilderクラスさえ使っておけばいいと思っている人 - Javaの文字列の結合の事なんて考えたこと無かった人
- Javaの知識必要
- JDKをインストールしている
◆解決できるかも知れないお悩み
- Javaの文字列結合において、
+演算子とStringBuilderクラスの使い分け方が理解できます
◆どうやって解決するか
- javap.exeを使って、ソースコードの展開方法(バイトコード)を見ます
Contents
まずは結論! +演算子とStringBuilderクラスとの使い分け方
- 基本的には
+演算子を使えばいいです - 但し、1行で全部の文字列を連結する場合のみ
- 何行かに分けて連結する場合は、
StringBuilderクラスを使ってね forとかwhileの中ではStringBuilderクラスを使う方が良いでしょう- どっちを使えばいいか分からない場合は、javap.exeで確認せよ!
javapを使ってみよう
javaファイルをコンパイルすると、バイトコードというものに展開されます
バイトコードに展開される内容はソースコードと全く同じというわけではなく最適化されることがありますし使用している命令が変わることもあります
Javaの実行環境であるJVMはそのバイトコードを読み取って実行してくれます
ですので、実際にどのようなコードで動くのかはバイトコードを見るのが良いのです
で、そのバイトコードがclassファイルです
※classファイルはバイトコード以外の情報も持ってるよ
javapを使えばclassファイルに入っているバイトコードが見られます
まずはjavapの存在を確認
JDKをインストールした時のディレクトリのbinフォルダにjavapはいます
僕の環境だとここ↓
- C:\Program Files\Java\jdk1.8.0_72\bin\javap.exe
WindowsでもMacでもPATHを通していると思うので、以下のコマンドを打ってみてください
> javap -help
↓こんな感じで何か表示されればOKです
>javap -help 使用方法: javap使用可能なオプションには次のものがあります: -help --help -? この使用方法のメッセージを出力する -version バージョン情報 -v -verbose 追加情報を出力する -l 行番号とローカル変数表を出力する -public publicクラスおよびメンバーのみを表示する -protected protected/publicクラスおよびメンバーのみを表示する -package package/protected/publicクラスおよび メンバーのみを表示する(デフォルト) -p -private すべてのクラスとメンバーを表示する -c コードを逆アセンブルする -s 内部タイプ署名を出力する -sysinfo 処理しているクラスのシステム情報(パス、サイズ、日付、MD5ハッシュ) を表示する -constants final定数を表示する -classpath ユーザー・クラス・ファイルを検索する場所を指定する -cp ユーザー・クラス・ファイルを検索する場所を指定する -bootclasspath ブートストラップ・クラス・ファイルの場所をオーバーライドする
以下のソースコードをコンパイルします
このソースコードをコンパイルしてclassファイルを作ってちょーーーだい!
Main.javaは別にコンパイルしなくてもいいですよ
動かしたいのであればコンパイルすればいいですが、SamplePlus.javaとSampleBuilder.javaさえコンパイルしてもらえればOKです
public class Main {
public static void main(String argv[]) {
SamplePlus sp = new SamplePlus();
System.out.println( "Test11 : " + sp.Test11() );
System.out.println( "Test12 : " + sp.Test12() );
System.out.println( "Test13 : " + sp.Test13() );
System.out.println( "Test14 : " + sp.Test14() );
System.out.println( "Test21 : " + sp.Test21() );
System.out.println( "Test22 : " + sp.Test22() );
System.out.println( "Test23 : " + sp.Test23() );
System.out.println( "Test24 : " + sp.Test24() );
System.out.println( "Test25 : " + sp.Test25() );
System.out.println( "Test26 : " + sp.Test26() );
SampleBuilder sb = new SampleBuilder();
System.out.println( "Test11 : " + sb.Test11() );
System.out.println( "Test12 : " + sb.Test12() );
System.out.println( "Test22 : " + sb.Test22() );
System.out.println( "Test24 : " + sb.Test24() );
System.out.println( "Test26 : " + sb.Test26() );
}
}
public class SamplePlus {
//===========================================================
// ノーマル系
//===========================================================
//***********************************************************
// 大分類:1行で連結
// 中分類:String変数使用
// 小分類:---
//***********************************************************
public static String Test11() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
String gabo;
gabo = hoge + fuga + piyo;
return gabo;
}
//***********************************************************
// 大分類:1行で連結
// 中分類:文字列使用
// 小分類:---
//***********************************************************
public static String Test12() {
String gabo;
gabo = "aiueo" + "kakikukeko" + "sasisuseso";
return gabo;
}
//***********************************************************
// 大分類:複数行で連結
// 中分類:String変数使用
// 小分類:---
//***********************************************************
public static String Test13() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
String gabo;
gabo = "";
gabo += hoge;
gabo += fuga;
gabo += piyo;
return gabo;
}
//***********************************************************
// 大分類:複数行で連結
// 中分類:文字列使用
// 小分類:---
//***********************************************************
public static String Test14() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
String gabo;
gabo = "";
gabo += "aiueo";
gabo += "kakikukeko";
gabo += "sasisuseso";
return gabo;
}
//***********************************************************
// 大分類:1行で連結
// 中分類:String変数と文字列の混合使用
// 小分類:---
//***********************************************************
public static String Test15() {
String hoge = "aiueo";
String piyo = "sasisuseso";
String gabo;
gabo = hoge + "kakikukeko" + piyo + "tatituteto";
return gabo;
}
//===========================================================
// ループ系
//===========================================================
//***********************************************************
// 大分類:ループ使用
// 中分類:String変数使用
// 小分類:ループの【外】でString変数定義
// :代入系
//***********************************************************
public static String Test21() {
String hoge = "aiueo";
String gabo = "";
for(int i=0; i < 100; i++) {
gabo = hoge;
}
return gabo;
}
//***********************************************************
// 大分類:ループ使用
// 中分類:String変数使用
// 小分類:ループの【外】でString変数定義
// :足していく系
//***********************************************************
public static String Test22() {
String hoge = "aiueo";
String gabo = "";
for(int i=0; i < 100; i++) {
gabo += hoge;
}
return gabo;
}
//***********************************************************
// 大分類:ループ使用
// 中分類:String変数使用
// 小分類:ループの【中】でString変数定義
// :代入系
//***********************************************************
public static String Test23() {
String gabo = "";
for(int i=0; i < 100; i++) {
String hoge = "aiueo";
gabo = hoge;
}
return gabo;
}
//***********************************************************
// 大分類:ループ使用
// 中分類:String変数使用
// 小分類:ループの【中】でString変数定義
// :足していく系
//***********************************************************
public static String Test24() {
String gabo = "";
for(int i=0; i < 100; i++) {
String hoge = "aiueo";
gabo += hoge;
}
return gabo;
}
//***********************************************************
// 大分類:ループ使用
// 中分類:文字列使用
// 小分類:---
// :代入系
//***********************************************************
public static String Test25() {
String gabo = "";
for(int i=0; i < 100; i++) {
gabo = "aiueo";
}
return gabo;
}
//***********************************************************
// 大分類:ループ使用
// 中分類:文字列使用
// 小分類:---
// :足していく系
//***********************************************************
public static String Test26() {
String gabo = "";
for(int i=0; i < 100; i++) {
gabo += "aiueo";
}
return gabo;
}
}
public class SampleBuilder {
//===========================================================
// ノーマル系
//===========================================================
//***********************************************************
// 大分類:1行で連結
// 中分類:String変数使用
// 小分類:---
//***********************************************************
public static String Test11() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
StringBuilder gabo = new StringBuilder();
gabo.append(hoge);
gabo.append(fuga);
gabo.append(piyo);
return gabo.toString();
}
//***********************************************************
// 大分類:1行で連結
// 中分類:文字列使用
// 小分類:---
//***********************************************************
public static String Test12() {
StringBuilder gabo = new StringBuilder();
gabo.append("aiueo");
gabo.append("kakikukeko");
gabo.append("sasisuseso");
return gabo.toString();
}
// //***********************************************************
// // 大分類:複数行で連結
// // 中分類:String変数使用
// // 小分類:---
// //***********************************************************
// public static String Test13() {
//
// }
// //***********************************************************
// // 大分類:複数行で連結
// // 中分類:文字列使用
// // 小分類:---
// //***********************************************************
// public static String Test14() {
//
// }
//***********************************************************
// 大分類:1行で連結
// 中分類:String変数と文字列の混合使用
// 小分類:---
//***********************************************************
public static String Test15() {
String hoge = "aiueo";
String piyo = "sasisuseso";
StringBuilder gabo = new StringBuilder();
gabo.append(hoge);
gabo.append("kakikukeko");
gabo.append(piyo);
gabo.append("tatituteto");
return gabo.toString();
}
//===========================================================
// ループ系
//===========================================================
// //***********************************************************
// // 大分類:ループ使用
// // 中分類:String変数使用
// // 小分類:ループの【外】でString変数定義
// // :代入系
// //***********************************************************
// public static String Test21() {
//
// }
//***********************************************************
// 大分類:ループ使用
// 中分類:String変数使用
// 小分類:ループの【外】でString変数定義
// :足していく系
//***********************************************************
public static String Test22() {
String hoge = "aiueo";
StringBuilder gabo = new StringBuilder();
for(int i=0; i < 100; i++) {
gabo.append(hoge);
}
return gabo.toString();
}
// //***********************************************************
// // 大分類:ループ使用
// // 中分類:String変数使用
// // 小分類:ループの【中】でString変数定義
// // :代入系
// //***********************************************************
// public static String Test23() {
// }
//***********************************************************
// 大分類:ループ使用
// 中分類:String変数使用
// 小分類:ループの【中】でString変数定義
// :足していく系
//***********************************************************
public static String Test24() {
StringBuilder gabo = new StringBuilder();
for(int i=0; i < 100; i++) {
String hoge = "aiueo";
gabo.append(hoge);
}
return gabo.toString();
}
// //***********************************************************
// // 大分類:ループ使用
// // 中分類:文字列使用
// // 小分類:---
// // :代入系
// //***********************************************************
// public static String Test25() {
//
// }
//***********************************************************
// 大分類:ループ使用
// 中分類:文字列使用
// 小分類:---
// :足していく系
//***********************************************************
public static String Test26() {
StringBuilder gabo = new StringBuilder();
for(int i=0; i < 100; i++) {
gabo.append("aiueo");
}
return gabo.toString();
}
}
javapでclassファイルを読み込みます
> javap -c SamplePlus.class > javap -c SampleBuilder.class
テキストファイルに出力したければリダイレクトしてください
> javap -c SamplePlus.class > SamplePlus_javap.txt > javap -c SampleBuilder.class > SampleBuilder_javap.txt
こんなデータが出力されます
↓これがバイトコードです
Compiled from "SamplePlus.java"
public class SamplePlus {
public SamplePlus();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static java.lang.String Test11();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."":()V
16: aload_0
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_1
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_2
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_3
32: aload_3
33: areturn
public static java.lang.String Test12();
Code:
0: ldc #9 // String aiueokakikukekosasisuseso
2: astore_0
3: aload_0
4: areturn
public static java.lang.String Test13();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: ldc #10 // String
11: astore_3
12: new #5 // class java/lang/StringBuilder
15: dup
16: invokespecial #6 // Method java/lang/StringBuilder."":()V
19: aload_3
20: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: aload_0
24: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore_3
31: new #5 // class java/lang/StringBuilder
34: dup
35: invokespecial #6 // Method java/lang/StringBuilder."":()V
38: aload_3
39: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
42: aload_1
43: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
46: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
49: astore_3
50: new #5 // class java/lang/StringBuilder
53: dup
54: invokespecial #6 // Method java/lang/StringBuilder."":()V
57: aload_3
58: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
61: aload_2
62: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
65: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
68: astore_3
69: aload_3
70: areturn
public static java.lang.String Test14();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: ldc #10 // String
11: astore_3
12: new #5 // class java/lang/StringBuilder
15: dup
16: invokespecial #6 // Method java/lang/StringBuilder."":()V
19: aload_3
20: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: ldc #2 // String aiueo
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_3
32: new #5 // class java/lang/StringBuilder
35: dup
36: invokespecial #6 // Method java/lang/StringBuilder."":()V
39: aload_3
40: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: ldc #3 // String kakikukeko
45: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
48: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
51: astore_3
52: new #5 // class java/lang/StringBuilder
55: dup
56: invokespecial #6 // Method java/lang/StringBuilder."":()V
59: aload_3
60: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
63: ldc #4 // String sasisuseso
65: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
68: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
71: astore_3
72: aload_3
73: areturn
public static java.lang.String Test15();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #4 // String sasisuseso
5: astore_1
6: new #5 // class java/lang/StringBuilder
9: dup
10: invokespecial #6 // Method java/lang/StringBuilder."":()V
13: aload_0
14: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: ldc #3 // String kakikukeko
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: ldc #11 // String tatituteto
28: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
31: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: astore_2
35: aload_2
36: areturn
public static java.lang.String Test21();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #10 // String
5: astore_1
6: iconst_0
7: istore_2
8: iload_2
9: bipush 100
11: if_icmpge 22
14: aload_0
15: astore_1
16: iinc 2, 1
19: goto 8
22: aload_1
23: areturn
public static java.lang.String Test22();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #10 // String
5: astore_1
6: iconst_0
7: istore_2
8: iload_2
9: bipush 100
11: if_icmpge 39
14: new #5 // class java/lang/StringBuilder
17: dup
18: invokespecial #6 // Method java/lang/StringBuilder."":()V
21: aload_1
22: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: aload_0
26: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: astore_1
33: iinc 2, 1
36: goto 8
39: aload_1
40: areturn
public static java.lang.String Test23();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 22
11: ldc #2 // String aiueo
13: astore_2
14: aload_2
15: astore_0
16: iinc 1, 1
19: goto 5
22: aload_0
23: areturn
public static java.lang.String Test24();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 39
11: ldc #2 // String aiueo
13: astore_2
14: new #5 // class java/lang/StringBuilder
17: dup
18: invokespecial #6 // Method java/lang/StringBuilder."":()V
21: aload_0
22: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: aload_2
26: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: astore_0
33: iinc 1, 1
36: goto 5
39: aload_0
40: areturn
public static java.lang.String Test25();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 20
11: ldc #2 // String aiueo
13: astore_0
14: iinc 1, 1
17: goto 5
20: aload_0
21: areturn
public static java.lang.String Test26();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 37
11: new #5 // class java/lang/StringBuilder
14: dup
15: invokespecial #6 // Method java/lang/StringBuilder."":()V
18: aload_0
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: ldc #2 // String aiueo
24: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore_0
31: iinc 1, 1
34: goto 5
37: aload_0
38: areturn
}
Compiled from "SampleBuilder.java"
public class SampleBuilder {
public SampleBuilder();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static java.lang.String Test11();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."":()V
16: astore_3
17: aload_3
18: aload_0
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: pop
23: aload_3
24: aload_1
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: pop
29: aload_3
30: aload_2
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: pop
35: aload_3
36: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
39: areturn
public static java.lang.String Test12();
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."":()V
7: astore_0
8: aload_0
9: ldc #2 // String aiueo
11: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: pop
15: aload_0
16: ldc #3 // String kakikukeko
18: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: pop
22: aload_0
23: ldc #4 // String sasisuseso
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: pop
29: aload_0
30: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
33: areturn
public static java.lang.String Test15();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #4 // String sasisuseso
5: astore_1
6: new #5 // class java/lang/StringBuilder
9: dup
10: invokespecial #6 // Method java/lang/StringBuilder."":()V
13: astore_2
14: aload_2
15: aload_0
16: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: aload_2
21: ldc #3 // String kakikukeko
23: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: pop
27: aload_2
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: pop
33: aload_2
34: ldc #9 // String tatituteto
36: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: pop
40: aload_2
41: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: areturn
public static java.lang.String Test22();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: new #5 // class java/lang/StringBuilder
6: dup
7: invokespecial #6 // Method java/lang/StringBuilder."":()V
10: astore_1
11: iconst_0
12: istore_2
13: iload_2
14: bipush 100
16: if_icmpge 31
19: aload_1
20: aload_0
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: pop
25: iinc 2, 1
28: goto 13
31: aload_1
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: areturn
public static java.lang.String Test24();
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."":()V
7: astore_0
8: iconst_0
9: istore_1
10: iload_1
11: bipush 100
13: if_icmpge 31
16: ldc #2 // String aiueo
18: astore_2
19: aload_0
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: pop
25: iinc 1, 1
28: goto 10
31: aload_0
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: areturn
public static java.lang.String Test26();
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."":()V
7: astore_0
8: iconst_0
9: istore_1
10: iload_1
11: bipush 100
13: if_icmpge 29
16: aload_0
17: ldc #2 // String aiueo
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: pop
23: iinc 1, 1
26: goto 10
29: aload_0
30: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
33: areturn
}
javapで出力された内容を解説します(SamplePlus編)
注目して欲しいのは2つ
- newの数
+演算子がStringBuilderに変換(最適化)されている
+演算子での文字連結は基本的にはStringBuilderに変換されるのです
ですので、+演算子を積極的に使うことを推奨します
StringBuilderより+演算子の方が読みやすいですよね
でもですね、newの数が無駄に多くなることがあります
その場合はインスタンス生成→解放の処理が無駄なので、素直にStringBuilderを使う方が良い場面もあります
+演算子で良い場合、悪い場合を見ていきましょう!
invokespecial:コンストラクタの呼び出し
invokevirtual:メソッドの呼び出し
ノーマル系
Test11
前置き
- 1行で連結
- String変数使用
public static String Test11() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
String gabo;
gabo = hoge + fuga + piyo;
return gabo;
}
public static java.lang.String Test11();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."":()V
16: aload_0
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_1
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_2
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_3
32: aload_3
33: areturn
解説
この1行で連結する形は、+演算子でいいです
Test12
- 1行で連結
- 文字列使用
public static String Test12() {
String gabo;
gabo = "aiueo" + "kakikukeko" + "sasisuseso";
return gabo;
}
public static java.lang.String Test12();
Code:
0: ldc #9 // String aiueokakikukekosasisuseso
2: astore_0
3: aload_0
4: areturn
これも1行で連結する形ですね
しかも、#9のところを見れば分かるように、コンパイル時点でaiueokakikukekosasisusesoを準備してくれてます
なので+演算子でいいです
Test13
- 複数行で連結
- String変数使用
public static String Test13() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
String gabo;
gabo = "";
gabo += hoge;
gabo += fuga;
gabo += piyo;
return gabo;
}
public static java.lang.String Test13();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: ldc #10 // String
11: astore_3
12: new #5 // class java/lang/StringBuilder
15: dup
16: invokespecial #6 // Method java/lang/StringBuilder."":()V
19: aload_3
20: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: aload_0
24: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore_3
31: new #5 // class java/lang/StringBuilder
34: dup
35: invokespecial #6 // Method java/lang/StringBuilder."":()V
38: aload_3
39: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
42: aload_1
43: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
46: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
49: astore_3
50: new #5 // class java/lang/StringBuilder
53: dup
54: invokespecial #6 // Method java/lang/StringBuilder."":()V
57: aload_3
58: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
61: aload_2
62: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
65: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
68: astore_3
69: aload_3
70: areturn
Test11()を複数行で連結にした形です
複数行にするとnewを3個も呼び出すので、無駄になります
1行で連結するか、StringBuilderを使いましょう
Test14
- 複数行で連結
- 文字列使用
public static String Test14() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
String gabo;
gabo = "";
gabo += "aiueo";
gabo += "kakikukeko";
gabo += "sasisuseso";
return gabo;
}
public static java.lang.String Test14();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: ldc #10 // String
11: astore_3
12: new #5 // class java/lang/StringBuilder
15: dup
16: invokespecial #6 // Method java/lang/StringBuilder."":()V
19: aload_3
20: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: ldc #2 // String aiueo
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_3
32: new #5 // class java/lang/StringBuilder
35: dup
36: invokespecial #6 // Method java/lang/StringBuilder."":()V
39: aload_3
40: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: ldc #3 // String kakikukeko
45: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
48: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
51: astore_3
52: new #5 // class java/lang/StringBuilder
55: dup
56: invokespecial #6 // Method java/lang/StringBuilder."":()V
59: aload_3
60: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
63: ldc #4 // String sasisuseso
65: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
68: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
71: astore_3
72: aload_3
73: areturn
これもTest12()を複数行で連結にした形です
先ほどと同じように複数行にするとnewを3個も呼び出すので、無駄になります
1行で連結するか、StringBuilderを使いましょう
Test15
- 1行で連結
- String変数と文字列の混合使用
public static String Test15() {
String hoge = "aiueo";
String piyo = "sasisuseso";
String gabo;
gabo = hoge + "kakikukeko" + piyo + "tatituteto";
return gabo;
}
public static java.lang.String Test15();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #4 // String sasisuseso
5: astore_1
6: new #5 // class java/lang/StringBuilder
9: dup
10: invokespecial #6 // Method java/lang/StringBuilder."":()V
13: aload_0
14: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: ldc #3 // String kakikukeko
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: ldc #11 // String tatituteto
28: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
31: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: astore_2
35: aload_2
36: areturn
変数と文字列が混在していますが、1行連結ですので、newも1個ですね
+演算子で問題ありません
ループ系
Test21
- ループ使用
- String変数使用
- ループの【外】でString変数定義
- 代入系
public static String Test21() {
String hoge = "aiueo";
String gabo = "";
for(int i=0; i < 100; i++) {
gabo = hoge;
}
return gabo;
}
public static java.lang.String Test21();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #10 // String
5: astore_1
6: iconst_0
7: istore_2
8: iload_2
9: bipush 100
11: if_icmpge 22
14: aload_0
15: astore_1
16: iinc 2, 1
19: goto 8
22: aload_1
23: areturn
hogeをgoboへ100回代入してますけど、意味はないです
19:で8:へgotoしているので、9:~16:がfor文の処理です
特にnewしているわけでもないので、問題ないですね
+演算子の使用でOKです
Test22
- ループ使用
- String変数使用
- ループの【外】でString変数定義
- 足していく系
public static String Test22() {
String hoge = "aiueo";
String gabo = "";
for(int i=0; i < 100; i++) {
gabo += hoge;
}
return gabo;
}
public static java.lang.String Test22();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #10 // String
5: astore_1
6: iconst_0
7: istore_2
8: iload_2
9: bipush 100
11: if_icmpge 39
14: new #5 // class java/lang/StringBuilder
17: dup
18: invokespecial #6 // Method java/lang/StringBuilder."":()V
21: aload_1
22: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: aload_0
26: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: astore_1
33: iinc 2, 1
36: goto 8
39: aload_1
40: areturn
Test21()を代入から常に連結に変えたものです
for文の処理はどこからどこまででしょうか?
36:でgotoしているので、9:~33:がfor文の処理ですね
ということは、毎回newしちゃってます
無駄ですね...
連結しまくるなら、StringBuilderを使いましょう
Test23
- ループ使用
- String変数使用
- ループの【中】でString変数定義
- 代入系
public static String Test23() {
String gabo = "";
for(int i=0; i < 100; i++) {
String hoge = "aiueo";
gabo = hoge;
}
return gabo;
}
public static java.lang.String Test23();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 22
11: ldc #2 // String aiueo
13: astore_2
14: aload_2
15: astore_0
16: iinc 1, 1
19: goto 5
22: aload_0
23: areturn
Test21()の変数hogeの宣言位置がfor文の中に移動しました
しかし、newしていませんね
これは"aiueo"の値固定なので、11:で準備してくれてますね
+演算子でいいでしょう
Test24
- ループ使用
- String変数使用
- ループの【中】でString変数定義
- 足していく系
public static String Test24() {
String gabo = "";
for(int i=0; i < 100; i++) {
String hoge = "aiueo";
gabo += hoge;
}
return gabo;
}
public static java.lang.String Test24();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 39
11: ldc #2 // String aiueo
13: astore_2
14: new #5 // class java/lang/StringBuilder
17: dup
18: invokespecial #6 // Method java/lang/StringBuilder."":()V
21: aload_0
22: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: aload_2
26: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: astore_0
33: iinc 1, 1
36: goto 5
39: aload_0
40: areturn
Test22()の変数hogeの宣言位置がfor文の中に移動しましたが、形は殆ど変わりません
for文の中で毎回newしています
StringBuilderを使いましょう
StringBuilderの宣言はfor文の外でしましょう
Test25
- ループ使用
- 文字列使用
- ---
- 代入系
public static String Test25() {
String gabo = "";
for(int i=0; i < 100; i++) {
gabo = "aiueo";
}
return gabo;
}
public static java.lang.String Test25();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 20
11: ldc #2 // String aiueo
13: astore_0
14: iinc 1, 1
17: goto 5
20: aload_0
21: areturn
Test21()での変数hogeが直接"aiueo"の文字列になりました
最適化内容はほぼ同じ
+演算子の使用でOKです
Test26
- ループ使用
- 文字列使用
- ---
- 足していく系
public static String Test26() {
String gabo = "";
for(int i=0; i < 100; i++) {
gabo += "aiueo";
}
return gabo;
}
public static java.lang.String Test26();
Code:
0: ldc #10 // String
2: astore_0
3: iconst_0
4: istore_1
5: iload_1
6: bipush 100
8: if_icmpge 37
11: new #5 // class java/lang/StringBuilder
14: dup
15: invokespecial #6 // Method java/lang/StringBuilder."":()V
18: aload_0
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: ldc #2 // String aiueo
24: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore_0
31: iinc 1, 1
34: goto 5
37: aload_0
38: areturn
Test22()での変数hogeが直接"aiueo"の文字列になりました
最適化内容はほぼ同じで、毎回newしちゃってます
無駄ですね...
連結しまくるなら、StringBuilderを使いましょう
javapで出力された内容を解説します(SampleBuilder編)
つぎに、StringBuilderを使った場合を見ます
バイトコードに展開されてもStringBuilderなので、ソースコードとバイトコードに大きな違いは出ませんが、一応見てみましょう
注目して欲しいのはこれ
- newの数
invokespecial:コンストラクタの呼び出し
invokevirtual:メソッドの呼び出し
ノーマル系
Test11
前置き
- 1行で連結
- String変数使用
public static String Test11() {
String hoge = "aiueo";
String fuga = "kakikukeko";
String piyo = "sasisuseso";
StringBuilder gabo = new StringBuilder();
gabo.append(hoge);
gabo.append(fuga);
gabo.append(piyo);
return gabo.toString();
}
public static java.lang.String Test11();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #3 // String kakikukeko
5: astore_1
6: ldc #4 // String sasisuseso
8: astore_2
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."":()V
16: astore_3
17: aload_3
18: aload_0
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: pop
23: aload_3
24: aload_1
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: pop
29: aload_3
30: aload_2
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: pop
35: aload_3
36: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
39: areturn
解説
+演算子の時よりも少し処理が多いですね
やっぱり1行で連結する形は、+演算子がいいですね
Test12
- 1行で連結
- 文字列使用
public static String Test12() {
StringBuilder gabo = new StringBuilder();
gabo.append("aiueo");
gabo.append("kakikukeko");
gabo.append("sasisuseso");
return gabo.toString();
}
public static java.lang.String Test12();
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."":()V
7: astore_0
8: aload_0
9: ldc #2 // String aiueo
11: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: pop
15: aload_0
16: ldc #3 // String kakikukeko
18: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: pop
22: aload_0
23: ldc #4 // String sasisuseso
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: pop
29: aload_0
30: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
33: areturn
これもTest11()と同じく、+演算子の時よりも少し処理が多くなっていますね
やっぱり1行で連結する形は、+演算子がいいですね
Test13
※無し
Test14
※無し
Test15
- 1行で連結
- String変数と文字列の混合使用
public static String Test15() {
String hoge = "aiueo";
String piyo = "sasisuseso";
StringBuilder gabo = new StringBuilder();
gabo.append(hoge);
gabo.append("kakikukeko");
gabo.append(piyo);
gabo.append("tatituteto");
return gabo.toString();
}
public static java.lang.String Test15();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: ldc #4 // String sasisuseso
5: astore_1
6: new #5 // class java/lang/StringBuilder
9: dup
10: invokespecial #6 // Method java/lang/StringBuilder."":()V
13: astore_2
14: aload_2
15: aload_0
16: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: aload_2
21: ldc #3 // String kakikukeko
23: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: pop
27: aload_2
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: pop
33: aload_2
34: ldc #9 // String tatituteto
36: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: pop
40: aload_2
41: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: areturn
これもTest11()と同じく、+演算子の時よりも少し処理が多くなっていますね
やっぱり1行で連結する形は、+演算子がいいですね
ループ系
Test21
※無し
Test22
- ループ使用
- String変数使用
- ループの【外】でString変数定義
- 足していく系
public static String Test22() {
String hoge = "aiueo";
StringBuilder gabo = new StringBuilder();
for(int i=0; i < 100; i++) {
gabo.append(hoge);
}
return gabo.toString();
}
public static java.lang.String Test22();
Code:
0: ldc #2 // String aiueo
2: astore_0
3: new #5 // class java/lang/StringBuilder
6: dup
7: invokespecial #6 // Method java/lang/StringBuilder."":()V
10: astore_1
11: iconst_0
12: istore_2
13: iload_2
14: bipush 100
16: if_icmpge 31
19: aload_1
20: aload_0
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: pop
25: iinc 2, 1
28: goto 13
31: aload_1
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: areturn
これは+演算子のバイトコードよりも処理が少なくなっています
しかし、処理の少なさよりも見てほしいのはnewの位置です
for文の処理はどこからどこまででしょうか?
28:でgotoしているので、14:~25:がfor文の処理ですね
ということは、+演算子の時と違ってnewは1回だけです
ループ文を使って連結しまくる処理の場合は、StringBuilderを使いましょう
Test23
※無し
Test24
- ループ使用
- String変数使用
- ループの【中】でString変数定義
- 足していく系
public static String Test24() {
StringBuilder gabo = new StringBuilder();
for(int i=0; i < 100; i++) {
String hoge = "aiueo";
gabo.append(hoge);
}
return gabo.toString();
}
public static java.lang.String Test24();
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."":()V
7: astore_0
8: iconst_0
9: istore_1
10: iload_1
11: bipush 100
13: if_icmpge 31
16: ldc #2 // String aiueo
18: astore_2
19: aload_0
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: pop
25: iinc 1, 1
28: goto 10
31: aload_0
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: areturn
+演算子の場合はfor文の中でnewを何度もしていましたが、StringBuilderを使った場合はnewは最初の1回だけです
ループで連結しまくるなら、StringBuilderを使いましょう
Test25
※無し
Test26
- ループ使用
- 文字列使用
- ---
- 足していく系
public static String Test26() {
StringBuilder gabo = new StringBuilder();
for(int i=0; i < 100; i++) {
gabo.append("aiueo");
}
return gabo.toString();
}
public static java.lang.String Test26();
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."":()V
7: astore_0
8: iconst_0
9: istore_1
10: iload_1
11: bipush 100
13: if_icmpge 29
16: aload_0
17: ldc #2 // String aiueo
19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: pop
23: iinc 1, 1
26: goto 10
29: aload_0
30: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
33: areturn
+演算子の場合はfor文の中でnewを何度もしていましたが、StringBuilderを使った場合はnewは最初の1回だけです
ループで連結しまくるなら、StringBuilderを使いましょう
まとめ
まとめると、
- Javaの文字連結は
+演算子を使い、コンパイル時の最適化に任せる方が良い StringBuilderを使うと最適化してもらえないので、無駄な処理になることがある- とは言っても、
+演算子ではダメな場面もあるので、その時は自分でStringBuilderを使う
| 内容 | +演算子 |
StringBuilder |
|---|---|---|
| Test11 1行で連結 String変数使用 |
○ 1行連結は +演算子推奨! |
☓ |
| Test12 1行で連結 文字列使用 |
○ 1行連結は +演算子推奨! |
☓ |
| Test13 複数行で連結 String変数使用 |
☓ | ○ 複数行連結なら StringBuilderもしくは1行連結に書き直すなら +演算子が使える
|
| Test14 複数行で連結 文字列使用 |
☓ | ○ 複数行連結なら StringBuilderもしくは1行連結に書き直すなら +演算子が使える
|
| Test15 1行で連結 String変数と文字列の混合使用 |
○ 1行連結は +演算子推奨! |
☓ |
| Test21 ループ使用 String変数使用 ループの【外】でString変数定義 代入系 |
○ ループ処理だけど同じ値を代入しているだけなので、何度もnewしないから +演算子でOK(現実的にはこんな処理を書くこと自体がおかしいけどねwww) |
☓ |
| Test22 ループ使用 String変数使用 ループの【外】でString変数定義 足していく系 |
☓ | ○ ループの中で毎回連結するなら StringBuilderを使いましょう
|
| Test23 ループ使用 String変数使用 ループの【中】でString変数定義 代入系 |
○ Test21と同じく、固定値を代入するだけなので +演算子でOK
|
☓ |
| Test24 ループ使用 String変数使用 ループの【中】でString変数定義 足していく系 |
☓ | ○ ループの中で毎回連結するなら StringBuilderを使いましょう
|
| Test25 ループ使用 文字列使用 --- 代入系 |
○ Test21と同じく、固定値を代入するだけなので +演算子でOK
|
☓ |
| Test26 ループ使用 文字列使用 --- 足していく系 |
☓ | ○ ループの中で毎回連結するなら StringBuilderを使いましょう
|
さいごに、

それは処理速度です
今回の記事はバイトコードでのnewの位置や数に着目しましたが、処理速度も重要な要素です
newでインスタンス作成→解放が処理コストかかるはずなので、newの数が多いと処理時間もかかるはずですが、
とは言え、処理速度が気になる場合には今回のようにまずバイトコードを見た上で、処理時間を計測するとよりよりソースコードになるでしょう
今回見た内容はJava8の場合です
将来的にどうなるかは分かりません
どんな場合であっても、バイトコードが見られるならば、自分の目で確認すればいいだけのことです
javapを使ってバイトコードを見ることを覚えてください
個人的にJavaに対する感想は...なんか分かりづらいんですよねぇ~
+演算子とStringBuilderを比較するというのが、なんか対称性がなくて、かなり変な感じがします(←この感覚分かる人には分かるでしょうけど、分からん人には分かんないですよねwww)
毎回毎回バイトコードを見るわけにはいかないですけど、ちょっとややこしいところはバイトコード見たり処理速度を見たりしましょう
あと、Javaだけじゃないですけど、プログラミングをする場合、コンパイラが最適化してくれる場合はその最適化が効くような書き方をすると良いですよ
C#はそういう思想だったはずですよね
今回はここまで!
プログラミング のレッスンに興味がある方、レッスン内容を聞いてみたい方、なんなりとお問い合わせください。
無料体験レッスンもありますのでお気軽にどうぞ!!!
