サーチ…


前書き

文字列( 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 SE 7

Java 7より前のJavaのリリースでは、文字列プールは "PermGen"と呼ばれるヒープの特別な部分に保持されていました。この部分はたまにしか収集されませんでした。

Java SE 7

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 SE 7

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)

foonull場合、 foo.equals("baz")NullPointerExceptionをスローしnull"baz".equals(foo)falseと評価されfalse

Java SE 7

より読みやすい別の方法は、 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文字列の特定の文字の大文字と小文字を変更するには、以下のアルゴリズムを使用できます。

ステップ:

  1. 文字列を宣言します。
  2. 文字列を入力します。
  3. 文字列を文字配列に変換します。
  4. 検索する文字を入力します。
  5. 文字を文字配列に検索します。
  6. 見つかった場合は、文字が小文字か大文字かを確認します。
    • 大文字の場合は、文字のASCIIコードに32を追加します。
    • 小文字の場合は、文字のASCIIコードから32を引いてください。
  7. 文字配列から元の文字を変更します。
  8. 文字配列を文字列に戻します。

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番目のパラメーターから減算して文字列の長さを予測することです。

Java SE 7

JDK <7u6バージョンでは、 substringメソッドは、元のStringと同じバッキングchar[]を共有するStringをインスタンス化し、結果の開始および長さに内部offsetおよびcountフィールドを設定します。そのような共有はメモリリークを引き起こす可能性があります。これは、 new String(s.substring(...))を呼び出してコピーを強制的に作成することで防ぐことができます。その後、 char[]はガベージコレクションされます。

Java SE 7

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)Stringnあなたが取得したい文字のインデックスであります

注:インデックスn0から開始しているので、最初の要素はn = 0になります。

プラットフォームに依存しない改行

新しいラインセパレータはプラットフォームからプラットフォームまで変化(例えばので\n Unixライクなシステムまたは上の\r\n Windows上で)それにアクセスするためのプラットフォームに依存しない方法を持っていることがしばしば必要です。 Javaでは、システムプロパティから取得できます。

System.getProperty("line.separator")
Java SE 7

新しい行区切り記号が非常に一般的に必要なので、上記のコードとまったく同じ結果を返すショートカットメソッドの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分割することもできます。

StringTokenizerString.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

区切り文字で文字列を結合する

Java SE 8

ストリングの配列は、静的メソッド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}"

文字列の反転

文字列を逆にして逆向きにすることができます。

  1. StringBuilder / StringBuffer:

     String code = "code";
     System.out.println(code);
    
     StringBuilder sb = new StringBuilder(code); 
     code = sb.reverse().toString();
    
     System.out.println(code);
    
  2. 文字配列:

    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

Javaヒープと文字列プールの図二重引用符を使用して文字列を作成すると、Stringプール内の同じ値を持つStringが最初に検索されます。見つかった場合は、参照を返します。プール内に新しいStringを作成してから参照を返します。

しかし、new演算子を使うと、Stringクラスはヒープ空間に新しいStringオブジェクトを作成します。 intern()メソッドを使ってプールに入れたり、同じ値を持つ文字列プールから他のStringオブジェクトを参照したりすることができます。

Stringプール自体もヒープ上に作成されます。

Java SE 7

Java 7より前では、 String リテラルは固定サイズのPermGenのメソッド領域のランタイム定数プールに格納されていました。

StringプールもPermGenいました。

Java SE 7

RFC:6962931

JDK 7では、インターネットされた文字列は、永続的なJavaヒープ生成では割り当てられなくなりましたが、アプリケーションによって作成された他のオブジェクトとともに、Javaヒープの主要部分(若い世代および古い世代) 。この変更により、メインJavaヒープに多くのデータが格納され、永続的な世代ではデータが少なくなるため、ヒープサイズの調整が必要になることがあります。ほとんどのアプリケーションでは、この変更によりヒープ使用量の差はごくわずかですが、多くのクラスを読み込んだり、 String.intern()メソッドを大量に使用しているアプリケーションが多いほど、大きな違いが見られます。

ケース非依存スイッチ

Java SE 7

switch自体は大文字小文字を区別しないようにパラメータ化することはできませんが、絶対に必要な場合は、 toLowerCase()またはtoUpperCaseを使用して入力文字列に対して非敏感な動作をすることができます。

switch (myString.toLowerCase()) {
     case "case1" :
        ...            
     break;
     case "case2" :
        ...            
     break;
}

注意してください

  • Localeは、 変化するケースがどのように起こるかに影響します。
  • ラベルに大文字を含まないように気をつけなければなりません。実行されることはありません!


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow