[java符号化の技術]2コードスタイル、Java APIの切り取り


3ヶ月前に新しく入社した非専門開発者が可読性の良いコードを作るために学んだ内容です.不足や再学習のアドバイスは、文章で発見された問題をいつでも話してください.

1.magic numberを定数に置き換える

@Setter
public class ExampleService {
    
    private double targetSpeed;
    
    public void setPreset(int speedPreset) {
        if (speedPreset == 2) {
            setTargetSpeed(17944);     
        }
        if (speedPreset == 1) {
            setTargetSpeed(6767);
        }
        if (speedPreset == 0) {
            setTargetSpeed(0);
        }
    }
}
  • magic number:表面的には意味のない数字ですが、プログラムの動作を制御する数字→magic numberが多すぎるとコードが分かりにくく、エラーが発生する可能性が高いです.
  • 他の開発者が任意の値に変更した場合、直ちに
  • エラーが発生します.
    ターゲット速度は
  • speedPresetで決定され、このとき開発者は選択可能なspeedPresetオプション+コンパイラがコード入力未知数の数を阻止できないことを知ることができない→コード入力が困難になると同時に、エラーが発生する確率は
  • 上昇する.
  • magic numberを定数で置き換えましょう
  • @Setter
    public class ExampleService {
        static final int STOP_SPEED_PRESET = 0;
        static final int PLANETARY_SPEED_PRESET = 1;
        static final int CRUISE_SPEED_PRESET = 2;
    
        static final int STOP_SPEED_KMH = 0;
        static final int PLANETARY_SPEED_KMH = 6767;
        static final int CRUISE_SPEED_KMH = 17944;
    
        private double targetSpeed;
    
        public void setPreset(int speedPreset) {
            if (speedPreset == CRUISE_SPEED_PRESET) {
                setTargetSpeed(CRUISE_SPEED_KMH);
            }
            if (speedPreset == PLANETARY_SPEED_PRESET) {
                setTargetSpeed(PLANETARY_SPEED_KMH);
            }
            if (speedPreset == STOP_SPEED_PRESET) {
                setTargetSpeed(STOP_SPEED_KMH);
            }
        }
    }
  • は明確で意味のある名前を使用しているため、どの設定値がどの速度値に関連付けられているかを容易に理解できます.
  • 2.ENUMの使用

  • 1コードでは、setPresetはすべての整数を含むことができる→すなわち、内部で処理可能な0、1、2に加えて、様々な変数値を入力することができる→この場合、メソッドは何も返さず、または処理しないが、無効な値を入力すること自体がエラー
  • を引き起こす可能性がある.
  • enumは、コンパイラが無効な値を事前に拒否することを許可します.
  • enumを使用するコード
  • を見てみましょう
    @Setter
    public class ExampleService {
    
        private double targetSpeed;
    
        public void setPreset(SpeedPreset speedPreset) {
            Objects.requireNonNull(speedPreset);
    
            setTargetSpeed(speedPreset.speedKmh);
        }
    
        enum SpeedPreset {
            STOP(0),
            PLANETARY_SPEED(6767),
            CRUISE_SPEED_KMH(17944);
    
            final double speedKmh;
    
            SpeedPreset(double speedKmh) {
                this.speedKmh = speedKmh;
            }
        }
    }
  • enumを使用する重要な利点の1つは、現在無効なspeedPresetをsetPreset()メソッドに入れることができないことです→無効なやつが現れたら、コンパイラはすぐに
  • を停止します.
    さらに
  • を加えると、magic numberの代わりに意味のある名前を使うことができ、最初の問題で見た問題を一緒に解決することができます.
  • enumを使用してifブロックを削除→コード簡潔
  • の例に示すように、可能なすべてのオプションをリストできる場合は、整数タイプではなくenumを常に使用することが望ましい.
  • 3.For文ではなくFor-each構文を使用する

  • インデックスを使用するクエリでは、インデックス変数iを使用すると、
  • というエラーが発生する可能性があります.
  • インデックス変数の詳細については、「
  • for-各構文について反復器
  • を使用
  • インデックス変数は繰り返し文でランダムに処理されないため、インデックス変数を使用するときに発生する問題
  • を回避することができる.
  • ほとんどの場合、for-each文を使用することが望ましいが、本当に短い時間でインデックス重複文を書く必要がある場合は、集合の特定の部分だけを繰り返したり、インデックス変数を明示的に使用したりすることができます.
  • 4.コレクションは巡回時に変更しない

    List<Supply> supplies = new ArrayList<>();
    
    public void dispose() {
        for (Supply supply : supplies) {
            if (supply.isContamiated()) {
                supplies.remove(supply);
            }
        }
    }
  • がこのように実施すると、Listの標準実施、SetまたはQueueのような集合は、同時修正Exception→集合サイクル中に修正する導出
  • を投げ出す.
  • また、1つの電源に問題が発生すると、無条件に競合→問題が発生するまで、そのコードが問題を引き起こすコードであるか否かを判断できない
  • .
    public void dispose() {
        Iterator<Supply> iterator = supplies.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().isContamiated()) {
                iterator.remove();
            }
        }
    }
  • 反復器を使用する場合は、まずループおよび変質データを検索し、次に変質データを削除します.
  • 反復器
  • の学習が必要

    5.計算集約型演算を行わずに循環する

    public void dispose(String regex) {
        List<Supply> result = new ArrayList<>();
        for (Supply supply : supplies) {
            if (Pattern.matches(regex, supply.toString())) {
                result.add(supply);
            }
        }
    }
  • 上のコードから分かるように、繰り返し出現するたびに正規表現がコンパイル→性能低下
  • となる.
  • 潜在的な性能低下を避けるために、繰り返し文の中でできるだけ演算回数を減らすことができる
  • .
    上記の
  • の例では、メソッドを呼び出すときに正規表現を1回コンパイルするだけでよい:
  • public void dispose(String regex) {
        List<Supply> result = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);
        for (Supply supply : supplies) {
            if (pattern.matcher(supply.toString()).matches()) {
                result.add(supply);
            }
        }
    }

    6.新行ケルピーで

  • のコードブロックが付着すると、1つのブロックと見なす→個別のブロックを新しい行に分割することで、コードの可読性を向上することができる
  • .
  • グルーが普段参考にしている良い比喩
  • 優秀な文章構造(文章)
  • タイトル(クラス名)
  • セッションヘッダー(公開メンバー、作成者、メソッド)
  • 詳細(非公開方法)
  • は、この程度の構造でコードを記述するだけで、クラス
  • をより明確に理解することができる.

    7.貼り付けではなくフォーマット

  • 文字列または結果をエクスポートする場合は、結果がどのように生成されるかを容易に理解する必要があります.
  • フォーマット文字列は、この問題を解決する
  • の核心はStringレイアウト(どのように出力するか)とデータ(何を出力するか)を区別することです.

    8.自分で作成せずにJava APIを使う

  • Javaクラスライブラリには多くの有用なAPIが含まれています→APIの作成に時間を費やす必要はありません!
  • public int countFrequency(TestAVo aVo) {
        if (aVo == null) {
            throw new NullPointerException();
        }
    
        int frequency = 0;
        for (TestAVo eleAVo : aVoList) {
            if (aVo.equals(eleAVo)) {
                frequency++;
            }
        }
        return frequency;
    }
  • は一見うまくやっているように見えますが、Javaがそれに対応するコンテンツを書けるようにマルチAPI
  • が作成されています
    public int countFrequency(TestAVo aVo) {
        Objects.requireNonNull(aVo);
    
        return Collections.frequency(aVoList, aVo);
    }
  • 段の2つのJava APIだけでスッキリ処理→Java APIをフル活用!
  • が直接作成するコードはエラーを引き起こす可能性が高い、Java APIを使用して既存の機能を実装しないと時間を節約できる
  • .
  • を開発するときにより良いコードが感じられる場合、それはAPIが存在しなければならない
  • である.