Java Language
文字列
サーチ…
前書き
文字列( java.lang.String
)は、プログラムに格納されているテキストです。文字列はJavaのプリミティブなデータ型ではありませんが 、Javaプログラムでは非常に一般的です。
Javaでは、文字列は変更できません。つまり、変更できません。 (クリックしてここでは不変性のより完全な説明のために。)
備考
Java文字列は不変なので、 String
を操作するすべてのメソッドは新しいString
オブジェクトを返します 。元のString
は変更されません。これには、CおよびC ++プログラマがターゲットのString
オブジェクトを変更すると予想される部分文字列および置換方法が含まれます。
コンパイル時に値が決定できない2つ以上のString
オブジェクトを連結する場合は、 String
代わりにStringBuilder
を使用します。このテクニックは、 StringBuilder
が変更可能であるため、新しいString
オブジェクトを作成して連結するよりも優れています。
StringBuffer
は、 String
オブジェクトを連結するためにも使用できます。ただし、このクラスはスレッドセーフであるように設計されており、各操作の前にミューテックスを取得するため、パフォーマンスが低下します。文字列を連結するときはスレッドセーフである必要はほとんどないので、 StringBuilder
を使用することをお勧めします。
文字列連結を単一の式として表現できる場合は、 +
演算子を使用する方がよいでしょう。 Javaコンパイラは、 +
連結を含む式をString.concat(...)
またはStringBuilder
を使用して効率的な一連の操作に変換します。 StringBuilder
明示的に使用するためのアドバイスは、連結に複数の式が含まれる場合にのみ適用されます。
機密情報を文字列に格納しないでください。誰かが実行中のアプリケーションのメモリダンプを取得できる場合、既存のString
オブジェクトをすべて見つけてその内容を読み取ることができます。これには、到達不能でガベージコレクションを待っているString
オブジェクトが含まれます。これが問題であれば、機密扱いの文字列データを処理したらすぐに消去する必要があります。これは不変なので、 String
オブジェクトではできません。したがって、機密扱いの文字データを保持するにはchar[]
オブジェクトを使用し、終了したらそれらを消去します(たとえば、 '\000'
文字で上書きするなど)。
すべての String
インスタンスは、文字列リテラルに対応するインスタンスでも、ヒープ上に作成されます。文字列リテラルに関する特別なことは、JVMは等しい(つまり、同じ文字で構成される)すべてのリテラルが単一のString
オブジェクトで表されることを保証することです(この動作はJLSで指定されています)。これは、JVMクラスローダーによって実装されます。クラスローダがクラスをロードすると、クラス定義で使用される文字列リテラルがスキャンされ、文字列プール内にこのリテラルのレコードがすでに存在するかどうかが確認されます(リテラルをキーとして使用します) 。リテラルのエントリがすでに存在する場合は、そのリテラルのペアとして格納されているString
インスタンスへの参照が使用されます。それ以外の場合は、新しいString
インスタンスが作成され、リテラル(キーとして使用される)のインスタンスへの参照が文字列プールに格納されます。 ( 文字列のインターンも参照してください)。
文字列プールはJavaヒープ内に保持され、通常のガベージコレクションの対象です。
Java 7より前のJavaのリリースでは、文字列プールは "PermGen"と呼ばれるヒープの特別な部分に保持されていました。この部分はたまにしか収集されませんでした。
Java 7では、文字列プールが「PermGen」から移動されました。
文字列リテラルは、それらを使用するメソッドから暗黙的に到達可能であることに注意してください。これは、コード自体がガベージコレクションされている場合にのみ、対応するString
オブジェクトがガベージコレクションされることを意味します。
Java 8までは、 String
オブジェクトはUTF-16 char配列(charあたり2バイト)として実装されています。 Java 9には、文字列がバイト(LATIN-1)または文字(UTF-16)としてエンコードされているかどうかを示すエンコードフラグフィールドを持つバイト配列としてString
を実装する提案があります。
文字列の比較
文字列を比較するには、Stringオブジェクトのequals
メソッドまたはequalsIgnoreCase
メソッドを使用する必要があります。
たとえば、次のスニペットは、 String
の2つのインスタンスがすべての文字で等しいかどうかを判断します。
String firstString = "Test123";
String secondString = "Test" + 123;
if (firstString.equals(secondString)) {
// Both Strings have the same content.
}
この例では、大文字と小文字を区別せずに比較します。
String firstString = "Test123";
String secondString = "TEST123";
if (firstString.equalsIgnoreCase(secondString)) {
// Both Strings are equal, ignoring the case of the individual characters.
}
ことに注意してください equalsIgnoreCase
、指定できませんLocale
。たとえば、英語で"Taki"
と"TAKI"
という2つの単語を比較すると、それらは等しいです。しかし、トルコでは、彼らは異なっています(トルコ語では、小文字のI
はı
)。このような場合、両方の文字列をLocale
小文字(または大文字)に変換し、 equals
と比較することequals
解決策です。
String firstString = "Taki";
String secondString = "TAKI";
System.out.println(firstString.equalsIgnoreCase(secondString)); //prints true
Locale locale = Locale.forLanguageTag("tr-TR");
System.out.println(firstString.toLowerCase(locale).equals(
secondString.toLowerCase(locale))); //prints false
==演算子を使用して文字列を比較しないでください
すべての文字列がインターンされていることを保証できない限り(下記参照)、 ==
または!=
演算子を使用して文字列を比較するべきではありません 。これらの演算子は実際には参照をテストし、複数のString
オブジェクトが同じStringを表すことができるので、これは間違った答えを与える可能性があります。
その代わりに、 String.equals(Object)
メソッドを使用します。このメソッドは、Stringオブジェクトをその値に基づいて比較します。詳細については、 Pitfall:==を使用して文字列を比較するを参照してください。
switch文の文字列の比較
Java 1.7以降、文字列変数をswitch
文のリテラルと比較することは可能です。 Stringがnullでないことを確認します。そうでない場合、常にNullPointerException
がスローされます。値はString.equals
(大文字と小文字を区別します)を使用して比較されます。
String stringToSwitch = "A";
switch (stringToSwitch) {
case "a":
System.out.println("a");
break;
case "A":
System.out.println("A"); //the code goes here
break;
case "B":
System.out.println("B");
break;
default:
break;
}
文字列と定数の比較
String
を定数値と比較する場合は、 equals
の左側に定数を設定して、他のStringがnull
場合にNullPointerException
ないようにすることができnull
。
"baz".equals(foo)
foo
がnull
場合、 foo.equals("baz")
はNullPointerException
をスローしnull
、 "baz".equals(foo)
はfalse
と評価されfalse
。
より読みやすい別の方法は、 Objects.equals()
を使用することObjects.equals()
。これは、 Objects.equals(foo, "baz")
両方のパラメータに対してヌルチェックを行います。
( 注:一般的にNullPointerExceptions
を回避する方が良いかどうか、または根本原因を修正する方が良いかどうかは議論の余地があります( こことここを参照してください)。
文字列の順序
String
クラスは、 String.compareTo
メソッドでComparable<String>
を実装しています(この例の最初で説明したString.compareTo
です)。これにより、 String
オブジェクトの自然順序付けが大文字小文字を区別した順序になります。 String
クラスは、大文字小文字を区別しないソートに適したCASE_INSENSITIVE_ORDER
というComparator<String>
定数を提供します。
インターナショナルストリングとの比較
Java言語仕様( JLS 3.10.6 )には、次のように記載されています。
さらに、文字列リテラルは、常に
String
クラスの同じインスタンスを参照します。これは、文字列リテラルまたはより一般的には定数式の値である文字列が、メソッドString.intern
を使用して一意のインスタンスを共有するためにインターンされるためString.intern
。 "
つまり、 ==
を使用して2つの文字列リテラルへの参照を比較することは安全です。さらに、 String.intern()
メソッドを使用して生成されたString
オブジェクトへの参照についても同様です。
例えば:
String strObj = new String("Hello!");
String str = "Hello!";
// The two string references point two strings that are equal
if (strObj.equals(str)) {
System.out.println("The strings are equal");
}
// The two string references do not point to the same object
if (strObj != str) {
System.out.println("The strings are not the same object");
}
// If we intern a string that is equal to a given literal, the result is
// a string that has the same reference as the literal.
String internedStr = strObj.intern();
if (internedStr == str) {
System.out.println("The interned string and the literal are the same object");
}
背後では、インターナショナル・メカニズムは、依然として到達可能なすべてのインターナショナル・ストリングを含むハッシュ・テーブルを維持します。 String
上でintern()
を呼び出すと、メソッドはハッシュテーブル内のオブジェクトを検索します。
- 文字列が見つかった場合は、その値が内部文字列として返されます。
- それ以外の場合は、文字列のコピーがハッシュテーブルに追加され、その文字列が内部文字列として返されます。
インターンを使用して、 ==
を使用して文字列を比較できるようにすることは可能です。しかし、これには重大な問題があります。 Pitfall - Interningの文字列を参照してください。 ==を使うことができます 。ほとんどの場合は推奨されません。
文字列内の文字の大文字/小文字の変更
String
型は、大文字と小文字の間で文字列を変換する2つのメソッドを提供します。
- すべての文字を大文字に変換する
toUpperCase
- すべての文字を小文字に変換する
toLowerCase
これらのメソッドの両方が新品同様に変換された文字列を返すString
インスタンスを:元String
ので、オブジェクトが変更されていないString
Javaで不変です。不変性の詳細についてはこれを見てください: Javaにおける文字列の不変性
String string = "This is a Random String";
String upper = string.toUpperCase();
String lower = string.toLowerCase();
System.out.println(string); // prints "This is a Random String"
System.out.println(lower); // prints "this is a random string"
System.out.println(upper); // prints "THIS IS A RANDOM STRING"
数字や句読点などの英字以外の文字は、これらのメソッドの影響を受けません。これらのメソッドは、特定の条件下で特定のUnicode文字を誤って扱う場合もあることに注意してください。
注意 :これらのメソッドはロケールに依存しており、ロケールとは独立して解釈される文字列で使用されると予期しない結果が生じることがあります。例としては、プログラミング言語識別子、プロトコルキー、 HTML
タグなどがありHTML
。
たとえば、トルコ語ロケールの"TITLE".toLowerCase()
は " tıtle
"を返します。ここで、 ı (\u0131)
はラテン小文字のDOTLESS I文字です。ロケールを区別しない文字列に対して正しい結果を得るには、 Locale.ROOT
を対応する大文字と小文字を変換するメソッド(例: toLowerCase(Locale.ROOT)
またはtoUpperCase(Locale.ROOT)
)にtoUpperCase(Locale.ROOT)
ます。
ほとんどの場合、 Locale.ENGLISH
を使用Locale.ENGLISH
ことも正しいですが、 言語の不変の方法はLocale.ROOT
です。
特殊なケーシングが必要なUnicode文字の詳細なリストは、Unicode ConsortiumのWebサイトにあります。
ASCII文字列内の特定の文字の大文字/小文字の変更:
ASCII文字列の特定の文字の大文字と小文字を変更するには、以下のアルゴリズムを使用できます。
ステップ:
- 文字列を宣言します。
- 文字列を入力します。
- 文字列を文字配列に変換します。
- 検索する文字を入力します。
- 文字を文字配列に検索します。
- 見つかった場合は、文字が小文字か大文字かを確認します。
- 大文字の場合は、文字のASCIIコードに32を追加します。
- 小文字の場合は、文字のASCIIコードから32を引いてください。
- 文字配列から元の文字を変更します。
- 文字配列を文字列に戻します。
Voila、キャラクターのケースが変更されました。
アルゴリズムのコード例は次のとおりです。
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the String");
String s = scanner.next();
char[] a = s.toCharArray();
System.out.println("Enter the character you are looking for");
System.out.println(s);
String c = scanner.next();
char d = c.charAt(0);
for (int i = 0; i <= s.length(); i++) {
if (a[i] == d) {
if (d >= 'a' && d <= 'z') {
d -= 32;
} else if (d >= 'A' && d <= 'Z') {
d += 32;
}
a[i] = d;
break;
}
}
s = String.valueOf(a);
System.out.println(s);
別の文字列内での文字列の検索
特定のString a
がString b
に含まれているかどうかを確認するには、 String.contains()
メソッドを次の構文で使用できます。
b.contains(a); // Return true if a is contained in b, false otherwise
String.contains()
メソッドを使用して、 CharSequence
がString内に見つかるかどうかを確認できます。この方法は、文字列を検索するa
文字列でb
大文字と小文字を区別した方法で。
String str1 = "Hello World";
String str2 = "Hello";
String str3 = "helLO";
System.out.println(str1.contains(str2)); //prints true
System.out.println(str1.contains(str3)); //prints false
Stringが別のString内で始まる正確な位置を見つけるには、 String.indexOf()
使用します。
String s = "this is a long sentence";
int i = s.indexOf('i'); // the first 'i' in String is at index 2
int j = s.indexOf("long"); // the index of the first occurrence of "long" in s is 10
int k = s.indexOf('z'); // k is -1 because 'z' was not found in String s
int h = s.indexOf("LoNg"); // h is -1 because "LoNg" was not found in String s
String.indexOf()
メソッドは、別のString
char
またはString
最初のインデックスを返します。このメソッドは、見つからない場合は-1
返します。
注意 : String.indexOf()
メソッドでは大文字と小文字が区別されます。
ケースを無視した検索の例:
String str1 = "Hello World";
String str2 = "wOr";
str1.indexOf(str2); // -1
str1.toLowerCase().contains(str2.toLowerCase()); // true
str1.toLowerCase().indexOf(str2.toLowerCase()); // 6
文字列の長さを取得する
String
オブジェクトの長さを取得するには、 length()
メソッドを呼び出します。長さは、文字列内のUTF-16コード単位(文字)の数に等しい。
String str = "Hello, World!";
System.out.println(str.length()); // Prints out 13
Stringのchar
はUTF-16の値です。値が0x1000以上のUnicodeコードポイント(たとえば、ほとんどのemojis)は、2つの文字位置を使用します。各コードポイントがUTF-16 char
値に収まるかどうかにかかわらず、StringのUnicodeコードポイントの数をカウントするには、 codePointCount
メソッドを使用できます。
int length = str.codePointCount(0, str.length());
Java 8の時点で、コードポイントのストリームを使用することもできます。
int length = str.codePoints().count();
サブストリング
String s = "this is an example";
String a = s.substring(11); // a will hold the string starting at character 11 until the end ("example")
String b = s.substring(5, 10); // b will hold the string starting at character 5 and ending right before character 10 ("is an")
String b = s.substring(5, b.length()-3); // b will hold the string starting at character 5 ending right before b' s lenght is out of 3 ("is an exam")
文字列をスライスし、元の文字列に文字を追加/置換するために、部分文字列を適用することもできます。たとえば、漢字を含む中国語の日付に直面しましたが、それを井戸形式の日付文字列として保存したいとします。
String datestring = "2015年11月17日"
datestring = datestring.substring(0, 4) + "-" + datestring.substring(5,7) + "-" + datestring.substring(8,10);
//Result will be 2015-11-17
部分文字列メソッドは、 String
一部を抽出します。 1つのパラメータが指定された場合、パラメータは開始であり、ピースはString
最後まで拡張されます。 2つのパラメータが与えられた場合、最初のパラメータは開始文字で、2番目のパラメータは終了直後の文字のインデックスです(インデックスの文字は含まれません)。簡単なチェック方法は、最初のパラメーターを2番目のパラメーターから減算して文字列の長さを予測することです。
JDK <7u6バージョンでは、 substring
メソッドは、元のString
と同じバッキングchar[]
を共有するString
をインスタンス化し、結果の開始および長さに内部offset
およびcount
フィールドを設定します。そのような共有はメモリリークを引き起こす可能性があります。これは、 new String(s.substring(...))
を呼び出してコピーを強制的に作成することで防ぐことができます。その後、 char[]
はガベージコレクションされます。
JDK 7u6から、 substring
メソッドは常に、元のchar[]
配列全体をコピーして、前回の定数と比較して複雑さを線形にしますが、同時にメモリリークがないことを保証します。
文字列のn番目の文字を取得する
String str = "My String";
System.out.println(str.charAt(0)); // "M"
System.out.println(str.charAt(1)); // "y"
System.out.println(str.charAt(2)); // " "
System.out.println(str.charAt(str.length-1)); // Last character "g"
文字列のn番目の文字を取得するには、単に呼び出すcharAt(n)
上String
、 n
あなたが取得したい文字のインデックスであります
注:インデックスn
は0
から開始しているので、最初の要素はn = 0になります。
プラットフォームに依存しない改行
新しいラインセパレータはプラットフォームからプラットフォームまで変化(例えばので\n
Unixライクなシステムまたは上の\r\n
Windows上で)それにアクセスするためのプラットフォームに依存しない方法を持っていることがしばしば必要です。 Javaでは、システムプロパティから取得できます。
System.getProperty("line.separator")
新しい行区切り記号が非常に一般的に必要なので、上記のコードとまったく同じ結果を返すショートカットメソッドのJava 7から利用できます。
System.lineSeparator()
注意 :新しい行区切り記号はプログラムの実行中に変更されることはほとんどないので、必要になるたびにシステムプロパティから取得するのではなく、静的最終変数に格納することをお勧めします。
String.format
を使用する%n
は、 \n
または '\ r \ n'ではなく%n
使用して、プラットフォームに依存しない新しい行区切り文字を出力します。
System.out.println(String.format('line 1: %s.%nline 2: %s%n', lines[0],lines[1]));
カスタムオブジェクトのtoString()メソッドの追加
次のPerson
クラスを定義したとします。
public class Person {
String name;
int age;
public Person (int age, String name) {
this.age = age;
this.name = name;
}
}
新しいPerson
オブジェクトをインスタンス化する場合は、次のようにします。
Person person = new Person(25, "John");
後でコード内でオブジェクトを印刷するために次のステートメントを使用します。
System.out.println(person.toString());
次のような出力が得られます。
Person@7ab89d
これは、 Person
クラスのスーパークラスであるObject
クラスで定義されたtoString()
メソッドの実装の結果です。 Object.toString()
のドキュメントには、次のように書かれています。
ObjectクラスのtoStringメソッドは、オブジェクトがインスタンスであるクラスの名前、アットマーク文字@、およびオブジェクトのハッシュコードの符号なし16進表現からなる文字列を返します。つまり、このメソッドは次の値に等しい文字列を返します。
getClass().getName() + '@' + Integer.toHexString(hashCode())
したがって、意味のある出力を得るには、 toString()
メソッドをオーバーライドする必要があります 。
@Override
public String toString() {
return "My name is " + this.name + " and my age is " + this.age;
}
これで出力は次のようになります。
My name is John and my age is 25
あなたも書くことができます
System.out.println(person);
実際、 println()
暗黙的にオブジェクトのtoString
メソッドを呼び出します。
文字列の分割
特定の区切り文字または正規表現に文字String
を分割するには、次のシグネチャを持つString.split()
メソッドを使用します。
public String[] split(String regex)
文字または正規表現の区切りは、結果の文字列配列から削除されることに注意してください。
区切り文字を使用する例:
String lineFromCsvFile = "Mickey;Bolton;12345;121216";
String[] dataCells = lineFromCsvFile.split(";");
// Result is dataCells = { "Mickey", "Bolton", "12345", "121216"};
正規表現を使用する例:
String lineFromInput = "What do you need from me?";
String[] words = lineFromInput.split("\\s+"); // one or more space chars
// Result is words = {"What", "do", "you", "need", "from", "me?"};
String
リテラルを直接分割することもできます:
String[] firstNames = "Mickey, Frank, Alicia, Tom".split(", ");
// Result is firstNames = {"Mickey", "Frank", "Alicia", "Tom"};
警告 :パラメータは常に正規表現として扱われることを忘れないでください。
"aaa.bbb".split("."); // This returns an empty array
前の例では.
すべての文字が区切り文字であるため、結果は空の配列になります。
正規表現のメタ文字である区切り文字に基づいて分割する
次の文字は、正規表現で特別な(別名メタ文字)と見なされます
< > - = ! ( ) [ ] { } \ ^ $ | ? * + .
上記のデリミタのいずれかに基づいて文字列を分割するには、 \\
使用してエスケープするか、 Pattern.quote()
使用する必要があります。
Pattern.quote()
を使う:String s = "a|b|c"; String regex = Pattern.quote("|"); String[] arr = s.split(regex);
特殊文字をエスケープする:
String s = "a|b|c"; String[] arr = s.split("\\|");
分割は空の値を削除する
デフォルトでsplit(delimiter)
は結果の配列から末尾の空の文字列を削除します。この機構をオフにするにはsplit(delimiter, limit)
値を負の値に設定してsplit(delimiter, limit)
オーバーロードsplit(delimiter, limit)
バージョンを使用する必要があります。
String[] split = data.split("\\|", -1);
split(regex)
はsplit(regex, 0)
結果を内部的に返します。
limitパラメータは、パターンが適用される回数を制御し、結果として得られる配列の長さに影響します。
制限nが0より大きい場合、パターンは最大でn - 1回適用され、配列の長さはnより大きくなく、配列の最後のエントリには最後に一致した区切り文字を超えるすべての入力が含まれます。
nが負の場合、パターンはできるだけ多くの回数適用され、配列の長さは任意です。
nが0の場合、パターンはできるだけ多くの回数適用され、配列の長さは任意で、後続の空の文字列は破棄されます。
分割StringTokenizer
split()
メソッドのほかに、 StringTokenizer
を使用して文字StringTokenizer
分割することもできます。
StringTokenizer
はString.split()
よりもさらに制限があり、使用するのが少し難しくなっています。基本的には、固定文字セット( String
として与えられる)によって区切られたトークンを引き出すために設計されています。各文字はセパレータとして機能します。この制限のため、 String.split()
の約2倍の速さString.split()
。
デフォルトの文字セットは空白です( \t\n\r\f
)。次の例では、各単語を別々に出力します。
String str = "the lazy fox jumped over the brown fence";
StringTokenizer tokenizer = new StringTokenizer(str);
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
これは印刷されます:
the
lazy
fox
jumped
over
the
brown
fence
分離には異なる文字セットを使用できます。
String str = "jumped over";
// In this case character `u` and `e` will be used as delimiters
StringTokenizer tokenizer = new StringTokenizer(str, "ue");
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
これは印刷されます:
j
mp
d ov
r
区切り文字で文字列を結合する
ストリングの配列は、静的メソッドString.join()
を使用して結合できます。
String[] elements = { "foo", "bar", "foobar" };
String singleString = String.join(" + ", elements);
System.out.println(singleString); // Prints "foo + bar + foobar"
同様に、 String.join()
はオーバーロードされたString.join()
メソッドがIterable
ます。
結合を細かく制御するには、 StringJoinerクラスを使用します。
StringJoiner sj = new StringJoiner(", ", "[", "]");
// The last two arguments are optional,
// they define prefix and suffix for the result string
sj.add("foo");
sj.add("bar");
sj.add("foobar");
System.out.println(sj); // Prints "[foo, bar, foobar]"
文字列のストリームに参加するには、 結合コレクタを使用します。
Stream<String> stringStream = Stream.of("foo", "bar", "foobar");
String joined = stringStream.collect(Collectors.joining(", "));
System.out.println(joined); // Prints "foo, bar, foobar"
接頭辞と接尾辞をここで定義するオプションもあります:
Stream<String> stringStream = Stream.of("foo", "bar", "foobar");
String joined = stringStream.collect(Collectors.joining(", ", "{", "}"));
System.out.println(joined); // Prints "{foo, bar, foobar}"
文字列の反転
文字列を逆にして逆向きにすることができます。
StringBuilder / StringBuffer:
String code = "code"; System.out.println(code); StringBuilder sb = new StringBuilder(code); code = sb.reverse().toString(); System.out.println(code);
文字配列:
String code = "code"; System.out.println(code); char[] array = code.toCharArray(); for (int index = 0, mirroredIndex = array.length - 1; index < mirroredIndex; index++, mirroredIndex--) { char temp = array[index]; array[index] = array[mirroredIndex]; array[mirroredIndex] = temp; } // print reversed System.out.println(new String(array));
文字列中の部分文字列または文字の出現を数える
org.apache.commons.lang3.StringUtilsの countMatches
メソッドは、通常、 String
内の部分文字列または文字の数をカウントするために使用されます。
import org.apache.commons.lang3.StringUtils;
String text = "One fish, two fish, red fish, blue fish";
// count occurrences of a substring
String stringTarget = "fish";
int stringOccurrences = StringUtils.countMatches(text, stringTarget); // 4
// count occurrences of a char
char charTarget = ',';
int charOccurrences = StringUtils.countMatches(text, charTarget); // 3
それ以外の場合は、標準Java APIでも正規表現を使用できます。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
String text = "One fish, two fish, red fish, blue fish";
System.out.println(countStringInString("fish", text)); // prints 4
System.out.println(countStringInString(",", text)); // prints 3
public static int countStringInString(String search, String text) {
Pattern pattern = Pattern.compile(search);
Matcher matcher = pattern.matcher(text);
int stringOccurrences = 0;
while (matcher.find()) {
stringOccurrences++;
}
return stringOccurrences;
}
文字列連結とStringBuilders
文字列の連結は、 +
演算子を使用して実行できます。例えば:
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s = s1 + s2 + s3; // abc
通常、コンパイラ実装では、 StringBuilder
含むメソッドを使用して上記の連結を実行します。コンパイルすると、コードは次のようになります。
StringBuilder sb = new StringBuilder("a");
String s = sb.append("b").append("c").toString();
StringBuilder
は、さまざまな型を追加するためのオーバーロードされたメソッドがいくつかあります(たとえば、 String
代わりにint
を追加するなど)。例えば、実装は次のように変換できます。
String s1 = "a";
String s2 = "b";
String s = s1 + s2 + 2; // ab2
次のようにします。
StringBuilder sb = new StringBuilder("a");
String s = sb.append("b").append(2).toString();
上記の例は、コード内の単一の場所で効果的に実行される単純な連結操作を示しています。連結には、 StringBuilder
単一インスタンスが含まれます。いくつかの場合、連結はループのように累積的に実行されます。
String result = "";
for(int i = 0; i < array.length; i++) {
result += extractElement(array[i]);
}
return result;
このような場合、コンパイラの最適化は通常適用されず、各反復で新しいStringBuilder
オブジェクトが作成されます。これは、単一のStringBuilder
を使用するようにコードを明示的に変換することによって最適化できます。
StringBuilder result = new StringBuilder();
for(int i = 0; i < array.length; i++) {
result.append(extractElement(array[i]));
}
return result.toString();
StringBuilder
は、16文字の空白で初期化されます。より大きな文字列を作成することが事前に分かっている場合は、あらかじめ十分なサイズで初期化して内部バッファのサイズを変更する必要はありません。
StringBuilder buf = new StringBuilder(30); // Default is 16 characters
buf.append("0123456789");
buf.append("0123456789"); // Would cause a reallocation of the internal buffer otherwise
String result = buf.toString(); // Produces a 20-chars copy of the string
多くの文字列を生成する場合は、 StringBuilder
を再利用することをお勧めします。
StringBuilder buf = new StringBuilder(100);
for (int i = 0; i < 100; i++) {
buf.setLength(0); // Empty buffer
buf.append("This is line ").append(i).append('\n');
outputfile.write(buf.toString());
}
複数のスレッドが同じバッファに書き込んでいる場合のみ、 StringBufferを使用します。これはStringBuilder
synchronized
バージョンです。しかし、通常は1つのスレッドだけがバッファに書き込むため、通常は同期せずにStringBuilder
を使用する方が高速です。
concat()メソッドの使用:
String string1 = "Hello ";
String string2 = "world";
String string3 = string1.concat(string2); // "Hello world"
これは、最後にstring2が追加されたstring1という新しい文字列を返します。次のように、concat()メソッドを文字列リテラルとともに使用することもできます。
"My name is ".concat("Buyya");
ストリングの一部を置き換える
置き換える2つの方法:正規表現または完全一致。
注:元のStringオブジェクトは変更されず、戻り値は変更されたStringを保持します。
完全に一致
単一の文字を別の単一の文字に置き換えます。
String replace(char oldChar, char newChar)
この文字列のすべてのoldCharをnewCharに置き換えた結果の新しい文字列を返します。
String s = "popcorn";
System.out.println(s.replace('p','W'));
結果:
WoWcorn
文字の並びを別の文字の並びに置き換えます。
String replace(CharSequence target, CharSequence replacement)
リテラルターゲットシーケンスと一致するこの文字列の各部分文字列を、指定されたリテラル置換シーケンスに置き換えます。
String s = "metal petal et al.";
System.out.println(s.replace("etal","etallica"));
結果:
metallica petallica et al.
正規表現
注 :グループは、 $1
ようにグループを参照するために$
文字を使用します。
すべての一致を置換する:
String replaceAll(String regex, String replacement)
指定された正規表現に一致するこの文字列の各部分文字列を、指定された置換文字列に置き換えます。
String s = "spiral metal petal et al.";
System.out.println(s.replaceAll("(\\w*etal)","$1lica"));
結果:
spiral metallica petallica et al.
最初の一致のみを置換する:
String replaceFirst(String regex, String replacement)
指定された正規表現に一致するこの文字列の最初の部分文字列を、指定された置換文字で置き換えます。
String s = "spiral metal petal et al.";
System.out.println(s.replaceAll("(\\w*etal)","$1lica"));
結果:
spiral metallica petal et al.
文字列の先頭と末尾の空白を削除する
trim()
メソッドは、先頭と末尾の空白を削除した新しいStringを返します。
String s = new String(" Hello World!! ");
String t = s.trim(); // t = "Hello World!!"
削除する空白を持たない文字列をtrim
すると、同じStringインスタンスが返されます。
trim()
メソッドには 、 Character.isWhitespace()
メソッドで使用されている概念とは異なる独自の空白の概念があります 。
コード
U+0000
U+0020
すべてのASCII制御文字は空白と見なされ、trim()
によって削除されtrim()
。これにはU+0020 'SPACE'
、U+0009 'CHARACTER TABULATION'
、U+000A 'LINE FEED'
U+0009 'CHARACTER TABULATION'
U+000A 'LINE FEED'
、U+000D 'CARRIAGE RETURN'
キャラクターだけでなく、U+0007 'BELL'
などのキャラクターも含まれます。U+00A0 'NO-BREAK SPACE'
やU+2003 'EM SPACE'
ようなUnicode空白はtrim()
によって認識されません 。
ストリングプールとヒープストレージ
多くのJavaオブジェクトと同様に、 すべての String
インスタンスはリテラルでもヒープ上に作成されます。 JVMが見つかったときString
ヒープには同等の参照を持たないリテラルを、JVMは、対応する作成String
ヒープ上にインスタンスをし、それはまた、新たに作成された参照格納するString
文字列プール内のインスタンス。同じString
リテラルへの他の参照は、ヒープ内の以前に作成されたString
インスタンスに置き換えられます。
次の例を見てみましょう:
class Strings
{
public static void main (String[] args)
{
String a = "alpha";
String b = "alpha";
String c = new String("alpha");
//All three strings are equivalent
System.out.println(a.equals(b) && b.equals(c));
//Although only a and b reference the same heap object
System.out.println(a == b);
System.out.println(a != c);
System.out.println(b != c);
}
}
上記の出力は次のとおりです。
true
true
true
true
二重引用符を使用して文字列を作成すると、Stringプール内の同じ値を持つStringが最初に検索されます。見つかった場合は、参照を返します。プール内に新しいStringを作成してから参照を返します。
しかし、new演算子を使うと、Stringクラスはヒープ空間に新しいStringオブジェクトを作成します。 intern()メソッドを使ってプールに入れたり、同じ値を持つ文字列プールから他のStringオブジェクトを参照したりすることができます。
Stringプール自体もヒープ上に作成されます。
Java 7より前では、 String
リテラルは固定サイズのPermGen
のメソッド領域のランタイム定数プールに格納されていました。
StringプールもPermGen
いました。
JDK 7では、インターネットされた文字列は、永続的なJavaヒープ生成では割り当てられなくなりましたが、アプリケーションによって作成された他のオブジェクトとともに、Javaヒープの主要部分(若い世代および古い世代) 。この変更により、メインJavaヒープに多くのデータが格納され、永続的な世代ではデータが少なくなるため、ヒープサイズの調整が必要になることがあります。ほとんどのアプリケーションでは、この変更によりヒープ使用量の差はごくわずかですが、多くのクラスを読み込んだり、
String.intern()
メソッドを大量に使用しているアプリケーションが多いほど、大きな違いが見られます。