Javaの悪臭を消す

52262 ワード

文書ディレクトリ
  • Mapのプライマリ・キーと値を求める場合はentrySet()
  • を反復する必要があります.
  • Collection.isEmpty()を使用して空の
  • を検出する必要があります.
  • 集合オブジェクトを自分に渡さない
  • 集合初期化できるだけサイズを指定する
  • .
  • Listのランダムアクセス
  • 静的メンバー変数
  • を付与するために集合インプリメンテーションを使用しないでください.
  • try-with-resources文
  • の使用を推奨
  • ツールクラスは構造関数
  • を遮蔽すべきである.
  • 余分な異常捕捉を削除し、
  • を放出する.
  • Null PointerExceptionで空の
  • を判断しないでください.
  • 使用禁止構造方法BigDecimal(double)
  • はnull
  • ではなく空の配列と空の集合を返します.
  • に列挙された属性フィールドは、プライベート可変
  • である必要があります.
  • 注意String.split(String regex)
  • Mapのプライマリ・キーと値が必要な場合はentrySet()を反復する必要があります.
    反復keySet()は、ループ中にMapのプライマリキーのみが必要な場合に正しい.ただし、プライマリ・キーと値を取得する必要がある場合は、keySet()を反復してからgetを取得するよりも効率的です.
    反例
    Map<String, String> map = ...;
    for (String key : map.keySet()) {
        String value = map.get(key);
        ...
    }
    

    正例
    Map<String, String> map = ...;
    for (Map.Entry<String, String> entry : map.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue();
        ...
    }
    

    Collection.isEmpty()を使用して空を検出する必要があります
    Collection.size()を使用して空の論理を検出しても問題はありませんが、Collection.isEmpty()を使用するとコードが読みやすくなり、パフォーマンスが向上します.任意のCollection.isEmpty()実装の時間的複雑さはO(1)であるが、いくつかのCollection.size()実装の時間的複雑さはO(n)である可能性がある.
    if (collection.size() == 0) {
        ...
    }
    
    if (collection.isEmpty()) {
        ...
    }
    

    nullを検出する必要がある場合は、CollectionUtils.isEmpty(collection)とCollectionUtils.isNotEmpty(collection)を使用します.
    集合相手を自分に伝えないで
    さらに、いくつかの方法では、パラメータが実行中に変わらないことが要求されるため、セットを自身に渡すと異常な動作を引き起こす可能性があります.
      :
    List<String> list = new ArrayList<>();
    list.add("Hello");
    list.add("World");
    if (list.containsAll(list)) { //    ,    true
        ...
    }
    list.removeAll(list); //    ,     clear()
    

    コレクション初期化できるだけサイズを指定
    **javaの集合クラスは便利ですが、ソースコードを見ると、集合にもサイズ制限があります.毎回の拡容の時間的複雑さはO(n)である可能性が高いので、できるだけ予知可能な集合の大きさを指定し、集合の拡容回数を減らすことができます.**
    int[] arr = new int[]{1, 2, 3};
    List<Integer> list = new ArrayList<>();
    for (int i : arr) {
        list.add(i);
    }
    
    int[] arr = new int[]{1, 2, 3};
    List<Integer> list = new ArrayList<>(arr.length);
    for (int i : arr) {
        list.add(i);
    }
    

    Listのランダムアクセス
    配列とチェーンテーブルの違いはよく知られています.配列のランダムアクセス効率が高いです.呼び出しメソッドがListを取得した後、その中のデータにランダムにアクセスしたい場合、その配列内部実装がチェーンテーブルなのか配列なのか分からない場合は、どうすればいいのでしょうか.RandomAccessインタフェースが実装されているかどうかを判断できます.
    //           list
    List<Integer> list = otherService.getList();
    if (list instanceof RandomAccess) {
        //       ,      
        System.out.println(list.get(list.size() - 1));
    } else {
        //          ,       
    }
    

    集合インプリメンテーションを使用して静的メンバー変数を割り当てるな
    集合タイプの静的メンバー変数では、集合インプリメンテーションを使用して値を割り当てるのではなく、静的コードブロックを使用して値を割り当てる必要があります.
    private static Map<String, Integer> map = new HashMap<String, Integer>() {
        {
            put("a", 1);
            put("b", 2);
        }
    };
    
    private static List<String> list = new ArrayList<String>() {
        {
            add("a");
            add("b");
        }
    };
    
    private static Map<String, Integer> map = new HashMap<>();
    static {
        map.put("a", 1);
        map.put("b", 2);
    };
    
    private static List<String> list = new ArrayList<>();
    static {
        list.add("a");
        list.add("b");
    };
    

    try-with-resources文の使用を推奨
    Java 7にはtry-with-resources文が導入されており、従来のtry-catch-finally文よりも関連リソースを閉じることを保証し、プログラムコードをより安全で簡潔にすることができます.
    private void handle(String fileName) {
        BufferedReader reader = null;
        try {
            String line;
            reader = new BufferedReader(new FileReader(fileName));
            while ((line = reader.readLine()) != null) {
                ...
            }
        } catch (Exception e) {
            ...
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    ...
                }
            }
        }
    }
    
    private void handle(String fileName) {
        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = reader.readLine()) != null) {
                ...
            }
        } catch (Exception e) {
            ...
        }
    }
    

    ツールクラスはコンストラクション関数を隠すべきです
    ツールクラスは静的フィールドと関数のセットであり、インスタンス化すべきではありません.ただし、Javaは、コンストラクション関数を明確に定義していないクラスごとに暗黙的な公有コンストラクション関数を追加します.したがってjavaの「シロ」の使用が誤っていることを避けるために、この暗黙的な公有構造関数を遮断するために、プライベート構造関数を明示的に定義する必要があります.
    public class MathUtils {
        public static final double PI = 3.1415926D;
        public static int sum(int a, int b) {
            return a + b;
        }
    }
    
    public class MathUtils {
        public static final double PI = 3.1415926D;
        private MathUtils() {}
        public static int sum(int a, int b) {
            return a + b;
        }
    }
    

    余分な例外のキャプチャと放出を削除
    catch文で異常をキャプチャした後、何も処理しないで異常を再放出します.これは異常をキャプチャしない効果と同じで、このコードを削除したり、別の処理を追加したりすることができます.
    private static String readFile(String fileName) throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            StringBuilder builder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            return builder.toString();
        } catch (Exception e) {
            throw e;
        }
    }
    
    private static String readFile(String fileName) throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            StringBuilder builder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            return builder.toString();
        }
    }
    

    Null PointerExceptionで空を判断しない
    空のポインタ異常は、異常をキャプチャする方法で処理するのではなく、コードで回避する必要があります(たとえば、検出が空ではありません).
    public String getUserName(User user) {
        try {
            return user.getName();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public String getUserName(User user) {
        if (Objects.isNull(user)) {
            return null;
        }
        return user.getName();
    }
    

    ビルドメソッドの使用を禁止するBigDecimal(double)
    BigDecimal(double)は精度損失のリスクがあり、正確な計算や値比較のシーンでビジネスロジックが異常になる可能性があります.
      :
    BigDecimal value = new BigDecimal(0.1D); // 0.100000000000000005551115...
    
      :
    BigDecimal value = BigDecimal.valueOf(0.1D);; // 0.1
    

    nullではなく空の配列と空の集合を返します.
    nullを返すには、呼び出し元がnullを強制的に検出する必要があります.そうしないと、空のポインタ異常が放出されます.空の配列または空の集合を返します.nullが検出されていないため、呼び出し元が空のポインタを放出する異常を効果的に回避します.また、呼び出し元がnullを検出する文を削除してコードをより簡潔にすることもできます.
    public static Result[] getResults() {
        return null;
    }
    
    public static List<Result> getResultList() {
        return null;
    }
    
    public static Map<String, Result> getResultMap() {
        return null;
    }
    
    public static void main(String[] args) {
        Result[] results = getResults();
        if (results != null) {
            for (Result result : results) {
                ...
            }
        }
    
        List<Result> resultList = getResultList();
        if (resultList != null) {
            for (Result result : resultList) {
                ...
            }
        }
    
        Map<String, Result> resultMap = getResultMap();
        if (resultMap != null) {
            for (Map.Entry<String, Result> resultEntry : resultMap) {
                ...
            }
        }
    }
    
    public static Result[] getResults() {
        return new Result[0];
    }
    
    public static List<Result> getResultList() {
        return Collections.emptyList();
    }
    
    public static Map<String, Result> getResultMap() {
        return Collections.emptyMap();
    }
    
    public static void main(String[] args) {
        Result[] results = getResults();
        for (Result result : results) {
            ...
        }
    
        List<Result> resultList = getResultList();
        for (Result result : resultList) {
            ...
        }
    
        Map<String, Result> resultMap = getResultMap();
        for (Map.Entry<String, Result> resultEntry : resultMap) {
            ...
        }
    }
    

    列挙されたプロパティフィールドは、プライベートで可変でなければなりません.
    列挙は通常定数として使用され、列挙に共通属性フィールドが存在する場合やフィールドメソッドを設定する場合、これらの列挙定数の属性は変更されやすい.理想的には、列挙中の属性フィールドはプライベートであり、プライベート構造関数に値を付与し、対応するSetterメソッドがなく、final修飾子を付けることが望ましい.
    public enum UserStatus {
        DISABLED(0, "  "),
        ENABLED(1, "  ");
    
        public int value;
        private String description;
    
        private UserStatus(int value, String description) {
            this.value = value;
            this.description = description;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    }
    
    public enum UserStatus {
        DISABLED(0, "  "),
        ENABLED(1, "  ");
    
        private final int value;
        private final String description;
    
        private UserStatus(int value, String description) {
            this.value = value;
            this.description = description;
        }
    
        public int getValue() {
            return value;
        }
    
        public String getDescription() {
            return description;
        }
    }
    
    
    

    String.split(String regex)に注意
    文字列Stringのsplitメソッドで、入力された区切り文字列は正規表現です!一部のキーワード(例.|など)はエスケープが必要です
    "a.ab.abc".split("."); //    []
    "a|ab|abc".split("|"); //    ["a", "|", "a", "b", "|", "a", "b", "c"]
    
    "a.ab.abc".split("\\."); //    ["a", "ab", "abc"]
    "a|ab|abc".split("\\|"); //    ["a", "ab", "abc"]