2009-05-27 42 views
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)的偏好。Convert.ToInt32與TryParse

而且從爪哇點,只是指出,它缺少這樣一個類似的方法,儘管我們可以得到它貫穿東西,如:

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

感謝。

回答

7

是的,Java缺少一個類似的方法,雖然沒有out參數,但它實際上很難表達(同時想要返回一個原語)。一般來說,在C#中,如果您希望該值有時不是整數,則應使用TryParse,否則應使用ToInt32;這種「特殊」情況就是這樣對待的。

特別是如果表現是您想要的TryParse的主要原因,那麼您發佈的正則表達式匹配方法會更糟糕。 Exceptions(實際上,非常小)的性能「開支」被錯誤地使用它們的程度超出了對控制流的容易理解的程度。

+0

BTW,有將是獲得在Java的替代方式。一個是使用Integer而不是int,另一個是將int放入一個數組並將其傳遞給該方法。 – 2009-05-29 07:31:51

+0

是的,這就是爲什麼我提到「想要返回原始」部分。這是可能的,但從來沒有整齊,基本上。 – Calum 2009-06-03 16:17:56

1

爲此在Java中,你可以使用衆所周知StringUtils的(對公地郎),這個類有一個方法isNumeric

也許你可以去看看的代碼,那些傢伙有寫that function

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

我不是說這是最有效的方式來做到這一點,但有沒有使用正則表達式的另一種選擇。 祝你好運!

3

我不知道C#,但是在Java中,異常只在實際拋出時很貴,但確實非常昂貴。如果你期望有很大一部分字符串是無效的,那麼即使你使用了正則表達式,也是值得的。

但是不要使用String.matches()Pattern.matches()來應用正則表達式;這些方法每次調用它們時都會重新編譯正則表達式。相反,提前編譯正則表達式並將其保存爲Pattern對象,然後使用它進行驗證。在我的測試中,解析一個包含20%無效的10,000個字符串的列表,使用Pattern進行預驗證幾乎是單獨使用Integer.parseInt()的兩倍,並捕獲異常。

但是,本討論僅適用於在緊密循環中進行大量轉換的情況。如果你只是偶爾做一次,比如當你接受用戶輸入時,讓Integer.parseInt()做驗證是好的。如果您選擇使用正則表達式進行驗證,則需要比^\d*$更好的正則表達式 - 該正則表達式將匹配空字符串以及大於Integer.MAX_VALUE的「數字」,並且它根本不匹配負數。

0

我只想問你關於使用public static bool TryParse(string s,out int result)或public static int ToInt32(string value)的偏好。

是的,我使用TryParse除了在那裏我預計值總是是有效的。我發現它比使用例外更清晰。即使我想要一個異常,我通常要定製消息或拋出自己的自定義異常;因此,我使用TryParse並手動拋出異常。

在Java和C#中,我都試圖捕獲最少的例外。在Java中,這意味着我必須分別捕獲NullPointerException和NumberFormatException以響應Number.ValueOf(...);或者,我可以捕捉「例外」並冒險捕捉意想不到的東西。用C#中的TryParse,我根本不用擔心。

1

而且從爪哇點, 只是指出,它缺少這樣的 類似的方法,儘管我們可以得到 它貫穿東西,如:

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

預測是否Integer.parseInt(myString)會拋出一個Exception有更多的工作要做。該字符串可以以-開頭。另外一個int不能超過10位有效數字。所以更可靠的表達是^-?0*\d{1,10}$。但即使這種表達方式也不能預測每個異常,因爲它仍然不夠精確。

生成可靠的正則表達式是可能的。但會很長。也可以實現一個精確確定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; 
}