5

多くのスローされた例外がアプリケーションのパフォーマンスに及ぼす影響は誰もが知っているため、制御フローに例外を使用するなどのことは避ける必要があります。この声明の後、私はコーディング時にこれについてあまり気にしなかったことを告白しなければなりません. 私は主に Java プラットフォームで作業してきましたが、最近は .NET プラットフォームで作業していてpublic static bool TryParse(string s,out int result) 、例外を発生させずに String を int に変換できる便利なメソッドを見つけました。その瞬間から、私はそれを使い続けています。public static bool TryParse(string s,out int result)またはの使用に関する好みについてお聞きしたかっただけですpublic static int ToInt32(string value)

そして、Java の観点からは、次のような方法で取得できるにもかかわらず、そのような同様のメソッドが欠落していることを指摘するだけです。

boolean isInteger = Pattern.matches("^\d*$", myString);

ありがとう。

4

5 に答える 5

7

はい、Java には同様のメソッドがありませんが、outパラメーターがないと、表現するのは実際にはかなり困難です (プリミティブを返したい場合)。ただし、通常、C# ではTryParse、値が整数ではないことが予想される場合やToInt32そうでない場合に使用する必要があります。このように、「例外的な」状況はそのように扱われます。

特に、パフォーマンスが主な理由であるTryParse場合、投稿する正規表現一致メソッドはかなり悪いです。例外のパフォーマンスの「費用」 (実際には非常にわずかです) は、それらを誤って使用すると、制御フローの簡単な理解が曖昧になる可能性があるため、はるかに小さくなります。

于 2009-05-27T10:39:53.723 に答える
3

C# についてはわかりませんが、Java の例外は、実際にスローされたときにのみ高価ですが、実際には非常に高価です。文字列の大部分が無効であると予想される場合は、正規表現を使用していても、最初に検証する価値があります。

String.matches()ただし、正規表現を使用またはPattern.matches()適用しないでください。これらのメソッドは、呼び出すたびに正規表現を再コンパイルします。代わりに、事前に正規表現をコンパイルして Pattern オブジェクトとして保存し、それを使用して検証を行います。Integer.parseInt()私のテストでは、20% が無効であった 10,000 個の文字列のリストを解析し、パターンによる事前検証は、単独で使用して例外をキャッチするよりもほぼ 2 倍高速です。

ただし、この議論は、タイトなループで多くの変換を行っている場合にのみ適用されます。ユーザー入力を受け入れるときのように、たまにしか実行しない場合Integer.parseInt()は、検証を実行しても問題ありません。また、正規表現で検証することを選択した場合は、よりもはるかに優れた正規表現が必要になります。^\d*$その正規表現は、空の文字列と より大きい「数値」Integer.MAX_VALUEに一致し、負の数にはまったく一致しません。

于 2009-05-27T12:35:19.170 に答える
1

Java でその目的のために、(commons-lang で) よく知られている StringUtils を使用できます。このクラスにはメソッドisNumericがあります。

おそらく、それらの人がその関数のために書いたコードを見ることができます:

public static boolean isNumeric(String str) {
  if (str == null) {
    return false;
  }
  int sz = str.length();
  for (int i = 0; i < sz; i++) {
    if (Character.isDigit(str.charAt(i)) == false) {
      return false;
    }
  }
  return true;
 }

これが最も効率的な方法だと言っているわけではありませんが、正規表現を使用しない別の方法があります。幸運を!

于 2009-05-27T11:03:40.353 に答える
1

そして、Java の観点からは、次のような方法で取得できるにもかかわらず、そのような同様のメソッドが欠落していることを指摘するだけです。

boolean isInteger = Pattern.matches("^\d*$", myString);

Integer.parseInt(myString)例外がスローされるかどうかを予測するには、さらに作業が必要です。文字列は . で始まる場合があり-ます。また、int の有効桁数は 10 桁を超えることはできません。したがって、より信頼できる表現は^-?0*\d{1,10}$. しかし、この式でもすべての Exception を予測することはできません。これはまだ不正確すぎるためです。

信頼できる正規表現を生成することが可能です。しかし、それは非常に長いでしょう。parseInt が例外をスローするかどうかを正確に判断するメソッドを実装することもできます。次のようになります。

static boolean wouldParseIntThrowException(String s) {
    if (s == null || s.length() == 0) {
        return true;
    }

    char[] max = Integer.toString(Integer.MAX_VALUE).toCharArray();
    int i = 0, j = 0, len = s.length();
    boolean maybeOutOfBounds = true;

    if (s.charAt(0) == '-') {
        if (len == 1) {
            return true; // s == "-"
        }
        i = 1;
        max[max.length - 1]++; // 2147483647 -> 2147483648
    }
    while (i < len && s.charAt(i) == '0') {
        i++;
    }
    if (max.length < len - i) {
        return true; // too long / out of bounds
    } else if (len - i < max.length) {
        maybeOutOfBounds = false;
    }
    while (i < len) {
        char digit = s.charAt(i++);
        if (digit < '0' || '9' < digit) {
            return true;
        } else if (maybeOutOfBounds) {
            char maxdigit = max[j++];
            if (maxdigit < digit) {
                return true; // out of bounds
            } else if (digit < maxdigit) {
                maybeOutOfBounds = false;
            }
        }
    }
    return false;
}

ただし、どのバージョンがより効率的かはわかりません。そして、どのようなチェックが合理的であるかは、主にコンテキストに依存します。

C#で文字列を変換できるかどうかを確認するには、TryParse を使用します。そして、それが true を返した場合、副産物として同時に変換されました。これは優れた機能であり、例外をスローする代わりに parseInt を再実装して null を返すだけで問題が発生することはありません。

しかし、解析メソッドを再実装したくない場合でも、状況に応じて使用できる一連のメソッドを手元に用意しておくと便利です。それら次のようになります。

private static Pattern QUITE_ACCURATE_INT_PATTERN = Pattern.compile("^-?0*\\d{1,10}$");

static Integer tryParseIntegerWhichProbablyResultsInOverflow(String s) {
    Integer result = null;
    if (!wouldParseIntThrowException(s)) {
        try {
            result = Integer.parseInt(s);
        } catch (NumberFormatException ignored) {
            // never happens
        }
    }
    return result;
}

static Integer tryParseIntegerWhichIsMostLikelyNotEvenNumeric(String s) {
    Integer result = null;
    if (s != null && s.length() > 0 && QUITE_ACCURATE_INT_PATTERN.matcher(s).find()) {
        try {
            result = Integer.parseInt(s);
        } catch (NumberFormatException ignored) {
        // only happens if the number is too big
        }
    }
    return result;
}

static Integer tryParseInteger(String s) {
    Integer result = null;
    if (s != null && s.length() > 0) {
        try {
            result = Integer.parseInt(s);
        } catch (NumberFormatException ignored) {
        }
    }
    return result;
}

static Integer tryParseIntegerWithoutAnyChecks(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException ignored) {
    }
    return null;
}
于 2010-12-11T15:03:16.783 に答える
0

public static bool TryParse(string s,out int result) または public static int ToInt32(string value) の使用に関する好みについてお聞きしたいだけです。

はい、値が常に有効であることを期待する場合を除いて、TryParse を使用します。例外を使用するよりも読みやすいことがわかりました。例外が必要な場合でも、通常はメッセージをカスタマイズするか、独自のカスタム例外をスローします。したがって、TryParse を使用して、手動で例外をスローします。

Java と C# の両方で、可能な限り最小限の例外セットをキャッチしようとしています。Java では、Number.ValueOf(...); への応答として、NullPointerException と NumberFormatException を個別にキャッチする必要があります。または、「例外」をキャッチして、意図しないものをキャッチするリスクを冒すこともできます。C# の TryParse では、その心配はまったくありません。

于 2009-05-27T16:48:40.703 に答える