スローされないチェック例外を処理する方法


35

例:

foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");

エンコーディングはハードコーディングされており、正しいため、コンストラクターは仕様で宣言されたUnsupportedEncodingExceptionをスローしません(Java実装が壊れていない限り、この場合はとにかく失われます)。とにかく、Javaはとにかくその例外に対処することを強制します。

現在、そのように見えます

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
}
catch(UnsupportedEncodingException e) { /* won't ever happen */ }

それを改善する方法はありますか?


4
本当の挑戦のために、このキャッチが実際に機能することを確認するために単体テストを書いてください。
ジェイエルストン

1
「新しいImpossibleException( "ユニバースを再起動します。物事が台無しになりました"、e);
クリスカドモア

1
意志...「これまで発生しません」

ThorbjørnRavn Andersen:プログラムを変更した後でも、少なくとも現在の状態では、入力データのセットは例外をトリガーできません。
user281377

上記の特定の例では、メソッドはサポートされているエンコーディングとサポートされていないエンコーディングのどちらで呼び出されるかを知らないため、例外がスローされます。これを回避する方法は、例外がスローされることを宣言する必要のない、標準の文字セットが与えられていると想定する別のコンストラクターがある場合です。
ヨルダン

回答:


27

私の習慣は、念のためassert、キャッチブロックに入れることです。誰かがtry後でブロックの内容を変更する可能性がありますが、コードが失敗したかどうかを知りたいですか?


良いアイデア; 単純なassert false;ものは余計なものを追加せず、catchブロックが入力されないことを想定していることを明確にします。
user281377

5
@ammoQ、またはメッセージを追加して、意図を完全に明確にすることもできますassert false : "should never happen"
ペテルトレック

13
さらに良いのは、「Javaでは文字セットISO-8859-1をサポートする必要があるからです。」
dan04

3
assertアサーションが有効であることを意味します。スローしますUnexpectedException(スタックトレースを取得できるという利点もあります)。
チョップ

35

「これは絶対に起こらないはずです」というログ/エラーが表示されるたびに1セントが与えられていた場合、... 2セントでした。それでも...

空のcatchブロックは、私のクモがうずきを感じさせ、ほとんどの優れたコードアナライザーツールが文句を言います。私はそれらを空のままにしないでください。確かに、エラーは決して発生しないことがわかっていますが、今から1年後に誰かが "ISO-8859-1"のグローバル検索置換を実行し、突然バグを見つけるのが非常に困難になる可能性があります。

assert false提案は良いですが、アサーションがあるため無効にすることができ、実行時に、彼らは保証されません。RuntimeException代わりにa を使用します。クラスを呼び出すことでこれらをキャッチする必要はありません。クラスが発生した場合は、完全な情報を提供するスタックトレースがあります。


28

私はいつもこのようにしました:

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
} catch(UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

少し冗長かもしれませんが(Javaは...)、少なくとも不可能が起こったときにアサーションエラーが発生します。

Javaの実装が壊れている場合は、不可能を無視するのではなく、できるだけ早く、できるだけ早く適切なエラーメッセージを取得する必要があります。Java実装が壊れていない場合でも、そして、誰かが変更されている可能性があり、あなたにコードを"UTF8"( -それはされている必要がありますおっと"UTF-8"?)。

これそもそも実行時例外だったはずです。JDKには、このような間違った選択がたくさんあります。


4
本当に悪い決定(または必要に応じて省略)は、Javaが必要とする6つの文字セットに対して事前定義された文字セットインスタンスがないことです。foobar = new InputStreamReader(p.getInputStream(), Charset.ISO_8859_1);-今ではそれはより良く、間違いを永遠に避けないでしょうか?
user281377

3
グアバ図書館にはこうしたものが山ほどあります。生活を楽にします。

3
Java 1.7+には、docs.oracle.com/ javase / 7 / docs / api / java / nio/ charset/…という文字セット定数が定義されています。次のように使用します:StandardCharsets.UTF_8.displayName()
Michael

4

あなたがこのコードを見ることができる唯一の開発者であれば、私はその罰金を言うでしょうが、そうでなければ私はそれを本当の可能性として扱うか、少なくとも「決して起こらない」コメントを変更しますもっと便利なもの。


4

これらの例外の中で私を最も悩ませるのは、コードカバレッジが損なわれることです。

カバレッジについて強迫的になったら、「絶対に起こらない」(または「US-ASCII」を含めるのを忘れたミュータントJVMを使用している場合のみ)試行/キャッチをロールアップします。 try / catchをカプセル化し、ここで説明した方法のいずれかでチェック済み例外を置き換えるクラスとメソッド(通常、未確認の例外をスナイドメッセージでスローします)。

次に、コードカバレッジはユーティリティクラスでヒットしますが、コードに散在するその操作へのすべての参照ではヒットしません。

時々、実際に一貫したセマンティクスを持つクラスの操作のようにロールアップするのに時間がかかります。しかし、チームメイトには何が起こっているかは明らかなので、通常はできる限りシンプルに保ち、可能な限り最高のデザインについてはあまり心配しません。

ただし、コメントで述べたように、Guavaと他のライブラリにはこの痛みを軽減する方法がありますが、基本的には同じ戦略です。メインコードがカバレッジ内でヒットしないように、迷惑をステージ外に移動します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.