Javaでの文字列処理。 パートI:String、StringBuffer、StringBuilder

エントリー



Javaでの文字列処理について何を知っていますか? これらの知識はどれくらいあり、どれほど深く関連性がありますか? 言語のこの重要で基本的でよく使用される部分に関連するすべての問題を整理するために私と一緒に試してみましょう。 私たちの小さなガイドは2つの出版物に分かれています。



  1. String、StringBuffer、StringBuilder(ストリング実装)
  2. パターン、マッチャー(正規表現)


文字列のJava実装は、 StringStringBufferStringBuilderの 3つの主要なクラスで表されます。 それらについて話しましょう。



ひも



文字列は、一連の文字を表すオブジェクトです。 Java文字列を作成および操作するために、プラットフォームはpublic final(サブクラスを持つことはできません)クラスjava.lang.Stringを提供します 。 このクラスは不変です-Stringクラスの作成されたオブジェクトは変更できません。 メソッドにはこのオブジェクトを変更する権利があると思うかもしれませんが、これは正しくありません。 メソッドは、操作の結果が保存される新しい行のみを作成して返すことができます。 行の不変性は多くの可能性を提供します:





作成



いくつかの方法でStringクラスのオブジェクトを作成できます。



1.文字列リテラルの使用:


String habr = "habrahabr";
      
      





文字列リテラルは、二重引用符で囲まれた一連の文字です。 文字列リテラルを使用するときはいつでも、コンパイラはこのリテラルの値でオブジェクトを作成することを理解することが重要です。



 System.out.print("habrahabr"); //      
      
      





2.コンストラクターの使用:


 String habr = "habrahabr"; char[] habrAsArrayOfChars = {'h', 'a', 'b', 'r', 'a', 'h', 'a', 'b', 'r'}; byte[] habrAsArrayOfBytes = {104, 97, 98, 114, 97, 104, 97, 98, 114}; String first = new String(); String second = new String(habr);
      
      





文字列のコピーが明示的に必要でない場合、文字列は不変であるため、これらのコンストラクタの使用は望ましくなく、必要ありません。 このように新しい施設を継続的に建設すると、生産性が低下する可能性があります。 文字列リテラルを使用して、それらを同様の初期化に置き換えることをお勧めします。



 String third = new String(habrAsArrayOfChars); // "habrahabr" String fourth = new String(habrAsArrayOfChars, 0, 4); // "habr"
      
      





コンストラクターは、文字の配列を使用して文字列オブジェクトを形成できます。 配列がコピーされ、静的メソッドcopyOfcopyOfRangeArraysクラスの使用(それぞれ、 配列全体とその部分(2番目と3番目のコンストラクターパラメーターが指定されている場合))に使用され、次に、 System.arraycopyのプラットフォーム依存の実装を使用します。



 String fifth = new String(habrAsArrayOfBytes, Charset.forName("UTF-16BE")); //      "桡扲慨慢 "
      
      





バイト配列を使用して文字列オブジェクトを作成することもできます。 さらに、 エンコードを担当するCharsetクラスにパラメーターを渡すことができます。 配列は、指定されたエンコーディングを使用してデコードされ(指定されていない場合、オペレーティングシステムのエンコーディングに応じてCharset.defaultCharset()が使用されます)、さらに、結果の文字配列がオブジェクトの値にコピーされます。



 String sixth = new String(new StringBuffer(habr)); String seventh = new String(new StringBuilder(habr));
      
      





最後に、 StringBufferオブジェクトStringBuilderオブジェクト 、その値( getValue() )および長さ( length() )を使用して、文字列オブジェクトを作成するコンストラクター。 これらのクラスについては、後ほど詳しく説明します。



Stringクラスの最も一般的に使用されるコンストラクターの例を示します。実際には15があります(そのうち2つは非推奨としてマークされています )。



長さ



各行の重要な部分はその長さです。 アクセサメソッド length()を使用してStringオブジェクトにアクセスすると、 文字列内の文字数を返します。たとえば、次のようになります。



 public static void main(String[] args) { String habr = "habrahabr"; //    int length = habr.length(); //        'h'  "habrahabr" char searchChar = 'h'; boolean isFound = false; for (int i = 0; i < length; ++i) { if (habr.charAt(i) == searchChar) { isFound = true; break; //   } } System.out.println(message(isFound)); // Your char had been found! // , ,    indexOf System.out.println(message(habr.indexOf(searchChar) != -1)); // Your char had been found! } private static String message(boolean b) { return "Your char had" + (b ? " " : "n't ") + "been found!"; }
      
      





連結



連結は、文字列を結合する操作であり、新しい文字列を返します。これは、2番目の行と最初の行の終わりを結合した結果です。 Stringオブジェクトの操作は、次の2つの方法で実行できます。



1. concatメソッド


 String javaHub = "habrhabr".concat(".ru").concat("/hub").concat("/java"); System.out.println(javaHub); //  "habrhabr.ru/hub/java" //     concat private static String message(boolean b) { return "Your char had".concat(b ? " " : "n't ").concat("been found!"); }
      
      





concatメソッド文字列を変更ず、現在のパラメーターをマージしてパラメーターとして渡した結果として新しいストリングを作成するだけであることを理解することが重要です。 はい、メソッドは新しいStringオブジェクトを返すため、このような長い「チェーン」が可能です。



2.オーバーロードされた演算子 " + "および " + = "


 String habr = "habra" + "habr"; // "habrahabr" habr += ".ru"; // "habrahabr.ru"
      
      





これはJavaの数少ないオーバーロード演算子の1つです。この言語では、カスタムクラスのオブジェクトのオーバーロード操作が許可されていません。 +演算子はconcatメソッドを使用しません。ここでは次のメカニズムが使用されます。



 String habra = "habra"; String habr = "habr"; //     String habrahabr = habra + habr; //     String habrahabr = new StringBuilder()).append(habra).append(habr).toString(); //    StringBuffer
      
      





一度だけマージする必要がある場合は、 concatメソッドを使用します。他の場合は、「 + 」演算子またはStringBuffer / StringBuilderを使用することをお勧めします。 また、オペランドの1つがnullである場合、NPE( NullPointerException )を取得することは、「 + 」または「 + = 」演算子では不可能であることに注意してください。



 String string = null; string += " habrahabr"; // null   "null",   "null habrahabr" string = null; string.concat("s"); //   NullPointerException
      
      





書式設定



Stringクラスは、フォーマットされた文字列を作成する機能を提供します。 静的なフォーマットメソッドはこれに責任があります、例えば:



 String formatString = "We are printing double variable (%f), string ('%s') and integer variable (%d)."; System.out.println(String.format(formatString, 2.3, "habr", 10)); // We are printing double variable (2.300000), string ('habr') and integer variable (10).
      
      





方法



さまざまな方法のおかげで、文字列とその文字を操作することができます。 Oracleには文字列の操作比較に関する優れた記事があるため、ここでそれらを説明することは意味がありません。 また、 ドキュメントは常に手元にあります。 Java 8で登場した新しい静的結合メソッドに注目したかったのです。今度は、セパレーター(クラスjava.lang.StringJoinerが追加され、それを担当します)を使用して複数の行を1つにまとめることができます



 String hello = "Hello"; String habr = "habrahabr"; String delimiter = ", "; System.out.println(String.join(delimiter, hello, habr)); //   System.out.println(String.join(delimiter, new ArrayList<CharSequence>(Arrays.asList(hello, habr)))); //    "Hello, habrahabr"
      
      





Java 8でのクラスの変更はこれだけではありません。Oracleは、 Stringコンストラクター(バイト[]、*)およびgetBytes()メソッドのパフォーマンスの改善を報告しています。



変換



1.行ごとの数


 int integerVariable = 10; String first = integerVariable + ""; //     String second = String.valueOf(integerVariable); //    valueOf  String String third = Integer.toString(integerVariable); //   toString -
      
      





2.番号の行


 String string = "10"; int first = Integer.parseInt(string); /*    (primitive type)   parseX  -,  Xxx -      ( parseInt) */ int second = Integer.valueOf(string); //   wrapper    
      
      







StringBuffer



行は不変であるため、頻繁に変更すると新しいオブジェクトが作成され、貴重なメモリが消費されます。 この問題を解決するために、 java.lang.StringBufferクラスが作成されました。これにより、文字列の変更をより効率的に行うことができます。 クラスはmutable 、つまりmutableです-文字列の内容を変更する場合に使用します。 StringBufferは、必要なすべてのメソッドが同期されているため、マルチスレッド環境で使用できます。



作成



クラスStringBufferのオブジェクトを作成するには、4つの方法があります。 各オブジェクトには独自の容量があり、これが内部バッファの長さを担当します。 内部バッファに格納されている文字列の長さがこのバッファのサイズ( capacity )を超えない場合、新しいバッファ配列を割り当てる必要はありません。 バッファがオーバーフローすると、自動的に大きくなります。



 StringBuffer firstBuffer = new StringBuffer(); // capacity = 16 StringBuffer secondBuffer = new StringBuffer("habrahabr"); // capacity = str.length() + 16 StringBuffer thirdBuffer = new StringBuffer(secondBuffer); //  -  ,   CharSequence StringBuffer fourthBuffer = new StringBuffer(50); //  capacity
      
      





修正



ほとんどの場合、 StringBufferを使用して、サブストリングの追加 、挿入、 削除を繰り返し実行します 。 ここでは、すべてが非常に単純です。たとえば、次のとおりです。



 String domain = ".ru"; //     String  StringBuffer buffer = new StringBuffer("habrahabr"); // "habrahabr" //     buffer.append(domain); // "habrahabr.ru" //   buffer.delete(buffer.length() - domain.length(), buffer.length()); // "habrahabr" //         insert buffer.insert(buffer.length(), domain); // "habrahabr.ru"
      
      





StringBufferを操作する他のすべてのメソッドは、 ドキュメントに記載されています



StringBuilder



StringBuilderは、可変の文字シーケンスを表すクラスです。 このクラスはJava 5で導入され、 StringBufferと完全に同一のAPIを備えています。 唯一の違いは、 StringBuilderが同期されないことです。 これは、マルチスレッド環境での使用が望ましくないことを意味します。 したがって、マルチスレッドを使用する場合はStringBufferが理想的です 。そうでない場合は、ほとんどの実装ではるかに高速に動作するStringBuilderを使用します 。 これら2つのクラスの速度を比較する小さなテストを作成します。



 public class Test { public static void main(String[] args) { try { test(new StringBuffer("")); // StringBuffer: 35117ms. test(new StringBuilder("")); // StringBuilder: 3358ms. } catch (java.io.IOException e) { System.err.println(e.getMessage()); } } private static void test(Appendable obj) throws java.io.IOException { //      long before = System.currentTimeMillis(); for (int i = 0; i++ < 1e9; ) { obj.append(""); } //      long after = System.currentTimeMillis(); //   System.out.println(obj.getClass().getSimpleName() + ": " + (after - before) + "ms."); } }
      
      





ご清聴ありがとうございました。 この記事があなたが何か新しいことを学ぶのを助け、これらの問題のすべてのギャップを取り除くことにつながることを願っています。 追加、説明、批判はすべて歓迎します。



All Articles