序文
2016年3月に修正し、自分の仕事と毎日の学習経験に基づいてコードを最適化する必要がある理由を再検討しました。私が修正する前に、私の声明は次のようでした:
エビを食べるクジラのように、たぶん1つか2つのエビを食べることはクジラにとってあまり効果的ではありませんが、エビを食べすぎるとクジラは自然に満たされます。コードの最適化は同じです。おそらく、1つまたは2つの最適化は、コードの実行効率を改善するためにほとんど意味がありませんが、どこでもコードの最適化に注意を払うことができる限り、コードの実行効率を改善するのに非常に役立ちます。
この見解は、現在の見解では、コードの最適化の理由ですが、完全に正しいわけではありません。現在、機械技術の開発により、サーバーには多くの場合、8つのコア、16コア、64ビットCPUがあり、コードの実行効率が非常に高くなっています。 StringBuilderはStringBufferを置き換え、ArrayListはVectorを置き換えます。プロジェクトのすべてのポイントに気付いたとしても、コード操作に明らかな変更が表示されません。
コードの最適化の最も重要な役割は、不明なエラーを避けるためです。オンラインで実行されているコード中に、オンライン環境と開発環境が非常に異なり、エラーポジショニングが非常に小さな理由であるため、多くの予期しないエラーがしばしば発生します。ただし、このエラーを解決するには、最初に自己検証し、次にクラスファイルをパッケージ化して交換し、ビジネスを一時停止し、再起動する必要があります。成熟したプロジェクトの場合、最後のプロジェクトは実際に非常に大きな影響を及ぼします。つまり、ユーザーはこの期間中にアプリケーションにアクセスできません。したがって、コードを書くとき、ソースからのさまざまな詳細に注意を払う、最良の選択肢を計量し、使用することで、不明なエラーを大幅に回避し、長期的にワークロードを大幅に削減します。
コードの最適化の目標は次のとおりです。
1.コードのボリュームを減らします
2。コード操作の効率を向上させます
この記事の内容のいくつかはインターネットから来ており、いくつかは毎日の仕事と勉強から来ています。もちろん、これは重要ではありません。重要なのは、これらのコードの最適化の詳細が本当に有用であるかどうかです。その後、この記事は長い間更新されます。共有する価値のあるコードの最適化の詳細が発生している限り、この記事は随時更新されます。
コード最適化の詳細
(1)クラスとメソッドの最終的な修飾子を可能な限り指定してみてください
最終的な修飾子を備えたクラスは派生できません。 Java Core APIでは、Java.lang.Stringなど、ファイナルを適用する例がたくさんあり、クラス全体が最終的です。クラスの最終的な修飾子を指定すると、クラスが継承されるのを防ぎ、メソッドの最終的な修飾子を指定すると、メソッドがオーバーライドされないようにすることができます。クラスが最終として指定されている場合、そのクラスのすべての方法が最終的です。 Javaコンパイラは、すべての最終的な方法をインライン化する機会を探します。インラインは、Javaのランニング効率を向上させるために非常に重要です。詳細については、Javaランタイムの最適化を参照してください。この動きは、パフォーマンスを平均50%改善できます。
(2)オブジェクトを再利用してみてください
特に文字列オブジェクトを使用するために、StringBuilder/StringBufferを代わりに使用する必要があります。 Java仮想マシンは、オブジェクトの生成に時間を費やす必要があるだけでなく、これらのオブジェクトの収集と処理に時間を費やす必要がある場合もあります。
(3)可能な限りローカル変数を使用します
メソッドを呼び出すときに渡されたパラメーターと、呼び出しで作成された一時変数がスタックに保存されますが、これはより速いです。静的変数、インスタンス変数などの他の変数はすべてヒープで作成され、これは遅いです。さらに、スタックで作成された変数が終了すると、これらの内容がなくなり、追加のごみ収集は必要ありません。
(4)時間内に流れを閉じます
Javaプログラミング中は、データベース接続とI/Oストリーミング操作を実行するときは注意してください。使用後、リソースをリリースするために時間内に閉じます。これらの大きなオブジェクトを動作させると、大規模なシステムオーバーヘッドが発生し、注意が必要ない場合は深刻な結果につながります。
(5)変数の繰り返し計算を最小限に抑えます
概念を明確にするために、メソッドに1つの文がある場合でも、スタックフレームの作成、メソッドを呼び出すときのサイトの保護、メソッドの呼び出し時にサイトを復元するなど、まだ消費されています。たとえば、次の操作:
for(int i = 0; i <list.size(); i ++){...}それを置き換えることをお勧めします:
for(int i = 0、length = list.size(); i <length; i ++){...}このように、list.size()が非常に大きい場合、それは多くの消費を減らします
(6)怠zyなロード戦略を採用してみてください。つまり、必要に応じて作成してください
例えば:
string str = "aaa"; if(i == 1){list.add(str);}それを置き換えることをお勧めします:
if(i == 1){string str = "aaa"; list.add(str);}(7)慎重に異常を使用します
異常はパフォーマンスには良くありません。例外をスローするには、最初に新しいオブジェクトを作成する必要があります。 Throwableインターフェイスのコンストラクターは、FillinStackTrace()という名前のローカル同期メソッドを呼び出します。 FillinStackTrace()メソッドはスタックをチェックし、コールトレース情報を収集します。例外がスローされている限り、Java仮想マシンは、処理中に新しいオブジェクトが作成されるため、コールスタックを調整する必要があります。例外はエラー処理にのみ使用でき、プログラムの流れを制御するために使用しないでください。
(8)試してみないでください...キャッチ...ループで、それは最も外側の層に配置する必要があります
ネチズンが提唱した意見によると、これは議論する価値があると思います
(9)追加するコンテンツの長さを推定できる場合は、基礎となるレイヤーの配列に実装されているコレクションおよびツールクラスの初期長さを指定します。
たとえば、ArrayList、LinkedLlist、StringBuilder、StringBuffer、Hashmap、Hashsetなど。StringBuilderを例として取得します。
stringbuilder()//デフォルトはスペースの16文字の16文字を割り当てました
その初期化容量は、クラスのコンストラクターを介して設定できます(ここでは、上記のStringBuilderだけでなく)パフォーマンスを大幅に改善できます。たとえば、StringBuilderの長さは、現在のStringBuilderが維持できる文字の数を表します。 StringBuilderが最大容量に達すると、独自の容量が2回に増加し、2回追加されるため、StringBuilderが最大容量に達すると、新しい文字配列を作成し、古い文字配列コンテンツを新しい文字配列にコピーする必要があります。これは非常にパフォーマンスを消費する操作です。 5000文字が長さを指定せずに文字配列に保存されていると推定できる場合、5000に最も近い2のパワーは4096であり、各拡張に追加された2は2に関係なく、次のとおりです。
4096に基づいて、8194サイズの文字アレイを適用し、最大12290サイズの文字アレイを一度に追加します。最初に5000サイズの文字配列を指定できる場合は、2倍以上のスペースを保存して、元の4096文字を新しい文字配列にコピーします。
これは、メモリスペースを無駄にするだけでなく、コード操作効率も低下させます。したがって、基礎となるアレイに実装されたコレクションおよびツールクラスの合理的な初期化容量を設定することは間違っていません。これにより、即時の結果がもたらされます。ただし、アレイ +リンクリストに実装されているハッシュマップのようなコレクションは、テーブルに接続された1つのオブジェクトのみがほぼ0になる可能性があるため、推定サイズと同じように初期サイズを設定する必要はありません。2,000個の要素があると推定できる場合は、新しいハスマップ(128)と新しいハスマップ(256)に設定できます。
(10)大量のデータをコピーするときは、System.ArrayCopy()コマンドを使用します
(11)乗算および分割使用シフト操作を使用します
例えば:
for(val = 0; val <100000; val += 5){a = val * 8; b = val / 2;}シフト操作の使用はパフォーマンスを大幅に改善できます。コンピューターの下部では、ポジショニング操作が最も便利で最速であるため、次のように変更することをお勧めします。
for(val = 0; val <100000; val += 5){a = val << 3; b = val >> 1;}シフト操作は高速ですが、コードの理解が困難になる可能性があるため、対応するコメントを追加するのが最善です。
(12)ループで常にオブジェクト参照を作成しないでください
例えば:
for(int i = 1; i <= count; i ++){object obj = new object(); }このアプローチにより、カウントオブジェクトの参照がメモリに存在します。カウントが大きい場合、メモリを消費します。次のように変更することをお勧めします。
オブジェクトobj = null; for(int i = 0; i <= count; i ++){obj = new Object();}このようにして、メモリにオブジェクトオブジェクト参照は1つだけです。新しいオブジェクト()が使用されるたびに、オブジェクトオブジェクトの参照は別のオブジェクトを指しますが、メモリには1つのオブジェクトのみがあり、メモリスペースを大幅に保存します。
(13)効率とタイプチェックの考慮に基づいて、可能な限り配列を使用する必要があります。 ArrayListは、配列サイズを決定できない場合にのみ使用する必要があります。
(14)HashMap、ArrayList、およびStringBuilderを使用してみてください。スレッドの安全性が必要な場合を除き、ハッシュテーブル、ベクトル、および弦楽剤を使用することはお勧めしません。後者の3つは、同期メカニズムの使用により、パフォーマンスオーバーヘッドを持っています。
(15)配列をパブリック静的な最終的なものとして宣言しないでください
これは無意味であるため、参照を静的な最終としてのみ定義し、配列のコンテンツを自由に変更できます。配列を一般に宣言することはセキュリティの脆弱性です。つまり、アレイは外部クラスによって変更される可能性があります
(16)適切な場合に単一のケースを使用してみてください
シングルトンを使用すると、負荷の負担を減らし、荷重時間を短縮し、荷重効率を改善できますが、すべての場所がシングルトンに適しているわけではありません。簡単に言えば、シングルトンは主に次の3つの側面に適用できます。
リソースの使用を制御し、スレッドの同期を通じてリソースの同時アクセス制御インスタンスの生成を制御し、データの共有を制御するためのリソースを節約する目的を達成し、直接的な関連性を確立せずに複数の無関係なプロセスまたはスレッド間の通信を可能にします。
(17)静的変数の使用を自由に使用しないようにしてください
オブジェクトが静的として定義された変数によって参照される場合、GCは通常、オブジェクトで占められているヒープメモリをリサイクルしないことを知っておく必要があります。
パブリッククラスA {private static b b = new b(); }この時点で、静的変数BのライフサイクルはクラスAのライフサイクルと同じです。クラスAがアンインストールされていない場合、参照Bで指摘されたBオブジェクトは、プログラムが終了するまでメモリに存在します。
(18)時間内に不要なセッションをクリアします
もはやアクティブではないセッションをクリアするために、多くのアプリケーションサーバーにはデフォルトのセッションタイムアウト(通常は30分)があります。アプリケーションサーバーがより多くのセッションを保存する必要がある場合、メモリが不十分な場合、オペレーティングシステムはデータの一部をディスクに転送します。また、アプリケーションサーバーは、MRU(最近使用されている)アルゴリズムに従って、いくつかの不活性セッションをディスクにダンプすることもあり、メモリの例外が不十分である場合もあります。セッションをディスクにダンプする場合は、最初にシリアル化する必要があります。大規模なクラスターでは、シリアル化オブジェクトは高価です。したがって、セッションが不要になった場合、セッションをクリアするために、HTTPSESSIONの無効な()メソッドを時間内に呼び出す必要があります。
(19)ArrayListなどのランダムアクセスインターフェイスを実装するコレクションは、foreachループの代わりにループに最も一般的なものを使用する必要があります。
これは、JDKがユーザーに推奨しています。ランダムアクセスインターフェイスに関するJDK APIの説明は、ランダムアクセスインターフェイスの実装を使用して、高速ランダムアクセスをサポートすることを示します。このインターフェイスの主な目的は、一般的なアルゴリズムが動作を変更できるようにすることです。そうすれば、ランダムまたは継続的なアクセスリストに適用されると良好なパフォーマンスを提供できます。実際の経験により、ランダムアクセスインターフェイスを実装するクラスインスタンスがランダムにアクセスされる場合、通常のループを使用する効率は、foreachループを使用するものよりも高くなることが示されています。逆に、連続的にアクセスすると、イテレータを使用する方が効率的になります。次のコードを使用して、判断を下すことができます。
if(list instanceof randomAccess){for(int i = 0; i <list.size(); i ++){}} else {iterator <?> iterator = list.iterable(); while(iterator.hasnext()){iterator.next()}}foreachループの基礎となる実装原則はイテレーターです。JavamyntaxSugar 1:可変長さパラメーターとforeachループ原理を参照してください。したがって、文の後半は「逆に、順番にアクセスされた場合、イテレータを使用することがより効率的になります」とは、順次アクセスされるクラスインスタンスがforeachループを使用して通過することを意味します。
(20)同期メソッドの代わりに同期コードブロックを使用します
これは、マルチスレッドモジュールの記事同期ロックメソッドブロックに既に明確に述べられています。メソッド全体を同期する必要があると判断できない限り、同期コードブロックを使用して、同期する必要のないコードの同期を避けて、コード実行効率に影響します。
(21)定数を静的な最終的なものとして宣言し、資本に名前を付ける
このようにして、これらのコンテンツは、コンピレーション中に一定のプールに入れることができ、ランタイム中に生成された定数値の計算を回避できます。さらに、資本の定数の名前を命名すると、定数と変数の区別を容易にすることもできます
(22)未使用のオブジェクトを作成しないで、未使用のクラスをインポートしないでください
これは意味がありません。 「ローカル変数Iが使用されていない」と「インポートJava.utilが使用されない」というコードに表示される場合は、これらの役に立たないコンテンツを削除してください
(23)プログラム操作中に反射を使用しないでください
詳細については、リフレクションを参照してください。リフレクションは、Javaがユーザーに提供する非常に強力な機能です。強力な機能は、多くの場合、効率が低いことを意味します。プログラム操作、特にメソッドの呼び出し方法中に反射メカニズムを頻繁に使用することはお勧めしません。実際に必要な場合、示唆的なアプローチは、反射を通じてオブジェクトをインスタンス化し、プロジェクトが開始されたときにメモリに入れることです。ユーザーは、ピアと対話するときに最速の応答速度を気にかけ、ピアプロジェクトが開始するのにどれくらいの時間がかかるかは気にしません。
(24)データベース接続プールとスレッドプールを使用します
両方のプールはオブジェクトの再利用に使用され、前者は接続の開閉を頻繁に回避し、後者は頻繁な作成と糸の破壊を回避します
(25)IO操作にバッファーされた入力および出力ストリームを使用する
バッファリド入力および出力ストリーム、すなわちバッファレッドリーダー、bufferedwriter、bufferedinputStream、bufferedOutputStream。
(26)よりシーケンシャル挿入とランダムアクセスを備えたシーンにArrayListを使用し、より要素の削除と中間挿入を備えたシーンにLinkedListを使用します。
これは、ArrayListとLinkedListの原則を理解することで知られています
(27)パブリックメソッドにあまりにも多くの正式なパラメーターを許可しないでください
パブリック方法は、外の世界に提供される方法です。これらの方法をあまりにも多くの正式なパラメーターに与えた場合、2つの主な欠点があります。
オブジェクト指向のプログラミングアイデアに違反します。 Javaは、すべてがオブジェクトであることを強調しています。正式なパラメーターが多すぎて、オブジェクト指向のプログラミングのアイデアと一致しません。パラメーターが多すぎると、メソッド呼び出しのエラーが発生する可能性が増加します。
3または4を指す「多すぎる」について。たとえば、JDBCを使用してInsertStudentinfoメソッドを記述します。学生テーブルに挿入する10の学生情報フィールドがあります。これらの10のパラメーターは、挿入方法の正式なパラメーターとしてエンティティクラスにカプセル化できます。
(28)文字列変数と文字列定数が文字列定数の前で書かれている場合
これは、次のコードがある場合、比較的一般的なトリックです。
string str = "123"; if(str.equals( "123")){...}それを変更することをお勧めします:
string str = "123"; if( "123" .equals(str)){...}これは、主にヌルポインターの例外を回避できます
(29)Javaでは、if(i == 1)とif(1 == i)の間に違いはないが、読書習慣の観点からは、前者を使用することをお勧めします。
時々、「if(i == 1)」と「if(1 == i)」に違いがあるかどうかを尋ねることがありますか?これは、C/C ++で始まります。
C/C ++では、「if(i == 1)」の判断条件は有効であり、0および非0に基づいています。 0はfalseを意味し、非0はtrueを意味します。そのようなコードがある場合:
int i = 2; if(i == 1){...} else {...}c/c ++は、「i == 1」が無効であるため、0、つまりfalseで表されます。しかし、場合:
int i = 2; if(i = 1){...} else {...}プログラマが「if(i == 1)」を誤って「if(i = 1)」と書いている場合、問題が発生します。 iを内に1に割り当てます。その中のコンテンツが0ではないと判断した場合、返されるコンテンツは真ですが、私は明らかに2であり、比較された値は1で、返されるべき偽です。この状況は、C/C ++の開発で発生する可能性が非常に高いため、理解しにくいエラーがいくつか発生します。したがって、IFステートメントでの開発者の誤った割り当て操作を回避するために、IFステートメントを次のように記述することをお勧めします。
int i = 2; if(1 == i){...} else {...}このようにして、開発者が誤って「1 = I」を書き込んだとしても、C/C ++コンパイラは、可変値Iを1に割り当てることができるため、できるだけ早くチェックすることができますが、定数値1をiに割り当てることはできません。
ただし、Javaでは、C/C ++の「if(i = 1)」の構文を表示することは不可能です。この構文が記述されると、Javaはエラーをコンパイルして報告します。ただし、Javaでは、「if(i == 1)」と「if(1 == i)」の間にセマンティックな違いはありませんが、習慣を読むという点で前者を使用することをお勧めする方が良いでしょう。
(30)配列にtoString()メソッドを使用しないでください
配列にtoString()を使用して印刷されているものを見てみましょう。
int i = 2; if(1 == i){...} else {...}消す:
I@18a992f
当初の意図は、配列の内容を印刷することですが、配列の参照がnullであるため、nullポインターの例外を引き起こす可能性があります。ただし、アレイtoString()には意味がありませんが、コレクションのコンテンツはコレクションのtoString()に印刷できます。これは、コレクションの親クラスであるため、オブジェクトのtoString()メソッドが書き換えられます。
(31)範囲外の基本的なデータ型で下向きの力変換を行わない
これは望ましい結果を得ることはありません:
public static void main(string [] args){long l = 12345678901234l; int i =(int)l; System.out.println(i);}それらの一部を手に入れることを期待するかもしれませんが、結果は次のとおりです。
1942892530
それを説明してください。 JavaのLongは64ビットの8バイトなので、コンピューターの12345678901234の表現は次のとおりです。
0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010
INTタイプのデータは4バイトと32ビットです。上記の一連のバイナリデータの最初の32ビットは、低いビットから取得されます。
0111 0011 1100 1110 0010 1111 1111 0010
このバイナリの文字列は、1942892530 10進数として表されるため、上記のコンソールのコンテンツ出力です。この例から、2つの結論を導き出すことができます。
1.整数型のデフォルトデータ型はint、long l = 12345678901234lです。この数はintの範囲を超えているため、最後にLがあり、これが長いタイプ数であることを示しています。ちなみに、フローティングポイントタイプのデフォルトのタイプは2倍であるため、フロートを定義するときは、「フロートF = 3.5F」と書く必要があります。
2。次に、別の文「int ii = l + i;」を書きます。 long + intが長く、intに割り当てることができないため、エラーを報告します
(32)パブリックコレクションクラスで使用されていないデータは、時間内に削除する必要があります
コレクションクラスが公開されている場合(つまり、メソッドのプロパティではありません)、このコレクションの要素は常にそれらを指す参照があるため、自動的にリリースされません。したがって、パブリックコレクションの特定のデータが使用されず、それらが削除されない場合、パブリックコレクションが成長し続け、システムがメモリ漏れの可能性を秘めます。
(33)基本的なデータ型を文字列に変換します。基本的なデータ型.toString()は最速の方法で、その後にstring.valueof(data)が続き、data +""は最も遅いです
通常、基本的なデータ型を変換するには3つの方法があります。整数型データ、つまりtoString()、string.valueof(i)、およびi+"" 3つの方法があります。 3つの方法はどれくらい効率的ですか?テストを参照してください:
public static void main(string [] args){int looptime = 50000;整数i = 0; long starttime = system.currenttimemillis(); for(int j = 0; j <looptime; j ++){string str = string.valueof(i); } system.out.println( "string.valueof():" +(system.currenttimemillis() - starttime) + "ms"); starttime = system.currenttimemillis(); for(int j = 0; j <looptime; j ++){string str = i.tostring(); } system.out.println( "integer.tostring():" +(system.currenttimemillis() - starttime) + "ms"); starttime = system.currenttimemillis(); for(int j = 0; j <looptime; j ++){string str = i+""; } system.out.println( "i + /" /":" +(system.currenttimemillis() - starttime) + "ms");}実行中の結果は次のとおりです。
string.valueof():11msinteger.toString():5ms + "":25ms
したがって、将来、基本的なデータ型を文字列に変換する場合、toString()メソッドを使用することを優先する必要があります。その理由については、それは非常に簡単です:
String.valueOf()メソッドはInteger.toString()メソッドと呼ばれますが、呼び出す前にInteger.toString()メソッドを判断するのは短くなります。 i + ""を呼び出します。下層は、stringbuilderの実装を使用します。最初に追加方法を使用してスプライスし、次にtoString()メソッドを使用して文字列を取得します。
3つと比較して、それは明らかに最速で、最速で、最も遅いものです
(34)最も効率的な方法を使用してマップを横断する
マップを横断する方法はたくさんあります。通常、マップ内のキーと値を横断するために必要なもの。推奨された最も効率的な方法は次のとおりです。
public static void main(string [] args){hashmap <string、string> hm = new hashmap <string、string>(); hm.put( "111"、 "222"); set <map.entry <string、string >> entryset = hm.entryset(); iterator <map.entry <string、string >> iter = entryset.iterator(); while(iter.hasnext()){map.entry <string、string> entry = iter.next(); System.out.println(entry.getKey() + "/t" + entry.getValue()); }}このマップのキー値を反復したい場合は、「 Set<String> keySet = hm.keySet();"を使用する方が適切です。
(35)リソースのclose()のために個別に動作することをお勧めします
たとえば、次のようなコードがあることを意味します。
{xxx.close()を試してください。 yyy.close();} catch(例外e){...}それを変更することをお勧めします:
try {xxx.close();} catch(例外e){...} try {yyy.close();} catch(Exception E){...}少し面倒ですが、リソースの漏れを避けることができます。変更されたコードがない場合、xxx.close()が例外をスローする場合、キャッチブロックに入ると思います。 yyy.close()は実行されず、yyyリソースはリサイクルされず、常に占有されます。このようなコードが増えると、リソースハンドルが漏れている可能性があります。次の執筆方法に変更した後、XXXとYYYが何があっても閉鎖されることが保証されます。
(36)threadlocalの場合、使用前または使用後に削除する必要があります
現在、基本的にすべてのプロジェクトはスレッドプーリングテクノロジーを使用していますが、これは非常に優れています。スレッドの数を動的に構成し、スレッドを再利用できます。
ただし、プロジェクトでthreadlocalを使用する場合は、使用前または使用後に削除することを忘れないでください。これは、上記のスレッドプールテクノロジーがスレッドを再利用することであるためです。つまり、コードを実行している間、スレッドは破壊されず、次の使用を待っているためです。 ThreadLocal.ThreadLocalMapを保持しているThreadクラスの参照を見てみましょう。
/*このスレッドに関連するthreadlocal値。このマップは、threadlocalクラスによって維持されます *。 */threadlocal.threadlocalmap threadlocals = null;
スレッドが破壊されていないことは、ThreadLocal.ThreadLocalMapのデータがまだ存在することを意味します。次のスレッドがこのスレッドを再利用するとき、あなたが得るものは、あなたが望むコンテンツではなく、以前のスレッドセットのデータである可能性があります。
この問題は非常にあいまいです。この原因によって引き起こされるエラーが発生すると、関連する経験や強固な基盤なしにこの問題を見つけることは非常に困難です。したがって、コードを作成するときはこれに注意を払う必要があります。これにより、その後のワークロードが減少します。
(37)悪魔の数を一定の定義に置き換えることを忘れないでください。悪魔の数の存在は、コードの読みやすさを大幅に低下させます。文字列定数が一定の定義を使用するかどうかは、状況に依存する可能性があります。
(38)文字Lは1番と混同するのが非常に簡単であるため、長いまたは長い長さの最初の割り当てを使用している場合、小文字の代わりに大文字Lを使用している場合、この点は非常に詳細であり、注目に値します。
(39)すべての書き換え方法は、@Overrideアノテーションを保持する必要があります
これを行う理由は3つあります。
(1)この方法が親クラスから継承されていることは明らかです
(2)getobject()およびget0bject()メソッド。前者の4番目の文字は「O」であり、後者の4番目の親と子は「0」です。 @overrideアノテーションを追加すると、書き換えが成功したかどうかを直ちに判断できます。
(3)抽象クラスのメソッド署名を変更すると、実装クラスはすぐにコンピレーションエラーを報告します。
(40)JDK7で新しく導入されたオブジェクトツールクラスを使用して、オブジェクトの等しい、A.Equals(b)を比較することをお勧めします。
(41)ループ本体の文字列をスプライスするために「+」を使用しないでください。
文字列スプライシングに「+」を使用しない理由について話しましょう。方法がある場合:
public string appendStr(string orist、string ... appendstrs){if(appendstrs == null || appendstrs.length == 0){return oristr; } for(string appendstr:appendstrs){oristr += appendStr; } return oristr;}このコードをコンパイルした後、javap -cを使用して.classファイルを逆コンパイルして重要な部分を傍受します。
つまり、仮想マシンが「+」演算子に遭遇して文字列をスプライスするたびに、StringBuilderを新しいものにし、Appendメソッドを呼び出し、最後にToString()メソッドを呼び出して文字列をORISTオブジェクトに変換します。つまり、ループが何回新しいstringbuilder()が発生します。これはメモリの無駄です。
(42)RuntimeExceptionから継承されたJavaクラスライブラリで定義されているランタイム例外クラスをキャプチャしない
例外処理効率は低く、RuntimeExceptionのランタイム例外クラスのほとんどは、次のようなプログラマーによって完全に回避できます。
(43)複数のスレッドでランダムインスタンスを使用しないでください。インスタンスを共有することはスレッドセーフですが、同じ種子の競争によりパフォーマンスの低下を引き起こします。 JDK7の後、ThreadLocalRandomを使用して乱数を取得できます
同じ種子の競争がパフォーマンスの劣化を引き起こす理由を説明してください。たとえば、ランダムクラスのnextint()メソッドの実装をご覧ください。
public int nextint(){return next(32); }次の(intビット)メソッドが呼び出されます。これは保護された方法です。
保護されたint next(int bits){long oldseed、nextseed; Atomiclong Seed = this.seed; {oldseed = seed.get(); NextSeed =(OldSeed * Multiplier + Addend)&Mask; } while(!seed.compareandset(oldseed、nextseed)); return(int)(nextseed >>>(48 -bits));}そして、ここの種子はグローバル変数です:
/***この擬似ランダム数ジェネレーターに関連する内部状態。 *(このクラスのメソッドの仕様は、この値の進行中の *コンピューティングを説明しています。)
複数のスレッドが同時に乱数を取得すると、それらは同じ種子を競い合い、効率が低下します。
(44)静的クラス、シングルトンクラス、および工場クラスは、コンストラクターをプライベートに設定します
これは、外で新しいものを新しい必要がないためです。コンストラクターをプライベートに設定した後、これらのクラスがインスタンスオブジェクトを生成しないようにします。
ポストスクリプト
優れたコードは、すべての小さな最適化から生まれます。すべての詳細に注意を払うと、プログラムの実行効率を改善するだけでなく、多くの未知の問題を回避できます。
上記は、編集者によって導入された44のJavaコード最適化の提案です。それがあなたに役立つことを願っています。ご質問がある場合は、メッセージを残してください。編集者は時間内に返信します。 wulin.comのウェブサイトへのご支援ありがとうございます!