Part 3: 例外処理の実装例

## **Part 3: 例外処理の実装例**

前回はSalesforceの組み込み例外クラスの概要と使いどころを解説しました。  
今回は、それらを実際にどのように扱うのか、具体的なコードサンプルを交えながら解説します。

---

### **1. DmlException の実装例**
DML操作（insert, update, delete など）が失敗したときに発生する `DmlException` を処理する例です。

#### **(1) `try-catch` を使った基本的なエラーハンドリング**
```apex
try {
    Account acc = new Account();
    insert acc; // Name が必須なのに指定されていないのでエラー
} catch (DmlException e) {
    System.debug('DMLエラー発生: ' + e.getMessage());
}
```
この場合、`Name` が必須項目であるため `DmlException` が発生し、  
`System.debug` に `"Required fields are missing: [Name]"` というエラーメッセージが出力されます。

#### **(2) どのレコードでエラーが発生したかを特定**
```apex
try {
    List<Account> accounts = new List<Account>{
        new Account(Name = 'Test 1'),
        new Account(), // これはエラー (Name が空)
        new Account(Name = 'Test 3')
    };
    insert accounts;
} catch (DmlException e) {
    for (Integer i = 0; i < e.getNumDml(); i++) {
        System.debug('エラー対象レコード ID: ' + e.getDmlId(i));
        System.debug('エラー項目: ' + e.getDmlFieldNames(i));
        System.debug('エラーメッセージ: ' + e.getDmlMessage(i));
    }
}
```
このコードでは、`getDmlId()`, `getDmlFieldNames()`, `getDmlMessage()` を使って、どのレコードで何が原因のエラーなのかを詳細に取得できます。

---

### **2. QueryException の実装例**
SOQL クエリで、結果が 0 件または複数件になった場合のエラーを処理する例です。

#### **(1) クエリ結果が 0 件の場合**
```apex
try {
    Account acc = [SELECT Id FROM Account WHERE Name = '存在しない名前'];
} catch (QueryException e) {
    System.debug('QueryException 発生: ' + e.getMessage());
}
```
このコードは `List has no rows for assignment to SObject` というエラーを発生させます。  
対策として、リストで受け取るようにすると安全です。

```apex
List<Account> accList = [SELECT Id FROM Account WHERE Name = '存在しない名前'];
if (accList.isEmpty()) {
    System.debug('該当するアカウントが見つかりませんでした');
}
```

#### **(2) クエリ結果が複数件の場合**
```apex
try {
    Account acc = [SELECT Id FROM Account]; // 1 件以上のレコードがあるとエラー
} catch (QueryException e) {
    System.debug('QueryException 発生: ' + e.getMessage());
}
```
複数レコードが返る場合は `List<Account>` で受け取るべきです。

---

### **3. CalloutException の実装例**
外部 API に対するコールアウトが失敗した場合に発生する `CalloutException` の処理方法です。

```apex
try {
    Http http = new Http();
    HttpRequest request = new HttpRequest();
    request.setEndpoint('https://invalid-api.com/data');
    request.setMethod('GET');
    
    HttpResponse response = http.send(request);
} catch (CalloutException e) {
    System.debug('CalloutException 発生: ' + e.getMessage());
}
```
この例では、API のエンドポイントが無効な場合に `CalloutException` が発生します。

**対策:**  
- コールアウト前に `HttpRequest.setTimeout()` でタイムアウト時間を指定する。
- `if(response.getStatusCode() != 200)` でレスポンスのステータスコードをチェックする。

---

### **4. LimitException の実装例**
`LimitException` は **catch できない** ため、ガバナ制限を意識した実装が必要です。

#### **(1) SOQL クエリの制限**
例えば、以下のようなコードは **SOQL クエリを 101 回実行しようとしてエラー** になります。

```apex
for (Integer i = 0; i < 101; i++) {
    Account acc = [SELECT Id FROM Account LIMIT 1];
}
```
**対策:** SOQL をループ外で 1 回だけ実行する。
```apex
List<Account> accList = [SELECT Id FROM Account];
for (Account acc : accList) {
    System.debug(acc.Id);
}
```

#### **(2) DML 操作の制限**
以下のコードは **DML 操作を 151 回実行しようとしてエラー** になります。

```apex
for (Integer i = 0; i < 151; i++) {
    Account acc = new Account(Name = 'Test ' + i);
    insert acc;
}
```
**対策:** `insert` をループ内で 1 件ずつ実行せず、リストでまとめて DML を実行する。

```apex
List<Account> accList = new List<Account>();
for (Integer i = 0; i < 150; i++) {
    accList.add(new Account(Name = 'Test ' + i));
}
insert accList;
```

---

### **5. NullPointerException の実装例**
`NullPointerException` は、`null` の変数に対してメソッドを呼び出した場合に発生します。

#### **(1) 発生するケース**
```apex
String str;
System.debug(str.length()); // NullPointerException
```
#### **(2) 対策**
事前に `null` チェックを行う。
```apex
if (str != null) {
    System.debug(str.length());
} else {
    System.debug('変数 str は null です');
}
```

---

### **6. カスタム例外クラスの作成**
独自の例外を作成する場合は、`Exception` クラスを継承して `extends` する。

#### **(1) カスタム例外クラスの定義**
```apex
public class MyCustomException extends Exception {}
```
#### **(2) 例外をスローする**
```apex
try {
    throw new MyCustomException('これはカスタム例外です');
} catch (MyCustomException e) {
    System.debug(e.getMessage());
}
```
#### **(3) 既存の例外をラップする**
```apex
try {
    throw new MyCustomException('カスタム例外', new DmlException());
} catch (MyCustomException e) {
    System.debug(e.getMessage());
}
```

---

## **まとめ**
今回は、例外処理の具体的なコードサンプルを解説しました。  
特に `DmlException`、`QueryException`、`CalloutException`、`LimitException` などは、Salesforce の開発で頻繁に遭遇するので、しっかりと使いこなせるようにしておきましょう。

> **次の Part 4** では、さらに **実践的なエラーハンドリングのテクニック** や **トランザクション管理** について解説します。