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が該当する。)

なお、replaceAllreplaceとほぼ同じ動きをするものの正規表現に対応しているため、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に従って素直に指定できるメソッドも存在する。