プライベートメソッドからargumentexceptionまたはargumentnullexceptionをスローしますか?


20

私はしばらく前に書いたコードをレビューしていましたが、メソッドのパラメーターに問題がある場合にargumentnullexceptionsおよび/またはargumentexceptionsをスローするプライベートメソッドがいくつかあることがわかります。

私の理論的根拠は、誰かが将来メソッドを「誤用」しようとする場合、アプリケーションの将来の証明に役立つと思います。ただし、それがプライベートメソッドであり、このメソッドを呼び出す可能性のある人々が関連するコメントとコードを見ることができる場合、これをスローする必要はありません。混乱させることはありますが、確かにそれらを使用しても害はありません。

私の考えでは、これらの例外は、一般に公開されるAPIのようなものでは一般的により有用であると考えています。

回答:


22

通常、プライベートメソッドの場合、例外をスローしません。これは、開発者がメソッドの呼び出し元と呼び出し元を知っている必要があるためです。そのため、プライベートメソッドにパラメーターとして渡される変数は、メソッドの外部で、つまり呼び出す前にチェックする必要があります。「InvalidArgumentException」およびその他のそのような例外をスローすることは、パブリックメソッドの適切なプラクティスと見なされます(「API」を記述しているかどうかに関係なく)。

「InvalidArgumentException」をスローしたい場合には、 Assertバージョン1.1.2以降のSpring API for Javaにクラスます。少なくとも私にとっては、チェックを実行するためのコードを減らすのに非常に役立ちました。

ただし、プライベートメソッドのパラメーターを確認するには、「アサート」を使用できます。それが彼らの本当の目的の一つです。それらを使用するより多くの理由は、次のリンクをチェックしてくださいを。また、アサートを使用するタイミングと例外を使用するタイミングについても説明しています。アサーションは製品コードに含まれず、コンパイラーはデフォルトでそれらを削除します。したがって、彼らはあなたが探しているものです:開発者を助け、ユーザーには見えません。Javaでは、特別なフラグ( "-ea")を使用して、アサーションを有効にするようコンパイラーに指示する必要があります。あなたはそれらを「デバッグ」友達と考えるかもしれません。

アサートの使用方法は次のとおりです。


1
Apacheのコモンズはまた、検証クラスを持っている春のAssertクラスと同様の機能
ローザ・リヒター

@cantidoはい、また、同じように機能するGoogleのGuavaのPreconditionsクラスも追加します。情報をお寄せいただきありがとうございます:-)
ジャレン

2

他のすべてのようにそれは依存します....

パブリックメソッドが(プライベートオーバーロードメソッドの行に沿って)プライベートメソッドを呼び出す単純なラッパーである場合、各パブリックメソッドをチェックインするのではなく、プライベートメソッドで例外をスローすることは理にかなっています。

一般に、上記の定義を満たさない場合、通常、引数を確認したり、プライベートメソッドで例外をスローしたりしません。他の場合もありますが、私は通常、引数が無効な場合に途中で失敗する可能性のある高価な操作を実行する前に、プライベートメソッドでこれを行います。


2

質問には言語タグはありませんが、おそらく暗黙のうちに「コーヒー言語」について話していることを理解しています。しかし、完全を期すために、C ++の世界では見かけ上のコンセンサスが多少異なっていることに言及したいと思います。

C ++プログラマーが通常関心を持っているのは、次の3つのことです。

  • 最適化されたビルドでオーバーヘッドがゼロになりますか?(つまり、「コンパイル」できますか?)
  • エラーが検出された時点でデバッガーにトラップするために使用できますか?
  • 宣言された関数の問題を報告するために使用できますnoexceptか?

過去に、私はこのようなコードを書くことで最初の問題に取り組みました

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

どこで CHECK_ARGSで、#definedはコンパイル時の定数であるため、コンパイラは最適化ビルドのすべての引数チェックコードを完全に削除する場合があります。(チェックアウトをコンパイルすることは一般に良いことだと言っているわけではありませんが、ユーザーがチェックアウトするオプション持っているべきだと思います。)

引数をチェックするコードがはっきりと見えるようにグループ化されているというこのソリューションについてはまだ気に入っています ifます。ただし、2番目と3番目の問題はこれで解決されません。したがって、assert引数のチェックにマクロを使用する方向に再び傾いています。

コーディング標準ブーストはこれに同意します:

プログラマーのエラーはどうですか?

開発者として、使用しているライブラリの前提条件に違反した場合、スタックを巻き戻したくありません。私が欲しいのは、コアダンプまたは同等のものです。問題が検出された正確なポイントでプログラムの状態を検査する方法です。それは通常、assert()またはようなものをします。

CppCon'14でJohn LakosによるDefensive Programming Done Rightpart 1part 2)」というタイトルの非常に興味深い講演がありました)。彼の講演の最初の部分で、彼は契約の理論と未定義の行動について議論します。第二部では、体系的な議論チェックのための非常に良い提案と私が考えるものを提示します。本質的に、彼は、ユーザーが引数チェックのためにライブラリに寄付したい予算の量を選択できるアサーションマクロを提案し、ライブラリにその予算を賢く使用させます。また、ユーザーは、破損した契約が検出された場合に呼び出されるグローバルエラー処理関数をインストールすることもできます。

関数がプライベートであるという側面に関して、これは引数をチェックしないようにする必要があるとは思わない。内部関数の規約に違反しないように、独自のコードをより信頼するかもしれませんが、私たちも完璧ではないことも知っています。内部関数の引数チェックは、クライアントコードのバグを検出するパブリック関数と同様に、独自のバグを検出するのに役立ちます。


1

次の構造を考慮してください。

  1. 内部ロジック:この関数は正しいパラメーターで呼び出されることを前提としているため、アサートを使用して前提条件、事後条件、および不変条件を検証し、内部ロジックをチェックします。

  2. ユーザーインターフェイスのラッパー:この関数は内部関数をラップし、間違った値を処理するために、彼の入力を修正するためにユーザーに伝えるためにInvalidArgumentExceptionsを使用しています Assert(x).hasLength(4);Assume(y).isAlphanumeric();Assert(z).isZipCode();Assume(mailAdress).matchesRegex(regex_MailAdress);Reject(x).ifEmpty();、など

  3. バッチインターフェイスラッパー:この関数は内部関数をラップし、ロギング、有効性マーキング、および統計を使用して、長時間実行されるタスクを中断することなく間違った値を処理します。マーキングは、結果データベースをチェックおよびクリーニングする誰かが後で使用できます。

  4. コマンドラインインターフェイスラッパー:この関数は内部関数をラップし、最後の入力を再度要求します。

アサートと例外の両方を異なるタスクの異なる方法で使用する必要があります。パラメーターのチェックから内部ロジックを分離する必要があります。モデル、ビュー、コントローラーの分離と比較してください。


0

null参照チェックを回避するより良い方法があります。コードコントラクトまたはAOPフレームワークを使用してチェックを行います。Googleの「c#コードコントラクト」または「ポストシャープ」。


私の質問はコード契約にも及ぶと思います。プライベートメソッドでメソッドの前提条件を確認する必要がありますか(つまり、将来のプルーフィングのために、または自分で足を撃てないようにするために)。
ムース氏
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.