37

Java には null 許容型がなく、TryParse() もないため、例外をスローせずに入力の検証をどのように処理しますか?

通常の方法:

String userdata = /*value from gui*/
int val;
try
{
   val = Integer.parseInt(userdata);
}
catch (NumberFormatException nfe)
{
   // bad data - set to sentinel
   val = Integer.MIN_VALUE;
}

正規表現を使用して解析可能かどうかを確認できますが、それも多くのオーバーヘッドのようです。

この状況を処理するためのベスト プラクティスは何ですか?

編集: 理論的根拠: 例外処理について SO について多くの議論があり、一般的な態度は、例外は予期しないシナリオにのみ使用する必要があるというものです。ただし、悪いユーザー入力はまれではなく、予期されていると思います。はい、それは本当に学問的なポイントです。

さらに編集:

一部の回答は、SO の何が問題なのかを正確に示しています。聞かれている質問を無視して、それとは関係のない別の質問に答えます。質問は、レイヤー間の移行について尋ねているのではありません。質問は、数値が解析できない場合に何を返すかを尋ねているわけではありません。ご存じのとおり、val = Integer.MIN_VALUE; この完全にコンテキスト フリーのコード スニペットが取得されたアプリケーションに最適なオプションです。

4

16 に答える 16

28

この解析を行うためのメソッドを備えたオープンソースのユーティリティ ライブラリがあるかどうかを尋ねたところ、答えはイエスです。

Apache Commons LangからNumberUtils.toIntを使用できます。

// returns defaultValue if the string cannot be parsed.
int i = org.apache.commons.lang.math.NumberUtils.toInt(s, defaultValue);

Google GuavaからInts.tryParseを使用できます:

// returns null if the string cannot be parsed
// Will throw a NullPointerException if the string is null
Integer i = com.google.common.primitives.Ints.tryParse(s);

例外をスローせずに数値を解析する独自のメソッドを作成する必要はありません。

于 2013-05-22T18:24:34.060 に答える
17

ユーザー提供のデータの場合、Integer.parseIntは国際化をサポートしていないため、通常は間違ったメソッドです。パッケージはあなたのjava.text(冗長な)友達です。

try {
    NumberFormat format = NumberFormat.getIntegerInstance(locale);
    format.setParseIntegerOnly(true);
    format.setMaximumIntegerDigits(9);
    ParsePosition pos = new ParsePosition(0);
    int val = format.parse(str, pos).intValue();
    if (pos.getIndex() != str.length()) {
        // ... handle case of extraneous characters after digits ...
    }
    // ... use val ...
} catch (java.text.ParseFormatException exc) {
    // ... handle this case appropriately ...
}
于 2008-10-06T15:05:00.090 に答える
16

基本的にエラーコードとして使用しているものに使用するのが正しいと確信していない限り、MIN_VALUE を返すことはちょっと疑わしいですが、それだけです。ただし、少なくとも、エラー コードの動作を文書化します。

(アプリケーションによっては) 不正な入力をログに記録してトレースできるようにすることも役立つ場合があります。

于 2008-10-06T14:32:07.723 に答える
11

あなたのアプローチの問題は何ですか?そのようにしても、アプリケーションのパフォーマンスがまったく損なわれるとは思いません。それが正しいやり方です。時期尚早に最適化しないでください

于 2008-10-06T14:32:22.387 に答える
6

私はそれが悪い形だと確信していUtilities.tryParseInt(String value)ますが、文字列が解析できない場合は 0 を返し、例外がスローUtilities.tryParseInt(String value, int defaultValue)された場合に使用する値を指定できるようにする一連の静的メソッドを Utilities クラスに持っています。parseInt()

悪い入力に対して既知の値を返すことが完全に許容される場合があると思います。非常に不自然な例: ユーザーに YYYYMMDD 形式の日付を要求すると、間違った入力が返されます。プログラムの要件に応じて、Utilities.tryParseInt(date, 19000101)または同様のことを行うことは完全に許容される場合があります。Utilities.tryParseInt(date, 29991231);

于 2008-10-06T14:38:13.920 に答える
3

記事の下の方で stinkyminky が指摘していたことをもう一度述べます。

ユーザー入力 (または構成ファイルからの入力など) を検証する一般的に受け入れられているアプローチは、実際にデータを処理する前に検証を使用することです。ほとんどの場合、これは適切な設計上の動きですが、解析アルゴリズムが複数回呼び出される可能性があります。

ユーザー入力を適切に検証したことがわかったら、それを解析して無視するか、ログに記録するか、RuntimeException に NumberFormatException に変換しても問題ありません。

このアプローチでは、モデルを 2 つの部分に分けて検討する必要があることに注意してください。ビジネス モデル (int または float 形式の値を実際に気にする場所) とユーザー インターフェイス モデル (ユーザーが何を入力してもかまわないようにしたい場所) です。欲しいです)。

データをユーザー インターフェイス モデルからビジネス モデルに移行するには、検証ステップを通過する必要があります (これはフィールドごとに発生する可能性がありますが、ほとんどのシナリオでは、構成されているオブジェクト全体の検証が必要です)。 .

検証が失敗した場合、ユーザーには、何が間違っていたかを知らせるフィードバックが表示され、それを修正する機会が与えられます。

JGoodies Binding や JSR 295 などのバインド ライブラリを使用すると、この種の実装が想像以上に簡単になります。また、多くの Web フレームワークは、ユーザー入力を実際のビジネス モデルから分離する構造を提供し、検証が完了した後にのみビジネス オブジェクトを設定します。

構成ファイルの検証 (いくつかのコメントで示されている別の使用例) に関しては、特定の値がまったく指定されていない場合にデフォルトを指定することは 1 つの方法ですが、データの形式が間違っている場合 (誰かが ' 「ゼロ」の代わりに「ああ」 - または、MS Word からコピーしたもので、すべてのバックティックがファンキーな Unicode 文字になっている場合)、何らかのシステム フィードバックが必要です (実行時例外をスローしてアプリに失敗しているだけであっても)。 .

于 2008-10-07T03:54:15.233 に答える
2

これが私がそれをする方法です:

public Integer parseInt(String data) {
  Integer val = null;
  try {
    val = Integer.parseInt(userdata);
  } catch (NumberFormatException nfe) { }
  return val;
}

次に、nullは無効なデータを示します。デフォルト値が必要な場合は、次のように変更できます。

public Integer parseInt(String data,int default) {
  Integer val = default;
  try {
    val = Integer.parseInt(userdata);
  } catch (NumberFormatException nfe) { }
  return val;
}
于 2008-10-06T15:13:30.900 に答える
1

試してみてくださいorg.apache.commons.lang.math.NumberUtils.createInteger(String s)。それは私を大いに助けました。ダブル、ロングなどにも同様の方法があります。

于 2012-12-05T15:23:22.110 に答える
1

ベストプラクティスはあなたが示すコードだと思います。

オーバーヘッドがあるため、正規表現の代替手段は使用しません。

于 2008-10-06T14:32:16.210 に答える
0

整数を使用できますが、値が正しくない場合は null に設定できます。Java 1.6 を使用している場合は、自動ボックス化/ボックス化解除が提供されます。

于 2008-10-06T14:41:21.683 に答える
-1

上記のコードは、次のコードと同等であるため、不適切です。

// this is bad
int val = Integer.MIN_VALUE;
try
{
   val = Integer.parseInt(userdata);
}
catch (NumberFormatException ignoreException) { }

例外は完全に無視されます。また、ユーザーが-2147483648(Integer.MIN_VALUE)を渡すことができるため、マジックトークンは不良です。

一般的な解析可能な質問は有益ではありません。むしろ、それは文脈に関連しているべきです。アプリケーションには特定の要件があります。メソッドを次のように定義できます

private boolean isUserValueAcceptable(String userData)
{
   return (    isNumber(userData)    
          &&   isInteger(userData)   
          &&   isBetween(userData, Integer.MIN_VALUE, Integer.MAX_VALUE ) 
          );
}

要件を文書化し、明確に定義されたテスト可能なルールを作成できる場合。

于 2008-10-06T15:01:08.867 に答える
-1

あなたが言ったように(isParsable())事前にテストすることで例外を回避できる場合は、より良いかもしれませんが、すべてのライブラリがそれを念頭に置いて設計されているわけではありません。

私はあなたのトリックを使用しましたが、組み込みシステムのスタックトレースは、キャッチするかどうかに関係なく出力されるため、最悪です:(

于 2008-10-06T16:04:21.670 に答える
-2

NumberFormatExceptionとしてのInteger.MIN_VALUEは悪い考えです。

Project Coinにプロポーザルを追加して、このメソッドをIntegerに追加できます

@Nullable public static Integer parseInteger(String src)...不正な入力に対してnullを返します

次に、ここにあなたの提案へのリンクを入れてください。そうすれば、私たち全員がそれに投票します!

PS:この http://msdn.microsoft.com/en-us/library/bb397679.aspxを見てください。 これは、いかに醜く肥大化する可能性があるかです。

于 2010-12-03T12:18:07.427 に答える
-2

例外メカニズムは、応答値と組み合わせてステータス インジケーターを取得する唯一の方法であるため、価値があります。さらに、ステータスインジケーターも標準化されています。エラーが発生した場合は、例外が発生します。そうすれば、エラー インジケーターを自分で考える必要がなくなります。論争は例外ではなく、チェックされた例外 (たとえば、キャッチまたは宣言する必要があるもの) に関するものです。

個人的には、例外が本当に価値のある例の 1 つを選んだと思います。ユーザーが間違った値を入力することはよくある問題であり、通常は正しい値についてユーザーに連絡する必要があります。ユーザーに尋ねた場合、通常、デフォルト値に戻すことはありません。ユーザーに自分の入力が重要であるという印象を与えます。

例外を処理したくない場合は、RuntimeException (または派生クラス) でラップするだけで、コード内の例外を無視できます (例外が発生した場合はアプリケーションを強制終了します。場合によっては問題ありません)。

NumberFormat の例外を処理する方法の例: Web アプリの構成データ:

loadCertainProperty(String propVal) {
  try
  {
    val = Integer.parseInt(userdata);
    return val;
  }
  catch (NumberFormatException nfe)
  { // RuntimeException need not be declared
    throw new RuntimeException("Property certainProperty in your configuration is expected to be " +
                               " an integer, but was '" + propVal + "'. Please correct your " +
                               "configuration and start again");
    // After starting an enterprise application the sysadmin should always check availability
    // and can now correct the property value
  }
}

GUI で:

public int askValue() {
  // TODO add opt-out button; see Swing docs for standard dialog handling
  boolean valueOk = false;
  while(!valueOk) {
    try {
      String val = dialog("Please enter integer value for FOO");
      val = Integer.parseInt(userdata);
      return val; 
    } catch (NumberFormatException nfe) {
      // Ignoring this; I don't care how many typo's the customer makes
    }
  }
}

Web フォーム: 有用なエラー メッセージと修正の機会を含むフォームをユーザーに返します。ほとんどのフレームワークは、標準化された検証方法を提供します。

于 2008-10-06T18:12:02.507 に答える
-5

その前に if ステートメントをいくつか置きます。if (null != ユーザーデータ)

于 2008-10-06T14:31:44.963 に答える