Java

Java あなたは例外をループを止めるために使っていないか?

記事内に商品プロモーションを含む場合があります

Javaでループ処理をする場合に様々な書き方がありますが、先日とんでもないループ処理を見ました。

while文でループを無限に回して、indexが溢れたら例外処理で止めて例外を握りつぶすという荒業でした。

そのような処理を書いてしまうと、本当に例外が起きてしまったときに、不具合を検知できないという事が起こってしまいます。

以降でソース例を記載しているのでよろしければご覧ください。

Java ループを例外で止める最悪なソース

ループを例外で止める最悪なソース例をご覧ください。

import java.util.Arrays;
import java.util.List;

public class AkanException {

    public static void main(String[] args) {

        List<String> akanList = Arrays.asList("a", "b", "c", "d", "e");
        int i = 0;
        try {
            while(true) {
                System.out.println(akanList.get(i++));
            }
        } catch (ArrayIndexOutOfBoundsException ex) {
        }
    }
}

この様な処理を書くと、確かにList内を全てループすることができますが、存在しないindexをgetした場合にArrayIndexOutOfBoundsExceptionが発生し、例外処理で何もしないことであたかも問題ないように見えますが、実際は課題が発生します。

ループ内で実施する処理で例外が起きてしまった場合に、その例外を見過ごしてしまう可能性や、一般的な全ループの拡張for文などと比較すると処理が遅くなってしまうこともあります。

そのため、例外処理でループを止めるのではなく、ループの終了条件を正しく設定したり、拡張for文でループしたりなどするべきです。

Java ループをする際の選択肢

ループをする際には例外でループを止める以外の方法を使用しましょう。

import java.util.Arrays;
import java.util.List;

public class AkanException {

    public static void main(String[] args) {

        List<String> akanList = Arrays.asList("a", "b", "c", "d", "e");
        // あかんループ
        int i = 0;
        try {
            while(true) {
                System.out.println(akanList.get(i++));
            }
        } catch (ArrayIndexOutOfBoundsException ex) {
            // ループを止めるために書いているので、例外処理ができない
        }

        // 終了条件をしっかりと用意しているループ
        int j = 0;
        try {
            while(j < akanList.size()) {
                System.out.println(akanList.get(j++));
            }
        } catch (ArrayIndexOutOfBoundsException ex) {
            // 例外が発生してしまった場合に適切に例外処理することができる
            System.out.println("ArrayIndexOutOfBoundsException発生");
        }

        // 拡張for文
        for (String akan : akanList) {
            System.out.println(akan);
        }

        // ListのforEach
        akanList.forEach(System.out::println);

        // streamの終端処理forEach
        akanList.stream().forEach(System.out::println);
        
    }
}

様々な方法がありますが、あかんループ意外であれば用途に合わせて使いやすいものであれば何でもOKです。

例外的状況のときに例外処理を使用すること

例外処理は例外的な状況を制御するために使用するものです。

ループを止めるとか、数値であるか判定するとかで使用してはいけません。

これはJavaプログラマー必携本である、「Effective Java」にも掲載されています。

Effective JavaはJavaの構文が解説されているのではなく、Javaでプログラミングをするときのベストプラクティスが網羅されている本です。

基礎として学んだListやMapなどの構文を、どのように使用すれば良い使い方ができるかを学ぶことができるので非常におすすめですし、業務で使用する人には必ず読んでおいてほしい本です。

上記リンクから試し読みすることができるので是非ご覧ください。

まとめ

Javaでループを止める場合の邪悪な方法をご紹介しました。

ほとんど使われない方法ではありますが、まれに使っている人がいます。

例外処理は例外的な状況を制御するために使用しましょう

Javaプログラマー必携のEffective Javaは以下から試し読みすることができます。

Effective Java