AIZU ONLINE JUDGE の教材を使って勉強していきます
文字列結合
-
文字列は演算子で結合できる
result += "bar";
-
builder.append("bar");
//めっちゃ早い
- + で文字列を結合すると、元の文字列、連結する文字列、結果文字列の3個のString文字列を生成しているのでガベージコレクションの増大に。。
- 元の文字列、連結する文字列の
"ABC"
"DEF"
は両方メモリのある領域に確保されていて - +するとメモリ領域に
"ABCDEF"
は新しく別の領域に確保されてる - 確保しながら足していくというコストのかかるoutputになっている。。。
- 元の文字列、連結する文字列の
- →StringBuilderクラスのappendメソッドを使うと、一定のサイズを確保した可変長の文字列を表すので、確保した領域で文字列を自由に変更できる
- appendは何をしたいかのみ蓄えて最後一回のみ結合するということ
-
"ABC"
"DEF"
"GHI"
足したいものを蓄えて、最後一回のみ結合 "ABCDEFGHI"
-
- appendは何をしたいかのみ蓄えて最後一回のみ結合するということ
- →インスタンスの生成・破棄が少ない!
- 最新のJavaでは+ 演算子は内部的にStringBuilderに変換されるので単発の文字列連結の場合+演算子でOK
時間比較
100000文字連結した結果、stringBuilderが7msで圧勝!
import java.util.Date;
public class Main {
public static void main(String[] args) { new Main().run(); }
private void run(){
long startTime = getNow();
String hoge = "";
for (int i= 0; i < 100000; i++){
hoge = hoge + "mohu";
}
long elapse = getNow() - startTime;
System.out.println("elapse "+ elapse ); //2716ms
}
//Dateで今の時間をとる
private long getNow(){
return new Date().getTime();
}
}
import java.util.Date;
public class Main {
public static void main(String[] args) { new Main().run(); }
private void run(){
long startTime = getNow();
StringBuilder stringBuilder = new StringBuilder();
for (int i= 0; i < 100000; i++){
stringBuilder.append("mohu");
}
long elapse = getNow() - startTime;
System.out.println("elapse "+ elapse ); //7ms
}
//Dateで今の時間をとる
private long getNow(){
return new Date().getTime();
}
}
複数の Hello World の出力
1000 個の "Hello World" を出力するプログラムを作成して下さい。
- 注意:AOJはJava9より下位JDKを使って動作しているので型推論varは動作しない(①)
- 変数名(symbol) builderが定義されていないというコンパイルエラーになる
- Aizu Online ではコンパイルエラーだと [CE]
//①AOJでは動かないが正しいコード
//cannot find symbol var builder = new StringBuilder();
public class Main{
public static void main(String[] args){
var builder = new StringBuilder();
for (var i=0; i<1000; i++){
builder.append("Hello World\n");
}
var result = builder.toString();
System.out.println(result);
}
}
//②AOJで動きます
public class Main {
public static final int BIG_NUM = 2000000000;
public static final int MOD = 1000000007;
public static void main(String[] args) {
StringBuilder ans = new StringBuilder();
for(int i = 0; i < 1000; i++){
ans.append("Hello World\n");
}
System.out.print(ans.toString());
}
}
BufferedReaderとScannerの違い
- Scannerは遅いしメモリを食う問題。。。
- 高速化が必要な場合はBufferedReader.readLineで行ごとに読み込む
- 比較
- BufferedReaderの方がScannerよりパフォーマンスが優れている
-
BufferedReaderは文字列しか受け取れないがScannerは数値も直接受け取れる
- BufferedReader数値を扱いたい場合は、文字列を受け取ったあとに数値に変換
- ScannerはnextInt()メソッドを使うことで数値を直接受け取れる
-
BufferedReaderはチェック例外の対処が必要(IOException)だが、Scannerは不要
- BufferedReaderはチェック例外の対処(try-catch文など)が必要
テストケースの出力
オンラインジャッジでは、提出されたプログラムが複数の入力データそれぞれに対して正しい出力を行っているかを判定するために、1つの入力データファイルに複数のデータセットが含まれているものがあります。この問題は、そのようなデータセットを処理するための練習問題です。
1つの整数 x を読み込み、それをそのまま出力するプログラムを作成して下さい。
Output 各データセットごとに、以下の形式で x を出力して下さい:
Case i: x
//実行時間18s
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int i=0;
while(true){
i++;
int k = Integer.parseInt(br.readLine());
if(k == 0){break;}
System.out.println("Case "+i+": "+k);
}
}
}
//実行時間31s
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner in = new Scanner(System.in);
for(int i=1;;i++){
int num=in.nextInt();
if(num==0)
break;
System.out.println("Case "+i+": "+num);
}
}
}