web-dev-qa-db-ja.com

Int to String in Java-不良データの可能性が高いため、例外を回避する必要がある

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;この完全にコンテキストのないコードスニペットが使用されたアプリケーションにぴったりのオプションです。

37
Chris Cudmore

MIN_VALUEを返すことは、疑いの種ですが、エラーコードとして本質的に使用しているものに使用するのが正しいことであると確信しない限り、それはほとんどそれです。ただし、少なくともエラーコードの動作は文書化する必要があります。

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

16
Steve B.

この解析を行うメソッドを備えたオープンソースのユーティリティライブラリがある場合 で、答えはイエスです!

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);

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

27

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

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 ...
}
17

アプローチの問題点は何ですか?そのようにすると、アプリケーションのパフォーマンスがまったく低下するとは思わない。それが正しい方法です。 時期尚早に最適化しない

11
asterite

私はそれが悪い形式だと確信していますが、文字列が解析できない場合に0を返すUtilities.tryParseInt(String value)Utilities.tryParseInt(String value, int defaultValue)が例外をスローする場合に使用する値を指定できるparseInt()のようなことを行うユーティリティクラスの静的メソッドのセットがあります。

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

6
Grant Wagner

Stinkyminkyが投稿の下部に向けて作成したポイントを再度説明します。

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

ユーザー入力を適切に検証したことがわかったら、thenを解析し、NumberFormatExceptionをRuntimeExceptionに無視、記録、または変換しても安全です。

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

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

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

JGoodies BindingやJSR 295のようなバインディングライブラリは、この種のことを思ったよりもはるかに簡単に実装できるようにします。また、多くのWebフレームワークは、ユーザー入力を実際のビジネスモデルから分離する構成を提供し、検証が完了した後にのみビジネスオブジェクトを生成します。

構成ファイルの検証(コメントの一部に示されている他の使用事例)に関して、特定の値がまったく指定されていない場合にデフォルトを指定することは1つです。ただし、データのフォーマットが間違っている(「 「ゼロ」の代わりに「ああ」-またはMS Wordからコピーし、すべてのバックティックにファンキーなユニコード文字を取得した)、何らかの種類のシステムフィードバックが必要です(ランタイム例外をスローしてアプリを失敗させるだけでも) 。

3
Kevin Day

以下にその方法を示します。

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;
}
2
noah

org.Apache.commons.lang.math.NumberUtils.createInteger(String s)を試してください。それはとても助けになりました。 double、longなどについても同様の方法があります。

1
Zlosny

ベストプラクティスは、表示するコードだと思います。

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

1
Shimi Bandiel

よりクリーンなセマンティクス(Java 8 OptionalInt)

Java 8+の場合、おそらく、RegExを使用して事前にフィルター処理を行い(ご指摘の例外を回避するため))、結果をオプションのプリミティブにラップします(「デフォルト」問題に対処するため) ):

_public static OptionalInt toInt(final String input) {
    return input.matches("[+-]?\\d+") 
            ? OptionalInt.of(Integer.parseInt(input)) 
            : OptionalInt.empty();
}
_

多数の文字列入力がある場合、flatMap()を実行できるように、IntStreamではなくOptionalIntを返すことを検討できます。

参照資料

0
AjahnCharles

整数を使用できます。値が悪い場合は、nullに設定できます。 Java 1.6を使用している場合、自動ボクシング/アンボクシングが提供されます。

0
Milhous