Ch7. StringBuilder/Stringクラスのメソッド
String#substring
substring
メソッドに限らず、文字列の範囲を指定するメソッドでRubyとは異なる派に指定の仕方をする。
(0) A (1) B (2) C (3) D (4) E (5) F (6)
このように文字列の前端を0と設定し、文字と文字の間に番号を振る。 substringメソッドに渡された2つの数値は、この文字と文字の間に付されたindexを指し示すことになる。
String#replace
Rubyにもreplace
メソッドがあるが、文字列そのものを置き換えるメソッドだった。
Javaのreplaceメソッドは指定された文字列に当てはまる全ての文字列を置き換える。先頭だけを置き換えたい場合replaceFirst
というメソッドが別途用意されている。
(ちなみにJavaScriptではreplace
が当てはまる先頭だけを置き換える。Rubyではsub
が該当する。)
なお、replaceAll
はreplace
とほぼ同じ動きをするものの正規表現に対応しているため、replace
の仕様が推奨されている模様。
時計仕掛けのトマト:JavaのreplaceとreplaceAllの違い
String#split
splitに限らず、Java Silverでは正規表現に関する出題もされるようなので再度インプットしておく。
特に、\d
とか\s
など、文字を使った正規表現を【定義済み文字クラス】という特別な名前で呼ぶらしい。
正規表現\w
は【単語構成文字】なので小文字・大文字・アンダーバー・数字だけが対象になる。.
などは対象範囲とならない。
正規表現のパターンはJavaでは文字列で渡すため、エスケープを避けるためにスラッシュを2回連続させてやる必要がある。(その点、Rubyは文字列で渡す必要が無かったので楽だった。)
String str = "A. B. C. D."; String[] array = str.split(".\\s"); for(String s: array) { System.out.println(s); //'A' 'B' 'C' 'D' }
String#concat
StringBuilderのappend
はStringのconcat
と同じ動き。
StringBuilderからconcat
を呼んだりすることは出来ないことに注意する。(StringBuilder#appendについてはこの後詳しく記述する。)
またString#concatは+
を利用した文字列連結とほぼ同じである。
しかし、nullの文字列に対する文字列連結の際にだけ少し異なる挙動を見せる。
String st2 = null; System.out.println(st2);//'null' //System.out.println(st2.length());//'Exception in thread "main" java.lang.NullPointerException' //st2.concat("Tokyo");//'Exception in thread "main" java.lang.NullPointerException' st2 += "Yokohama"; System.out.println(st2);//'nullYokohama' String st3 = null; //st3.concat("Odawara");//'Exception in thread "main" java.lang.NullPointerException' String st6 = null; st6 = st6 + "Numazu"; System.out.println(st6);//'nullNumazu'
3行目からわかるように、null
を文字列の変数に代入しても、"null"という文字列が代入されているわけではない。
しかし、+=
及び+
を利用した文字列連結を行おうと"null"という文字列に対する連結が行われる。
4行目・8行目からもわかる通り、concat
はnullの文字列に対しては行えない。(Stringオブジェクトが存在しないので、それはそう。)
一方+
を利用した文字列連結は可能なので、こちらの利用の方が安全だろう。
StrinbBuilder#capacity
StringBuilderはStringと異なり、常に変更が発生することを前提にオブジェクトが設計されている。 StringBuilderでは常に現在の文字列の長さ+16字分の長さのメモリを確保している。
オブジェクトが変更されるたびに16文字分を追加で確保しているということで、以下のサンプルコードで挙動が実感できる。
StringBuilder sb = new StringBuilder(); System.out.println(sb.capacity());//'16' sb.append("Yokohama"); System.out.println(sb);//'Yokohama' System.out.println(sb.capacity());//'16'
StringBuilder#append
StringBulderのappendは強力なオーバーロードで、多くの型のオブジェクトを文字列型に変換して連結できる。
一般的なオブジェクトに対してはtoString
が呼ばれ、プリミティブ型とchar[]
に対しても文字列型に返却された値が連結される。
このような豊富な型に対する対応は通常のString型(のconcat
)では行われない。
//String st1 = "Helo".concat(true); //String st3 = "Helo".concat(new char[]{'w','o','r','l','d'}); //String st1 = "Helo".concat(new TestClass()); StringBuilder st4 = new StringBuilder("Hello").append(true); StringBuilder st5 = new StringBuilder("Hello").append(new char[]{'w','o','r','l','d'}); System.out.println(st5);//'Helloworld'
更にchar[]のappend
に対しては配列の要素の区間を指定することも可能。範囲指定の方法はString#substring
と同じ
StringBuilder#insert
insertに対して、自身の長さを超える位置は指定できない。(飛び石の文字列連結は出来ない。) ただし、飛び石の連結が発生しても例外が発生するわけではない。
StringBuilder st7 = new StringBuilder(); st7.insert(0, "Hello"); System.out.println("st7 :" + st7);//'st7 :Hello' StringBuilder st8 = new StringBuilder(); st7.insert(1, "HelloWorld"); System.out.println("st8 :" + st8);//'st8 :' StringBuilder st9 = new StringBuilder(); st7.insert(3, "HelloWorld!!!"); System.out.println("st9 :" + st9);//'st9 :'
StringBuilder#deleteCharAt
範囲指定の方法についてString#substring
の例を示してきたが、文字列のindexに従って素直に指定できるメソッドも存在する。