11


5

String内の各文字を調べて、Stringの各文字をStringとして別の関数に渡します。

文字列s = "abcdefg"; for(int i = 0; i <s.length(); i){newFunction(s.substring(i、i 1));}

または

文字列s = "abcdefg"; for(int i = 0; i <s.length(); i){newFunction(Character.toString(s.charAt(i)));}

最終結果は文字列である必要があります。 それでは、もっと速くまたはもっと効率的になるアイデアはありますか?

5 Answer


15


答えは次のとおりです。http://www.codinghorror.com/blog/archives/000061.html [それは問題ではない]。

あなたのコードをプロファイルしてください。 これはあなたのボトルネックですか?


15


いつものように:それは問題ではありません、あなたがマイクロ最適化に時間を費やすことを主張するか、あなたが本当にあなたの非常に特別な使用例のために最適化したいならば、これを試してください:

import org.junit.Assert; import org.junit.Test;

パブリッククラスStringCharTest {

// Times:// 1 ループ外での "s"の初期化// 2 ループ内の "s"の開始// 3 newFunction()は実際には文字列の長さをチェックします。

@Test //最速:237ms / 562ms / 2434ms public void testCacheStrings()例外{//すべての可能な文字列をキャッシュするString [] char2string = new String [Character.MAX_VALUE]; for(char i = Character.MIN_VALUE; i <Character.MAX_VALUE; i){char2string [i] = Character.toString(i); }

(int x = 0; x <10000000; x){char [] s = "abcdefg" .toCharArray(); for(int i = 0; i <s.length; i){newFunction(char2string [s [i]]); }}}

@Test // Fast:1687ms / 1725ms / 3382ms public void testCharToString()が例外をスローします{(int x = 0; x <10000000; x){String s = "abcdefg"; for(int i = 0; i <s.length(); i){//高速:新しいStringオブジェクトを作成しますが、配列newFunction(Character.toString(s.charAt(i)))はコピーしません。 }}}

@Test //非常に速い:1331ミリ秒/ 1414ミリ秒/ 3190ミリ秒public void testSubstring()は{{(int x = 0; x <10000000; x)}の場合は例外をスローします。 for(int i = 0; i <s.length(); i){//最速です。 内部のchar配列newFunction(s.substring(i、i 1))を再利用します。 }}}

@Test //最も遅い:2525ms / 2961ms / 4703ms public void testNewString()が例外をスローします{char [] value = new char [1];} (int x = 0; x <10000000; x){char [] s = "abcdefg" .toCharArray(); (int i = 0; i <s.length; i){value [0] = s [i]; // スロー! 配列newFunction(new String(value))をコピーします。 }}}

private void newFunction(String string){// 1文字のストリングAssert.assertEquals(1、string.length()); }

}


4


newFunction`は本当に String`を取る必要がありますか? newFunction`に char`を取らせてこれを次のようにして呼び出すことができればもっと良いでしょう:

newFunction(s.charAt(i));

そうすることで、一時的なStringオブジェクトを作成しなくて済みます。

あなたの質問に答えるには:どちらがより効率的かを言うのは難しいです。 どちらの例でも、1文字だけを含む `String`オブジェクトを作成する必要があります。 どちらがより効率的かは、あなたの特定のJava実装上でどれだけ正確に `String.substring(…​)`と `Character.toString(…​)`が実装されているかに依存します。 それを見つける唯一の方法はプロファイラーを通してあなたのプログラムを走らせてそしてどのバージョンがより多くのCPUおよび/またはより多くのメモリを使用するかを見ることです。 通常、このようなマイクロ最適化については心配する必要はありません。これがパフォーマンスやメモリの問題、あるいはその両方の原因であることがわかった場合にのみ時間をかけてください。


2


あなたが投稿した2つの断片のうち、私は言いたくないでしょう。 Will氏の意見に同意すると思いますが、コードの全体的なパフォーマンスにはほとんど関係がありません。そうでない場合は、変更を加えて、ハードウェア上のJVMでデータに対して最も速いものを判断できます。

とは言っても、最初にStringをchar配列に変換し、次にその配列に対して反復を実行したほうが、2番目のスニペットの方が優れている可能性があります。 このようにすると、すべての呼び出しの代わりにStringのオーバーヘッドが1回だけ(配列に変換されて)実行されます。 さらに、いくつかのインデックスを使用して配列をStringコンストラクタに直接渡すこともできます。これは、配列のchar _out_を取り出して個別に渡すよりも効率的です(その後、1文字の配列に変換されます)。

String s = "abcdefg";
char[] chars = s.toCharArray();
for(int i = 0; i < chars.length; i++) {
    newFunction(String.valueOf(chars, i, 1));
}

しかし、私の最初のポイントを補強するために、 `String.charAt()`の各呼び出しで実際に避けていることを見ると - それは2つの境界チェック、(遅延)ブールOR、そして追加です。 これによって目立った違いが生じることはありません。 Stringコンストラクタにも違いはありません。

基本的に、どちらのイディオムもパフォーマンスの観点からは問題ありません(どちらもすぐには明らかに非効率的になるわけではありません)。 それでも、この分野でサポートコードを再構築することで、ほぼ確実にパフォーマンスを向上させることができます(例: `newFunction`に文字列全体を取り込ませる) java.lang.Stringはこの点ではかなり最適化されています。


0


最初にString.toCharArray()を使用してソースStringから基礎となるchar []を取得し、次にnewFunctionを呼び出します。

しかし、私はJesperに同意します。あなたが文字を扱うことができて、すべてのString関数を避けることができればそれが最善であるということです…​