Javaのちょっとしたトリック。 パート2

最初の記事の続きでは、最も一般的なエラーと、すでに作成されたプロジェクトで作業するときにしばしば対処しなければならない単純な悪いコードについて、もう少し触れます。 これらの状況はあまり一般的ではないため、最初の部分では我慢できませんでしたが、最初の部分は多くの肯定的なフィードバックを引き起こしたため、続行することにしました。 すべてのコメンテーター、レビュー、コメントに感謝します。 私は犯した間違いを避けようとします。 それでは、続けましょう:



バッファリングされたストリーム


// InputStream is = new FileInputStream(file); int val; while ((val = is.read()) != -1) { } // InputStream is = new BufferedInputStream(new FileInputStream(file)); int val; while ((val = is.read()) != -1) { }
      
      





それは思えます-明らかな真実、そうではありませんか? しかし、他の誰かのコードと候補者へのインタビューの経験が示したように、一部の開発者は、バッファされたストリームの利点が何であるかを確実に理解していません。 まだわからない人-FileInputStreamクラスのread()メソッド:

 public native int read() throws IOException;
      
      





同意して、毎回1​​バイトを読み取るためにシステムコールを行うことは、いくらか無駄です。 実際、この問題を回避するために、シェルバッファーが作成されました。 それらが行うことは、最初にシステム読み取りを呼び出すとき()指定されたバッファーサイズによって異なります(既定では8 kbです)、次に読み取るときは、既にバッファーからデータを読み取ります。 パフォーマンスの向上は一桁です。 実際、システムコールは必ずしも悪いわけではありません。次に例を示します。

 System.arraycopy(src, srcPos, dest, destPos, length);
      
      





配列をコピーする場合、システムメソッドはjavaで実装されるよりもはるかに高速になります。 そしてまだ-バイトではなくバッチでデータを読み取り、これによりまともな保存も可能になります。



列挙型と文字列


 // String status = plan.getStatus(); if (status.equals("draft")) { //do stuff } else if (status.equals("submitted")) { //do stuff } // PlanStatus status = plan.getStatus(); if (status == PlanStatus.DRAFT) { //do stuff } else if (status == PlanStatus.SUBMITTED) { //do stuff }
      
      





可能な場合は、事前定義されたモデルの状態にEnumを使用します。 これにより、コードの理解が簡単になるだけでなく、これらの状態を比較するプロセスが高速化されます。 参照による比較は、文字列や他のオブジェクトを比較するよりも間違いなく1桁高速です。 確かに、この場合、大きなマイナス点が1つあります。アプリケーションをサポートするコストが増加し、既存の状態の1つを追加、削除、または変更する必要がある場合に特に顕著になります。 ただし、これらが月のように不変のプロパティである場合は、列挙を安全に使用します。



ArrayListとHashSet


コレクションにデータを保存する場合は十分注意してください。 多くの場合、リストを分配できるセットと、アレイを分配できるリストが使用されます。 たとえば、データベーステーブルにマップするクラス。 これを避け、適切な依存関係と適切なクエリを構築してください。 HashSetがHashMapに実装され、HashMapが内部エントリクラスを使用することは秘密ではないため、これによりメモリが節約されます。内部エントリクラスは、キーと値に加えて、ハッシュと次のエントリオブジェクトへのリンクも格納します さらに、絶えずハッシュを追加することが計算されます。これは、複雑なオブジェクトの場合は高価になる可能性があります。



データ読み取り


 // byte[] fileBinaryData = readFile(filepath); // InputStream fileStream = readFile(filepath);
      
      





これらの罪のない行の何が問題になっていますか? はい、一般的に、読んでいるファイルのサイズがわからないという事実以外は何もありません。 ファイルの代わりに、データ、ポストリクエストからのデータ、すべてを受け入れるオープンソケットなどがあります。一般的に、すべてをバイトの配列に読み込まないようにしてください。メモリが足りない可能性があります。 したがって、データのサイズには注意してください。 データを部分的に処理および転送してみてください。 そして、ユーザーデータのサイズに常に注意を払い、可能な限り制限します。



ログフィールド


 // private Logger logger = Logger.getLogger(Plan.class); // private static final Logger logger = Logger.getLogger(Plan.class);
      
      





クラスでロギングを使用しますか? ログ変数は常に静的最終として定義します。 まず、オブジェクトをシリアル化および逆シリアル化する際に問題が発生することはありません。 第二に、クラスオブジェクトを作成するときの初期化は常に行われるのではなく、1回だけ初期化されます。



フィールドの初期化


 // class Plan { private String name = null; private Boolean isNew = false; private Set<Document> documents = new HashSet<Document>(); } // class Plan { private String name; private Boolean isNew; private Set<Document> documents; }
      
      





これに自信がない限り、クラスフィールドを早期に初期化しないようにしてください。 それでも、これらの目的のためにコンストラクタがあります。 クラスフィールドの値が明示的に指定されている場合、コンストラクターが呼び出される前に初期化されます。たとえば、オブジェクトを作成した直後に初期化フィールドに他の値を設定する場合など、初期化された値を使用する必要がない場合、追加のコストが発生します。 クラスフィールドは常にデフォルト値で初期化されることを忘れないでください。



空の文字列


 // if (name.equals("")) { // if (name.isEmpty()) {
      
      





文字列に空の値が含まれているかどうかを確認する必要がある場合は、isEmpty()メソッドを使用します。 なぜ()に等しくないのですか? 遅いです。 文字列の実装を見ると、すぐにすべてを理解できます。 驚かないでください、多くの開発者はまだこの方法を知りません。



オブジェクト[]とカスタムクラス


 // Object[] data = new Object[3]; data[0] = row.getUserCount(); data[1] = row.getOwnerCount(); data[2] = row.getLocations(); return data; // RowResult data = new RowResult(); data.setUserCount(row.getUserCount()); data.setOwnerCount(row.getOwnerCount()); data.setLocations(row.getLocations()); return data;
      
      





他の場所で戻り値を操作する必要がある場合、Objectを含むコードは完全に判読できません。 つまり、戻り値自体が保持するものを理解するためには、呼び出しクラスに戻ってメソッドのコメントを読む必要があります。もちろん、そうであり、コードにアクセスしない場合はあまり効果的ではありません。 実際、急いでいるとき、私自身も時々この罪を犯します。 非常にまれな場合はこれに耐えることができますが、それでも、そのような状況では新しいクラスを作成することをお勧めします。 あなたの後に来る人たちの生活を楽にします。



匿名クラス


匿名クラスは優れた機能ですが、アプリケーションのすべての場所に匿名クラスを押し込まないでください。時間を少し節約できるからです。 匿名クラスを含むコードは読みにくく、読みにくいです。 もちろん、匿名クラスが非常に適切な場合を除いて、それらを別々のクラスに配置することをお勧めします。



比較順序


 // if (name.equals("broadcast")) { // if ("broadcast".equals(name)) {
      
      





このメソッドを使用すると、不要なnullチェックを取り除くことができます。 ただし、最初の記事のルールを順守している場合、この方法は必要ありません。



結論


はい、書かれていることの多くは明白というよりも明白です。 しかし、もしそうなら、それはプロジェクトからプロジェクトへどこから来るのでしょうか? この記事は、アプリケーションのパフォーマンスを改善するためのガイドではありません。 それはちょうど良い、正しいスタイルです。 これがお役に立てば幸いです。



All Articles