コンストラクタで例外を発生させるかどうか

コンストラクタで例外を投げたい状況が出てきた。
あるオブジェクトを生成するにあたって必要なデータをコンストラクタの引数として渡すのだが、渡された引数がそのオブジェクトに相応しくない場合(nullとか)には当然例外を投げたくなるよな。


投げたいなら投げればいいじゃないのと思うかもしれないが、何故素直に投げられないかというと、一般に「C++ではコンストラクタから例外を投げるのは良くない事」という風潮があるから。なのでJavaでもやってはいけないのではないかと歯止めがかかってしまう。
なぜC++ではコンストラクタで例外を投げないほうが良いのかというと、デストラクタが呼ばれないのでメモリリークを起こす可能性があるからというのが主な理由だと思われる。
メモリリークを起こさないためにはデストラクタに頼ることなくコンストラクタ内で後始末を済ませてから例外を投げてやれば良いわけだが、面倒くさいからなのかミスの元だからなのか、とにかくやめたほうが良いということになっている。


一方Javaの場合は純粋なデストラクタはないわけだが、それに相当するfinalize()はきちんと呼ばれるようだ。
但しこの場合コンストラクタにて初期化が完了していないフィールドなどに注意する必要がある。だが、そもそも普通にJavaを身に付けている人ならfinalize()に頼ったコードなんて書かないと思うので関係ない気がしてきた。
結局例外を発生させるならその場で後始末はしましょうということだな。


――と、色々調べていたわけだが、よくよく思い出してみるとjava.io.Fileとかjava.net.URLとか普通にコンストラクタが例外投げてくるじゃん!


そもそもオブジェクトというものは具象的な、あるいは概念的な何かを表しているわけなので、無名のファイルや無名のURLといった「ありえないもの」は存在させてはいけないようにするのが理想と言える。
となるとコンストラクタで例外を発するのも何ら問題ないように思える。というかむしろ積極的に投げたくなってきた。
ただ、コンストラクタで例外を投げるということはtry-catchで括らなければならないので使い勝手が悪くなるのかなぁとも思う。いやでもどのみちチェックはしなければいけないので同じことか。


ちなみに「コンストラクタで例外を投げるの禁止」ルールを適用する場合は、「このオブジェクトが正当かどうか調べるメソッドを別途用意する」とか、「空の状態で生成してから初期化メソッドでデータを突っ込む」ということになると思うが、これらは「ありえない」状態を許してしまうことになるので嫌だなぁと感じる。「-30歳の人」とか扱いに困る。やはりインスタンスとして存在するからには正当性を保っていて欲しい。