新人SEの学習記録

14年度入社SEの学習記録用に始めたブログです。もう新人じゃないかも…

学習記録:優れた例外処理コード

[Java]Javaの学習

内容: 5章 優れた例外処理コード

2種類の例外
  1. Exceptionのサブクラス
    • メソッドでExceptionを発行する場合、
    • このタイプのエラーは恒常的に起こる場合にのみ問題となる
  2. RuntimeExceptionのサブクラス
    • 恒常的には起こらない問題を示す
      • コードで予期せぬことが発生したことを示す
      • ビジネスロジックやユーザエラーとは無関係、プログラミングエラー
    • throws句を宣言する必要がない
例外の隠蔽・無視
  • 隠蔽
    • とりあえず全部RuntimeExceptionを発行 -> わかりづらい...
  • 無視
    • catch句で何もしない -> これが良い場合は非常にまれ
Exceptionを使うかRuntimeExceptionを使うか
  • 常にプログラミングエラーの結果起こる>RuntimeException
  • 常にビジネスロジックのエラーの結果起こる>Exception
  • ユーザのデータ入力が適切でない>RuntimeExceptionで回避
例外をいつ使うか
  • (既存の)例外の使用し忘れ
    • JDKで既に提供されている例外があれば使うべし
public void setName(final String name) {
    if (name == null) {
        throw new NullPointerException();
    }
    if (name.length() == 0) {
        throw new IllegalArgumentException();
    }
    this.name = name;
}
  • 多すぎる例外
    • 大量の例外クラスを作るのはやり過ぎ
public class GUIErrorException extends Exception { ... }
public class CreditCardDeclineException extends Exception { ... }
public class BillingException extends Exception { ... }
...
    • 事態が根本的に異なる場合をのぞき、新しい例外は作らない
    • 以下のようにすることで解決
public class MyCustomException extends Exception {
    public static final int GUI_ERROR = 0;
    public static final int CREDIT_CARD_DECLINE_ERROR = 1;
    ....
    final int type;

    public MyCustomException (final int type) {
        if ((type != GUI_ERROR) && (type != CREDIT_CARD_DECLINE_ERROR)...) {
            throw new IllegalArgumentException();
        }
        this.type = type;
    }

    public int getType() {
        return this.type;
    }
}
...
if (!validcard) {
    throw new MyCustomException(MyCustomException.CREDIT_CARD_DECLINE_ERROR);
}
  • 後始末のためのfinally句
    • tryブロック内で外部リソースを占有するときはfinally句で必ず解放
  • 例外処理の罠
    • 例外によって処理が中断された場合、データの破壊が起きる可能性
// 悪い例
public void processOrder(final Object order, final Customer customer) {
    // billCreditCard()でNullPointer例外が発生した場合、既にprocessOrdersにorderは追加済
    this.processOrders.add(order);
    doOrderProcessing();
    billCreditCard(customer);
}

public void billCreditCard(final Customer customer) {
    if (customer == null) { throw new NullPointerException(); }
    ...
}
// 良い例
public void processOrder(final Object order, final Customer customer) {
    // 他の全ての操作が終了した時のみ、注文内容がprocessOrdersに追加される
    doOrderProcessing();
    billCreditCard(customer);
    this.processOrders.add(order);
}

public void billCreditCard(final Customer customer) {
    if (customer == null) { throw new NullPointerException(); }
    ...
}

所感

  • より実務的な話が多く少しわかりづらい
    • というか例外機能自体が実務的なプログラムを書くためのものだから実務的な話になるのは当然か?
    • 現在理解しにくそうな箇所はざっと読んで次に進んだ方が良さそう
  • 研修で聞いたのは以下のような話
    • Exceptionはthrow/catchすることで実用性を高めることができる
    • RuntimeExceptionはプログラミングエラーなのでプログラムを修正する