【Java】Exceptionを強制throwさせて絶対そこで処理を中断させる


「とにかく何が何でもそこから先の処理にいってほしくない」という場合、
処理を強制的に中断させる目的で無条件にExceptionをthrowするようなコーディングするとコンパイルエラーになる。
ただこれにちょっと手を加えることで、誰がどう見ても明らかに絶対そこで落ちるにも関わらず
結果的に強制処理中断するロジックとして成立させることができる。


 


 
例えば↓


public class ExceptionTest {
public static void main(String[] args) throws Throwable {  
  
	System.out.println("START");  
	  
	<span style="color: red; font-weight: bold;">throw new Exception("TEST EXCEPTION");</span>  
	  
	System.out.println("END");  
  
}  

}


って書くと、赤太字の部分で処理が止まるので、
その下の「System.out.println("END");」に処理が進むことが絶対にないため、javacでコンパイルかけると

ExceptionTest.java:9: この文に制御が移ることはありません。  
                System.out.println("END");  
                ^  
エラー 1 個  


となってコンパイルエラーになる。

ただこのthrow new Exception("TEST EXCEPTION");の部分を
絶対にtrueになる条件を明示的に書いてifブロックで囲ってしまえばコンパイル通る。

if (0 == 0) {  
	throw new Exception("TEST EXCEPTION");  
}  


こんな感じ。
javacのオプションによっては警告出る事もあるようであるが、コンパイルは通る(classファイルは出来る)。
ifで囲っているとはいえその判定条件は絶対trueだから、当然のごとく処理はここで止まり、その先の「System.out.println("END");」に処理が進むことはない。




「強制処理中断」の実現方法を、Exceptionをthrowさせることで行う場合は、
なんでもいいからとりあえずifで囲ってしまえばいいらしい。
ifで囲うことで、その判定条件が↑のように明らかに無意味なものだとしても、
「絶対に通るわけではない(時と場合によって通らないこともある)」とコンパイラーが判断するらしくてとりあえずコンパイル出来てしまう。
SBRでジャイロが泉の試練中にルーレットにお金を賭けたときの心境に似ている。

Exceptionをthrowさせるのは、Exceptionのインスタンスを作るときにメッセージ(String型の文言)を埋め込むことができるので、
標準エラー出力等において「確実にここで落ちた」と実行している本人が認識できるために、俺個人がよく使う方法っていうだけである。
目的が「強制処理中断」なら別に他の方法での実現も可能で、たとえば

  
System.out.println("START");  
  
String str = null;  
str.toString();  
  
System.out.println("END");  


としても良い。
String型の変数strは定義時点で中身をnullにしており、
しかもその後間髪入れずにtoStringしてるので絶対ここで落ちる(NullPointerExceptionが発生する)。
要するにnull.toString()してるのと同じ。
素直にこうやって書くとやっぱりコンパイルエラーになるので一度Stringの変数を定義しておいてから書き出す。
(なので、型はStringである必要すらないが。。。)




このケースだと強制中断の先に待ち構えるのはただのSystem.out.printlnなので強制中断させる意味はまったくないけども、
これが例えば「クレジット決済」の処理だったりすると、
誤って決済処理を走らせて課金されてしまうリスクを”確実に”防止するために
「どうしてもクレジット決済処理の手前で止まってほしい」ということが稀にある。
→逆に言うと”「絶対に止まってほしい」処理の直前までは確実に処理が進んでいることを確認したい”という目的もある。
俺が使うときも大体こういうケースである。

まあ、実装者・テスト実施者の観点でいえば、そこで処理を止めるよりは、
”危なっかしい「クレジット決済処理」をコメントアウトして=つまり素通りさせてとりあえず処理だけは通す”という方が、
テストフェーズにおけるニーズは強いと思う。
(「クレジット決済処理」を除く部分は、前後含めてちゃんと動いていることを確認できるためである)
これを使っているのが画面だったりすると、
「誤ってクレジット決済にいっちまって決済に失敗して落ちた」のか「強制中断がちゃんと働いて思惑通りに落ちた」のか一見すると判別がつかないので心臓に悪い。
一方で「コメントアウトして素通り」させても、
「コメントアウトしてるから素通りさせてちゃんと完了した」のか「実際には誤ってクレジット決済してしまって完了してしまった」のかやっぱり一見すると判別付かないので心臓に悪い。
ただ、「完了」までしてしまうと、下手すると決済してしまっている可能性が出てくるため、
仮に決済にいったとしても失敗している(ことによって落ちている)=つまり絶対に課金されていない、という確信が持てる「強制中断」の方が、個人的には安心感がある。

当然このままじゃ運用できないし、実際に決済が正常に動くことを確認するフェーズもどこかでは確実に必要になるため、状況によって取るべき方式は変わってくると思うが。
どういう形であれ、課金が絡むところは、経験上、実装ひとつとってもこういう神経質な対応が求められる。
面倒な話だ…関わりたくない案件の一つである。。。