ホームページ  >  記事  >  Java  >  Java の改善 (13) -----文字列

Java の改善 (13) -----文字列

黄舟
黄舟オリジナル
2017-02-10 11:22:301098ブラウズ

文字列操作はコンピュータープログラミングにおいて最も一般的な動作であることが証明できます。


1. String

まず第一に、String は基本データ型ではなくオブジェクトであり、不変オブジェクトであることを明確にする必要があります。ソース コードを見ると、String クラスが Final であることがわかります (もちろん継承できません)。JDK ドキュメントを見ると、String オブジェクトを変更するほぼすべての操作で、実際には新しいクラスが作成されることがわかります。文字列オブジェクト。

String はオブジェクトなので、初期化前の値は null です。 ""、null、new String() の違いについて言及する必要があります。 null は文字列がまだ新しくないことを意味します。つまり、オブジェクトへの参照がまだ作成されておらず、メモリ空間が割り当てられていないことを意味します。ただし、"" と new String() は、文字列が新しいことを示します。内部的には空ですが、オブジェクトへの参照にはメモリ領域の割り当てが必要です。例: 空のグラス、中には空気があるので、中には何もないとは言えません。もちろん、真空、ヌル、「」にすることもできます。 "、 new String() の違いは真空と空気のようなものです。

string には非常に特別な場所があります。それが string プールです。 string オブジェクトを作成するときは、まず、文字列プールがあるかどうかを確認します。文字列プールに同じ値を持つ文字列が存在する場合は、それを作成せず、オブジェクトへの参照を文字列プールに直接入れます。このメカニズムは、効率を向上させ、メモリ領域の使用量を削減できるため、必要な場合を除き、直接割り当て (つまり、String s="aa") を使用することをお勧めします。文字列オブジェクトが作成されます (つまり、文字列 s = 新しい文字列("aa"))。

文字列の使用は次の側面にすぎません:

1. 文字列の比較

------内容が同じかどうかの判定?

CompareToIgno reCase(String int) ------- 比較するときに文字の大文字と小文字を無視します。

== ------ 内容とアドレスが同じかどうかを判断します。

equalsIgnoreCase() ------ 大文字と小文字を区別せずに内容が同じかどうかを判定します。

regionMatches() ------ 文字列の一部が同じかどうかを比較します (詳細については API を参照してください)。

2. 文字列検索

charAt(intindex) -------指定されたインデックスインデックス位置にある文字を返します。インデックス範囲は 0 から始まります。

indexOf(String str)-----文字列の先頭から str を取得し、最初に出現する位置を返します。出現しない場合は、-1 を返します。 ️ indexOf(String str, int fromIndex);-----文字列の fromIndex 番目の文字から始まる str を取得します。

lastIndexOf(String str)-----最後の出現位置を検索します。

lastIndexOf(String str, int fromIndex)----文字列の fromIndex 番目の文字から最後に出現する位置を検索します。

starWith(String prefix, int toffset)-----指定されたインデックスから始まるこの文字列の部分文字列が指定されたプレフィックスで始まるかどうかをテストします。

starWith(String prefix)------この文字列が指定されたプレフィックスで始まるかどうかをテストします。

endsWith(String suffix)------この文字列が指定されたサフィックスで終わるかどうかをテストします。

3. 文字列インターセプト

begin public String subString(intIndex)-----この文字列部分文字列の 1 つである新しい文字列を返します。 IPublic String Substring (int Beginindex, int Endindex) ------ 返される戻り文字列は、Beginindex から Endindex-1 までの文字列です。

4. 文字列置換

public String replace(char oldChar, char newChar)。

public String replace(CharSequence target,CharSequence replace)------ 原来の etarget 子配列置換を置換配列に置き換え、新しい串を返します。

public String replaceAll(String regex, String replace)------正規表現を使用して文字列を照合します。 replaceAll の最初のパラメータは正規表現であることに注意してください。私はこれで非常に苦労しました。

5. その他のメソッドについては、API を参照してください

2. StringBuffer
StringBuffer は、String と同様に、格納するために使用されます。 StringBuffer の場合、文字列の処理時に変更しても新しい文字列が生成されないため、メモリの点で String よりも優れています。使用法。

実際、StringBuffer の多くのメソッドは String クラスのメソッドに似ており、それらが表す関数は、変更するときに StringBuffer 自体が変更されるのに対し、String クラスは新しいオブジェクトを生成する点を除いて、ほぼまったく同じです。これが両者の最大の違いです。

同時に、StringBuffer は = を使用して初期化することはできません。StringBuffer インスタンスを生成する必要があります。つまり、その構築メソッドを通じて初期化する必要があります。

StringBuffer の使用に関しては、追加、変更、削除などの文字列の変更に重点を置いています。 対応するメソッドは次のとおりです:

1: 指定されたコンテンツを追加します。現在の StringBuffer オブジェクトの最後では、文字列の連結と同様に、StringBuffer オブジェクトの内容が変更されます。

2. insert: このメソッドは主に StringBuffer オブジェクトにコンテンツを挿入します。

3. delete: このメソッドは主に StringBuffer オブジェクトのコンテンツを削除するために使用されます。

inStringBuilder の

StringBuilder も StringBuffer とは異なり、安全でないスレッドであるため、一般に StringBuffer よりも速度が優れています。 StringBuffer と同様、StringBuider の主な操作も追加メソッドと挿入メソッドです。どちらのメソッドも、指定されたデータを効果的に文字列に変換し、その文字列の文字を文字列ジェネレーターに追加または挿入します。

上記は String、StringBuffer、StringBuilder の簡単な紹介に過ぎません。実際には、これら 3 つの違いを明確にすることによってのみ、これらをより良く使用できるようになります。


4. String、StringBuffer、StringBuilderの正しい使い方 始めましょう 以下の表を参照してください。 :



ここで String がスレッドセーフであるかどうかについてはよくわかりません。その理由は次のとおりです。文字列は不変であり、すべての操作でその値を変更することはできません。スレッドセーフであるかどうかを判断するのは非常に困難です。しかし、スレッドが安全かどうかを主張する場合、コンテンツは不変であるため、スレッドは常に安全です。

使用に関しては、String を変更するたびに新しいオブジェクトが必要となるため、頻繁に内容を変更する必要がある文字列には StringBuffer または StringBuilder を選択するのが最善です。StringBuffer の場合、各操作は StringBuffer オブジェクトに対して実行されます。 StringBuffer は、それ自体では新しいオブジェクトを生成しないため、文字列の内容が頻繁に変更される状況に特に適しています。

ただし、すべての String 文字列操作が StringBuffer よりも遅いわけではありません。一部の特殊なケースでは、String 文字列の結合が StringBuilder オブジェクトの結合に解析されます。この場合、String の速度は StringBuffer よりも高速になります。文字列バッファ。例:

String name = ”I ” + ”am ” + ”chenssy ” ;

StringBuffer name = new StringBuffer(”I ”).append(” am ”).append( ” chenssy ”);

これら 2 つのメソッドでは、最初のメソッドが 2 番目のメソッドよりもはるかに高速であり、StringBuffer の利点がここでは失われていることがわかります。本当の理由は、JVM が何らかの最適化を行っているためです。実際、JVM の目では String name = "I am chenssy" になります。 、JVM の場合、本当に時間はかかりません。しかし、これに String オブジェクトを追加すると、JVM は元の仕様に従って String オブジェクトを構築します。

これら 3 つが使用されるシナリオは次のように要約されます (参考:「品質コードの作成: Java プログラムを改善するための 151 の提案」):

1. 文字列はあまり使用されません。 String クラスは、定数の宣言、少数の変数操作など、変化するシナリオで使用できます。

文字列バッファ 2.バッファ: 文字列操作 (スプライシング、置換、削除など) を頻繁に実行し、マルチスレッド環境で実行する場合は、XML 解析、HTTP パラメータ解析、およびカプセル化を待ちます。

3. StringBuilder: 文字列操作 (スプライシング、置換、削除など) を頻繁に実行し、マルチスレッド環境で実行する場合は、SQL ステートメントのアセンブル、JSON カプセル化などの StringBuffer の使用を検討できます。 (これら 2 つは |StringBuffer も使用しているようです)。

それらの違いの詳細については、http://www.php.cn/ を参照してください。余計な余計な贅沢は一切加えません。

5. 文字列の結合メソッド

文字列の場合、多くの場合、+ 、 concat() 、および append() メソッドの 3 つのアセンブリ メソッドが追加されています。 。これら 3 つの違いは何ですか?まず次の例を見てください:

public class StringTest {
    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void
     */
    public static void main(String[] args) {
        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";
        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }
        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");
        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";
        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }
        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");
        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");
        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }
        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}

------------
Output:
  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米



public class StringTest {    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void     */
    public static void main(String[] args) {        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}------------Output:  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米

上記の実行結果から、append() が最も速く、concat() が 2 番目であることがわかります。 、+ が最も遅いです。理由は以下の内訳をご覧ください:


(1) + 文字列を結合する方法

() StringBuilder が StringBuffer よりも高速であることはわかっていますが、なぜでしょうか。走るスピードは同じですか?主な理由は、コンパイラが append() メソッドを使用して toString() で String 文字列に追加し、変換するためです。つまり、 str += "b" は

str = new StringBuilder(str) と同等です。 .append( "b").toString();

遅い主な理由は、new StringBuilder() と toString() です。ここでは、100,000 個の StringBuilder オブジェクトが作成され、そのたびに変換する必要があります。文字列に変換すると遅くなる可能性がありますか?

(2) 文字列を結合する concat() メソッド

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    char buf[] = new char[count + otherLen];
    getChars(0, count, buf, 0);
    str.getChars(0, otherLen, buf, count);
    return new String(0, count + otherLen, buf);
    }


これは concat() のソースコードです。次のようになります。 a デジタル コピーの形式では、配列の処理が非常に高速であることがわかりますが、メソッドは次のようになります。 return new String(0, count + otherLen, buf); これにより、ルートとなる 10W の文字列オブジェクトも作成されます。遅さの原因。

(3) 文字列を結合するappend()メソッド

public synchronized StringBuffer append(String str) {    super.append(str);        return this;
    }

StringBufferのappend()メソッドは親クラスAbs tractStrを直接使用しますingBuilder の append()このメソッドのソース コードは次のとおりです。

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
        int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
        expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
    }

concat() メソッドと同様に、文字配列を処理し、それを拡張してからコピーします。ただし、最終的には返され、新しい文字列を返す代わりに、それ自体を返すことに注意してください。つまり、この 100,000 回のループ中に新しい文字列オブジェクトは生成されません。

上記の分析を通じて、適切な場所で適切な文字列結合メソッドを選択する必要がありますが、必ずしも append() メソッドと concat() メソッドを選択する必要はありません。 append() メソッドと concat() メソッドの使用がシステムの効率に本当に役立つ場合にのみ考慮します。同時に、 concat() メソッドを使用したことはありません。

上記は Java 改善章 (13)-----String の内容です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。