JAVAパフォーマンスの最適化:コード操作の効率を改善するための35の小さな詳細(Javaインタビュー)

1.不変性の特性を考慮して、java8の機能開発の使用を推奨します。

注:マルチコアサーバーでの機能開発の運用効率は、コアの数と正の関係がありますが、従来のJavaコードにはこの機能がありません。

2. IDEAを開発ツールとして使用し、gitをバージョン管理ツールとして使用することをお勧めします。

注:IDEAは現在最も強力なJava開発ツールであり、その効率、パフォーマンス、インテリジェンスは現在一流です。開発者は、従来のEclipse、sts、myeclipseからアイデアへの変更の非互換性を克服する必要があります。

3. IDEAはlombokプラグインをインストールし、各エンティティクラスにlombokアノテーションを追加します:@ Data、@ Builder、

@ NoArgsConstructor、@ AllArgsConstructorを使用すると、コードを簡略化できます。デバッグにログ出力が必要なクラスに@ Slf4jアノテーションを直接追加したり、http://log.xxx()を使用してコード内のログ出力を直接呼び出すことができます。

注:lombokの主な機能は、コードを単純化することです。一部の従来のメソッドは、lombokのアノテーションを介して直接実装できます。

Lombokは説明しました:

@Data Annotation:アノテーションはクラスにあり、クラスのすべてのプロパティにgetter / setterメソッド、equalsメソッド、toStringメソッド、hashCodeメソッドを直接埋め込みます。

@ NoArgsConstructor:アノテーションはクラスにあり、引数なしの構築メソッドがクラスに埋め込まれています

@AllArgsConstructor:アノテーションはクラスにあり、フルパラメーターの構築メソッドがクラスに埋め込まれています

@ Builder:クラスにアノテーションを付け、クラスにBuilderの内部クラスを埋め込みます。このクラスはコンストラクターのデザインパターンを採用し、主な機能はインスタンスを初期化することです。

@ Slf4j:アノテーションはクラスにあり、slf4jログオブジェクトを取得するためのメソッドがクラスに埋め込まれています

関数の不変性に応じて、インスタンスを初期化するときに、新しいObjcet()メソッドを使用したり、Class.newInstance()メソッドを使用したりすることはできません。これらの初期化されたオブジェクトは柔軟性が高すぎて、最小限の権限しかありません。コードでは変更の原則は許可されていません。

上記の項目3では、lombokの@Builderアノテーションが追加されています。クラスのコンストラクターを使用して初期化し、参照の前にvalを追加します(これもlombokのアノテーションですが、@を使用する必要はありません。このアノテーションの機能は、不変性に合わせて、最終型への参照を変更するときにコンパイルすることです)

示例:val user = User.builder()。age(18).username( "xxx")。build();

4.変数を宣言するときは、それがメンバー変数であるかローカル変数であるかにかかわらず、最終型として宣言できるかどうかを検討します(基本的には、ループ本体など、コードブロックを入力する必要があります。 try-catchは不可能です)、できますfinalとして宣言されている場合は、final変更を使用します。そうでない場合は、それを実現する方法があるかどうかを検討します。そうでない場合は、妥協することしかできません。
注:不変性に準拠することに加えて、finalタイプはJVMの効率も大幅に向上させます(メモリのアドレス指定は非常に明確です)。単一の項目は効果的ではありませんが、プロジェクトには数千の変数があり、それぞれが累積的な改善の後、それは大きな改善になります。

5.階層の説明(重要):誰もがDDD(ドメイン駆動設計)の階層設計のアイデアを理解できることを願っています。
伝統的に、私たちは皆MVC階層を実行します。Mレイヤーはモデル、dao、サービスの総称であり、 Vレイヤーはビュー、レイヤー、Cはコントロールレイヤーです。このような状況に遭遇したことはありますか?コントローラーがトランザクション操作で複数のサービスを呼び出したい場合、2つの方法があります。(1)複数のサービスを直接呼び出すデータアセンブルのコントローラーがビューに戻ります。(2)大規模なサービスをカプセル化し、ビジネスを満足させるためにdaoを複数回呼び出してから、それをコントローラーに返して呼び出します。

これら2つのアプローチの結果の分析:(1)最初のアプローチ、トランザクションの問題を確実にする方法、すべてが成功した場合、それを成功と見なし、1つが失敗した場合、このトランザクションを失敗と見なし、以前の完了両方をロールバックする必要がありますが、トランザクション制御はビジネスレイヤーにあり、Springフレームワークを使用しているため、コントローラーレイヤーはSpringのトランザクションプロキシを使用できないため、最初のアプローチでは明らかにこの整合性の問題を保証できません。

(2)2番目のアプローチは、実際にはMVC階層設計を採用する主流のアプローチです。1つ目はトランザクションを確実にするため、2つ目はビジネスを確実にするために、コードの量を増やすことに他なりません。ですから、この大きなサービスの状況に戸惑いを感じますか?実は、トランザクション制御も含めたきめ細かいビジネスが必要ですが、原子性にも気を配っていますが、このビジネスは分析できますが、ビジネスではありません。 、しかし、複数のビジネスの組み合わせによって形成される「ビジネス」。実際、MVC階層設計では、いわゆる「ビジネス」ステータスはありませんが、妥協してビジネスとして扱います。

トピック:DDDレイヤードデザインのアイデアは、大きく4つのレイヤーに分かれています。

a:インフラストラクチャ層

-このレイヤーには、さまざまなutilクラス、データベース操作、キャッシュ操作、キュー操作、およびMVCのモデルやdaoなどのコンポーネント操作の他の基本要素が含まれています。

b:ドメインレイヤー(@Component)

-このレイヤーには、きめ細かいサービスが含まれています。インフラストラクチャレイヤーは、ビジネス実装のために呼び出されます。サービスレイヤーに似ていますが、サービスよりもきめ細かくなります。基本的には、サービス内の単純なCRUD操作です。

c:アプリケーション層(@Service)

-この層は、この事件で言及された「厄介なビジネス」が今置かれている場所です。この層で行うこと:1。業務はこの層で管理されます。2.ドメインレイヤーを呼び出してデータをアセンブルします。この層の機能は、インターフェイス層によって直接呼び出すことができるビジネスの複雑さをカプセル化することです。1つのステップで、インターフェイス層にロジックを書き込むことは悪い動作であり、インターフェイス層は外の世界に開かれています。シンプルであるほど良い

d:インターフェースレイヤー(@ Controller / @ RestController)

-このレイヤーの位置は、MVCのコントローラーと同等であり、外部に公開されており、アプリケーションレイヤーを呼び出してクライアントデータを返します。

上記の説明を通して、ある程度の理解があるはずです。私が言ったことは、比較的単純で明確であり、MVCとの類推によって実行されます。DDD思考の真の意味合いは、誰もがそれを掘り下げることができることを望んでいます。どんな洞察でも、私たちはそれについて一緒に話し合い、一緒に進歩することができます。

上記からわかるように、ドメイン層はシステム全体で「最も太い」ものであるため、DDD(Domain-Driven-Design)と呼ばれます。システム全体の通常の操作はドメインによって駆動され、このように設計されています。利点はシステムのスケーラビリティにあり、スケーラビリティの向上は非常に大きいです。

パッケージの命名規則:パッケージの命名に大文字は使用できません。理由は、gitが大文字と小文字を区別しないためです。Javaは異なるパッケージを考慮しますが、gitは同じパッケージを考慮してコードを送信します。コードをマージするときに問題が発生します。また、下線は表示されません。

コードの最適化は非常に重要なテーマです。一部の人々はそれが役に立たないと感じるかもしれません。いくつかの小さな領域で何を変更できますか?変更はコードの効率にどのような影響を与えますか?海にいるクジラのように、小さなエビを食べるのは便利ですか?役に立たないですが、エビをもっと食べた後、クジラに餌をやる。

コードの最適化についても同じことが言えます。プロジェクトがBUGなしでできるだけ早くオンラインにすることに焦点を当てている場合は、現時点で大きなものに焦点を当てることができ、コードの詳細を注意深く磨く必要はありません。コードの開発と保守に十分な時間があれば、この時点でそれぞれを検討する必要があります。最適化できる詳細、小さな最適化ポイントの蓄積により、コードの運用効率が確実に向上します。

コード最適化の目標は

コードのサイズを小さくする

コード実行の効率を向上させる

コード最適化の詳細

1.クラスとメソッドの最後の修飾子を指定してみてください

最終修飾子を持つクラスは導出できません。JavaコアAPIには、java.lang.Stringなどの最終アプリケーションの例が多数あり、クラス全体が最終です。クラスが継承されないようにクラスの最終修飾子を指定し、メソッドがオーバーライドされないようにメソッドの最終修飾子を指定します。クラスがfinalとして指定されている場合、そのクラスのすべてのメソッドはfinalです。Javaコンパイラは、すべてのfinalメソッドをインライン化する機会を探します。インライン化は、Java操作の効率の向上に大きな影響を及ぼします。詳細については、Javaランタイムの最適化を参照してください。これにより、パフォーマンスが平均50%向上します。

2.オブジェクトを可能な限り再利用します

特にStringオブジェクトの使用では、文字列接続が発生したときに代わりにStringBuilder / StringBufferを使用する必要があります。Java仮想マシンはオブジェクトの生成に時間がかかるだけでなく、将来これらのオブジェクトをガベージコレクションして処理するのにも時間がかかる可能性があります。したがって、生成するオブジェクトが多すぎると、プログラムのパフォーマンスに大きな影響を与えます。

3.可能な限りローカル変数を使用します

メソッドが呼び出されたときに渡されたパラメーターと、呼び出しで作成された一時変数はスタックに速く保存され、静的変数、インスタンス変数などの他の変数は、より遅い速度でヒープに作成されます。さらに、スタックで作成された変数はメソッドの終了とともに削除され、追加のガベージコレクションは必要ありません。

4.時間内にストリームを閉じます

Javaプログラミングの過程では、データベース接続やI / Oストリーム操作を行う際に注意が必要です。使用後は、リソースを解放するためにそれらを時間内に閉じてください。これらの大きなオブジェクトの操作は大きなシステムオーバーヘッドを引き起こすため、少しの不注意は深刻な結果につながります。

5.変数の繰り返し計算を最小限に抑えます

概念を明確にします。メソッドに文が1つしかない場合でも、スタックフレームの作成、メソッドの呼び出し時のシーンの保護、メソッドの呼び出し時のシーンの復元など、メソッドの呼び出しにはコストがかかります。したがって、たとえば次の操作:

for(int i = 0; i <list.size; i ++){…}

次のように置き換えることをお勧めします。

for(int i = 0、int length = list.size; i <length; i ++){…}

このように、list.sizeが非常に大きい場合、多くの消費を削減します

6.遅延読み込み戦略を使用してみてください。つまり、必要に応じて作成してください。

例えば:

文字列str =“ aaa”; if(i == 1){list.add(str);}

次のように置き換えることをお勧めします。

if(i == 1){String str =“ aaa”; list.add(str);}

7.例外は注意して使用してください

異常はパフォーマンスに悪影響を及ぼします。例外をスローするには、最初に新しいオブジェクトを作成します。Throwableインターフェイスのコンストラクターは、fillInStackTraceという名前のローカル同期メソッドを呼び出します。fillInStackTraceメソッドは、スタックをチェックし、呼び出しトレース情報を収集します。処理中に新しいオブジェクトが作成されるため、例外がスローされる限り、Java仮想マシンはコールスタックを調整する必要があります。例外はエラー処理にのみ使用でき、プログラムフローの制御には使用しないでください。

8.ループ内でtry ... catch ...を使用しないでください。これは、最外層に配置する必要があります。

最後の手段を除いて。あなたが理由もなくこれを書いた場合、あなたのリーダーがより年長で強迫神経症である限り、Bachengはそのようなゴミコードを書いたことであなたを叱ります。

9.追加するコンテンツの長さが見積もることができる場合は、最下層の配列に実装されているコレクションとツールクラスの初期の長さを指定します

ArrayList、LinkedLlist、StringBuilder、StringBuffer、HashMap、HashSetなど、例としてStringBuilderを取り上げます。

(1)StringBuilder //デフォルトでは、16文字のスペースが割り当てられます

(2)StringBuilder(int size)//サイズ文字のデフォルトのスペース割り当て

(3)StringBuilder(String str)// 16文字+ str.length文字スペースがデフォルトで割り当てられます

初期容量は(上記のStringBuilderだけでなく)クラスを介して設定でき、パフォーマンスを大幅に向上させることができます。StringBuilderを例にとると、lengthは、現在のStringBuilderが保持できる文字数を表します。StringBuilderが最大容量に達すると、容量が現在の容量の2倍に増加し、2が追加されるためです。StringBuilderが最大容量に達するたびに、新しい文字配列を作成してから古い文字を追加する必要があります。新しい文字配列への配列-これは非常にパフォーマンスを消費する操作です。長さを指定せずに5000文字が文字配列に格納されていると推定できる場合、拡張ごとに2が増加しても、5000に最も近い2の累乗は4096であると想像してみてください。

(1)4096に基づいて、8194サイズの文字配列を申請します。これは、一度に12290サイズの文字配列を申請するのと同じです。最初に5000サイズの文字配列を指定できる場合は、節約できます。 2倍以上になります。スペース。

(2)元の4096文字を新しい文字配列にコピーします。

このようにして、両方のメモリスペースが無駄になり、コード操作の効率が低下します。したがって、下部の配列によって実装されるコレクションクラスとツールクラスに適切な初期容量を設定することは間違いではありません。これにより、すぐに結果が得られます。ただし、HashMapのようなコレクションは、配列+リンクリストとして実装されていることに注意してください。テーブル上の1つのオブジェクトのみを接続する可能性はほとんどないため、初期サイズを推定と同じサイズに設定しないでください。初期サイズは2のN乗に設定することをお勧めします。2000個の要素があると推定できる場合は、新しいHashMap(128)または新しいHashMap(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;}

このアプローチでは、メモリ内のオブジェクト参照がカウントされます。カウントが大きい場合、メモリが消費されます。次のように変更することをお勧めします。

Object obj = null; for(int i = 0; i <= count; i ++){ob​​j = new Object; }

この場合、メモリ内のオブジェクトオブジェクト参照は1つだけです。新しいオブジェクトが使用されるたびに、オブジェクトオブジェクト参照は別のオブジェクトを指しますが、メモリ内のコピーは1つしかないため、メモリスペースが大幅に節約されます。

13.効率と型チェックの考慮に基づいて、配列は可能な限り使用する必要があり、ArrayListは、配列のサイズを決定できない場合にのみ使用する必要があります。

14. HashMap、ArrayList、StringBuilderを使用してみてください。スレッドセーフが必要な場合を除き、Hashtable、Vector、StringBufferの使用はお勧めしません。後者の3つは、同期メカニズムを使用するため、パフォーマンスのオーバーヘッドが発生します。

15.配列をpublicstaticfinalとして宣言しないでください

これは無意味なので、参照をstatic finalとして定義するだけで、配列の内容を自由に変更できます。配列をpublicとして宣言することは、さらにセキュリティホールです。つまり、配列は外部クラスによって変更できます。

16.必要に応じてシングルトンを使用してみてください

シングルトンを使用すると、ロードの負担を軽減し、ロード時間を短縮し、ロード効率を向上させることができますが、すべての場所がシングルトンに適しているわけではありません。簡単に言えば、シングルトンは主に次の3つの側面に適しています。

(1)リソースの使用を制御し、スレッドの同期を通じてリソースへの同時アクセスを制御します

(2)インスタンスの生成を制御して、リソースを節約する目的を達成します

(3)データの共有を制御し、直接の関連付けを確立せずに、複数の無関係なプロセスまたはスレッドが通信できるようにします。

17.静的変数を自由に使用しないようにしてください

ご存知のとおり、オブジェクトが静的として定義された変数によって参照されている場合、gcは通常、次のように、このオブジェクトが占有しているヒープメモリを再利用しません。

パブリッククラスA {プライベート静的Bb =新しいB;}

このとき、静的変数bのライフサイクルはクラスAのライフサイクルと同じです。クラスAがアンロードされていない場合、参照Bが指すオブジェクトBは、プログラムが終了するまでメモリに残ります。

18.時間内に不要になったセッションをクリアします

アクティブでなくなったセッションをクリアするために、多くのアプリケーションサーバーにはデフォルトのセッションタイムアウト期間があります。これは通常30分です。アプリケーションサーバーがさらにセッションを保存する必要がある場合、メモリが不足していると、オペレーティングシステムはデータの一部をディスクに転送し、アプリケーションサーバーはMRU(最も頻繁に使用される)に従って非アクティブなセッションをディスクにダンプすることもあります。最近)アルゴリズム。メモリ不足の例外をスローすることもあります。セッションをディスクにダンプする場合は、最初にシリアル化する必要があります。大規模なクラスターでは、オブジェクトのシリアル化には非常にコストがかかります。したがって、セッションが不要になった場合は、HttpSessionのinvalidateメソッドを呼び出して、セッションを時間内にクリアする必要があります。

19. ArrayListなどのRandomAccessインターフェースを実装するコレクションは、foreachループではなく、最も一般的なforループを使用してトラバースする必要があります。

これは、JDKによってユーザーに推奨されています。JDK APIによるRandomAccessインターフェースの解釈は、次のとおりです。RandomAccessインターフェースの実装は、高速ランダムアクセスをサポートすることを示すために使用されます。このインターフェースの主な目的は、一般的なアルゴリズムがその動作を変更できるようにして、良好な結果を提供できるようにすることです。ランダムまたは連続アクセスリストに適用した場合。パフォーマンス。実際の経験では、RandomAccessインターフェイスを実装するクラスインスタンスにランダムにアクセスすると、通常のforループを使用する効率がforeachループを使用する効率よりも高くなります。逆に、順次アクセスする場合は、Iteratorを使用する方が効率的です。 。次のようなコードを使用して判断を下すことができます。

if(RandomAccessのインスタンスを一覧表示)

{for(int i = 0; i <list.size; i ++){}

}そうしないと{

Iterator <?> iterator = list.iterable; while(iterator.hasNext){iterator.next}

}

foreachループの基本的な実装原則はイテレーターです。Java構文シュガー1:可変長パラメーターとForeachループの原則を参照してください。したがって、後半の文「逆に、順次アクセスされる場合は、Iteratorを使用する方が効率的です」は、順次アクセスされるクラスインスタンスがforeachループを使用してトラバースされることを意味します。

20.同期メソッドの代わりに同期コードブロックを使用する

この点は、マルチスレッドモジュールの同期ロックメソッドブロックの記事で非常に明確に説明されています。メソッド全体を同期する必要があると判断できない場合は、同期コードブロックを使用して、同期する必要のないコードを回避してください。 。同期も実行されたため、コード実行の効率に影響がありました。

21.定数をstaticfinalとして宣言し、大文字で名前を付けます

このようにして、これらのコンテンツをコンパイル中に定数プールに入れることができ、実行時の定数値の計算と生成を回避できます。さらに、定数に大文字で名前を付けることで、定数と変数を区別することもできます。

22.未使用のオブジェクトを作成したり、未使用のクラスをインポートしたりしないでください

これは意味がありません。コードに「ローカル変数iの値が使用されていない」および「インポートjava.utilが使用されていない」が表示されている場合は、これらの不要なコンテンツを削除してください。

23.プログラム操作中にリフレクションを使用しないでください

については、リフレクションを参照してください。リフレクションは、Javaがユーザーに提供する非常に強力な関数です。強力な関数は、多くの場合、効率が低いことを意味します。リフレクションメカニズム、特にプログラムの実行中にリフレクションメカニズムを頻繁に使用すること、特にメソッドのinvokeメソッドを使用することはお勧めしません。本当に必要な場合は、クラスのリフレクションインスタンスを使用することをお勧めします。プロジェクトの開始時にリフレクションを介してロードする必要があります。オブジェクトを変換してメモリに配置します。ユーザーは、ピアと対話するときに最速の応答速度を取得することだけを気にし、ピアのプロジェクトにかかる時間を気にしません。始めること。

24、データベース接続プールとスレッドプールを使用します

これらの2つのプールはオブジェクトを再利用するために使用され、前者は接続の頻繁な開閉を回避でき、後者はスレッドの頻繁な作成と破棄を回避できます。

25.IO操作にバッファリングされた入力ストリームと出力ストリームを使用する

バッファリングされた入力および出力ストリーム、つまりBufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream。これによりIO効率が大幅に向上します。

26. ArrayListは、より順次挿入とランダムアクセスのシナリオで使用され
、LinkedListは、より多くの要素の削除と中間挿入のシナリオで使用されます。ArrayListとLinkedListの原則を理解できます。

27.パブリックメソッドにあまりにも多くの仮パラメータを持たせないでください

パブリックメソッドは、外部に提供されるメソッドです。これらのメソッドにあまりにも多くの仮パラメーターを指定すると、2つの主な欠点があります。

1.オブジェクト指向プログラミングの概念に違反します。Javaはすべてがオブジェクトであることを強調しています。形式的なパラメーターが多すぎると、オブジェクト指向プログラミングの概念に適合しません。

2.パラメータが多すぎると、必然的にメソッド呼び出しのエラー確率が高くなります。

「多すぎる」とは、3つか4つです。たとえば、JDBCを使用してinsertStudentInfoメソッドを記述します。Studentテーブルに挿入する学生情報フィールドは10個あります。これらの10個のパラメータは、挿入メソッドの正式なパラメータとしてエンティティクラスにカプセル化できます。

28.文字列変数と文字列定数が等しい場合は、文字列定数を前に記述します

次のコードがある場合、これは比較的一般的なトリックです。

String str =“ 123”; if(str.equals(“ 123”)){…}

以下を修正することをお勧めします。

String str =“ 123”; if(“ 123” .equals(str)){…}

これは主にnullポインタ例外を回避するためです

29. Javaではif(i == 1)とif(1 == i)の間に違いはありませんが、読書習慣の観点からは前者を使用することをお勧めします。

通常、誰かが「if(i == 1)」と「if(1 == i)」の間に違いがあるかどうかを尋ねます。これはC / C ++で始まる必要があります。

C / C ++では、「if(i == 1)」判定条件が確立されます。これは、0と非ゼロに基づいています。0は偽を意味し、非ゼロは真を意味します。このようなコードがある場合:

int i = 2; if(i == 1){…} else {…}

C / C ++は、「i == 1」が成り立たないと判断するため、0で表されますが、これは誤りです。しかし、次の場合:

int i = 2; if(i = 1){…} else {…}

プログラマーが注意しない場合は、「if(i == 1)」を「if(i = 1)」と書くと、問題が発生します。ifでiを1に割り当て、if判定の内容が0でない場合、戻り値はtrueですが、iが2であり、比較値が1であることは明らかであり、falseを返すはずです。この状況はC / C ++の開発で発生する可能性が高く、理解できないエラーが発生する可能性があります。したがって、開発者によるifステートメントでの誤った代入操作を回避するために、ifステートメントを次のように記述することをお勧めします。

int i = 2; if(1 == i){…} else {…}

このように、開発者が誤って「1 = i」と書き込んだ場合でも、変数にiを割り当てることはできますが、定数に1を割り当てることはできないため、C / C ++コンパイラは最初にそれをチェックアウトできます。

ただし、Javaでは、C / C ++の「if(i = 1)」構文は不可能です。この構文が記述されると、Javaはコンパイルして、「型の不一致:intからブール値に変換できません」というエラーを報告するためです。ただし、Javaの「if(i == 1)」と「if(1 == i)」は意味的には違いはありませんが、読み方の観点からは前者を使用することをお勧めします。

30.配列でtoStringメソッドを使用しないでください

配列でtoStringを使用して出力されるものを見てください。

public static void main(String args)

{int is = new int {1、2、3};

System.out.println(is.toString);

}

結果は次のとおりです。

[I @ 18a992f

配列の内容を出力することを目的としていますが、配列参照がnullであるため、nullポインター例外が発生する可能性があります。ただし、配列toStringには意味がありませんが、コレクションの親クラスAbstractCollectionsがObjectのtoStringメソッドをオーバーライドするため、コレクションの内容をコレクションtoStringに出力することは可能です。

31.範囲外の基本的なデータ型をキャストダウンしないでください

これでは、望ましい結果が得られることはありません。

public static void main(String args){long l = 12345678901234L; int i =(int)l; System.out.println(i);}

それらのいくつかを取得することを期待するかもしれませんが、結果は次のとおりです。

1942892530

説明します。Javaでのlongは8バイトと64ビットであるため、コンピューターでの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

このバイナリ表現の文字列は10進数の1942892530であるため、上記のコンソールに出力されます。ちなみに、この例から2つの結論を導き出すことができます。

1.整数のデフォルトのデータ型はint、long l = 12345678901234Lです。この数値はintの範囲を超えているため、末尾にLがあり、これがlong型の数値であることを示しています。ちなみに、浮動小数点型のデフォルトの型はdoubleなので、floatを定義するときは、「 "float f = 3.5f"」と書く必要があります。

2.次に、別の文を書くと、「int ii = l + i;」はエラーを報告します。これは、long + intがlongであり、intに割り当てることができないためです。

32.パブリックコレクションクラスで使用されていないデータは、時間内に削除する必要があります

コレクションクラスがパブリックである場合(つまり、メソッドの属性ではない場合)、コレクション内の要素は常に参照されているため、自動的に解放されません。したがって、パブリックコレクション内の一部のデータを削除せずに使用しないと、パブリックコレクションが継続的に増加し、システムにメモリリークの隠れた危険性が生じます。

33.基本データ型を文字列に変換します。基本データ型.toStringが最も速く、String.valueOfが2番目で、data + ""が最も遅くなります。

基本的なデータ型を一般的なデータ型に変換する方法は3つあります。整数型のデータiがあります。i.toString、String.valueOf(i)、i + ""の3つの方法を使用できます。これらの方法の効率は、次のとおりです。テスト:

public static void main(String args)

{{

int loopTime = 50000;

整数i = 0; long startTime = System.currentTimeMillis; for(int j = 0; j <loopTime; j ++)

{{

文字列str = String.valueOf(i);

}

System.out.println(“ String.valueOf:” +(System.currentTimeMillis --startTime)+“ ms”);

startTime = System.currentTimeMillis; for(int j = 0; j <loopTime; j ++)

{{

文字列str = i.toString;

}

System.out.println(“ Integer.toString:” +(System.currentTimeMillis --startTime)+“ ms”);

startTime = System.currentTimeMillis; for(int j = 0; j <loopTime; j ++)

{{

文字列str = i +“”;

}

System.out.println(“ i +“”:” +(System.currentTimeMillis-startTime)+“ ms”);

}

操作の結果は次のとおりです。

String.valueOf:11ms Integer.toString:5ms i +“”:25ms

したがって、将来、基本データ型をStringに変換する場合は、toStringメソッドを使用することをお勧めします。理由については、それは簡単です:

1. String.valueOfメソッドは、下部にあるInteger.toStringメソッドを呼び出しますが、呼び出す前にnullの判断を下します。

2. Integer.toStringメソッドは言うまでもなく、直接呼び出すだけです。

3. i + ""の最下層はStringBuilderによって実装され、最初にappendメソッドを使用してスプライスし、次にtoStringメソッドを使用して文字列を取得します。

3つと比較すると、2が最も速く、1が2番目で、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 keySet = hm.keySet;」を使用する方が適切です。

35.リソースのクローズを個別に操作することをお勧めします

たとえば、次のようなコードがあります。

try {XXX.close; YYY.close;} catch(例外e){…}

以下を修正することをお勧めします。

try {XXX.close; } catch(Exception e){…} try {YYY.close; } catch(例外e){…}

少し面倒ですが、リソースリークを回避できます。変更されたコードがない場合、XXX.closeが例外をスローした場合、それはcathブロックに入り、YYY.closeは実行されず、リソースYYYはリサイクルされず、常に占有されると思います。 。コードが多いと、リソースハンドルのリークが発生する可能性があります。上記の文言に変更した後、XXXとYYYはとにかく閉じられることが保証されます。

おすすめ

転載: blog.csdn.net/qq_40093255/article/details/113583680