2012-06-15 18 views
1

儘管問題是通用的,但我會提到引發查詢的場景。程序模型是否在速度方面過度使用異常處理?

方案

我很感興趣,分析大量的字符串(數字者尤其是)。因此,我的第一份工作是過濾那些甚至包含數字以外的單個字符的那些。

一個簡單的方法來做到這一點(在Java中):

for (String val : stringArray){ 
    try{ 
    int num = Integer.parseInt(val); 
    doSomething(num); 
    } 
    catch(NumberFormatException nfe){} 
} 

其中不得不提的另一點是,在數組中是純數字的字符串只有5%左右。因此,總之,會涉及很多追趕。

我想知道的是,無論這是一種有效的設計方法,還是我應該考慮採用其他方法來做同樣的事情?


結論基於答案:例外確實是昂貴的,它不是一個很好的設計實踐將它們作爲控制語句的一種形式。 因此,人們應該儘可能尋找替代品,並且如果例外情況看起來更加清晰/容易,應該記錄下來。

+0

使用一個分析器來查看什麼在減慢您的程序。你在那裏做的事情本質上是正確的,因爲如果字符串是數字的話沒有其他標準的文本方式。 –

+0

@dystroy:我不是說這會讓程序變慢。它工作正常。但是我的測試案例非常少(大約1000個字符串),但實時可能涉及的不僅僅是這些。再一次,它的純粹推測,因爲我不知道異常處理如何在java中工作,但我猜一個異常可能有某種繼承樹。所以如果有異常,它會嘗試並找出在不同的類中引發了哪個異常。此外,拋出異常似乎是停止代碼流的嚴酷方式,不是嗎? (我在開玩笑) –

+2

這是一種苛刻的方式,是的,但這就是java的製作方式:在許多情況下(如這個),它是標準的分支方式。 –

回答

2

你在這裏做的事情本質上是正確的,因爲在java中沒有其他標準方法來檢查字符串是否是數字。

如果a profiling證明你這個操作太長,你可以嘗試自己動手爲in the parseInt method但JVM將不能夠做同樣的優化,所以我不建議這樣做。您會看到JVM經過了大量優化以處理異常,並且它很好地完成了這項工作。

這樣的好奇心,這裏有幾個方法可以做到這一點在Java中:

http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#Java

鏈接到其他語言,但您的解決方案是標準和習慣之一,我懷疑你會發現通過改寫其作爲例如一個很大的區別:

private static final boolean isNumeric(final String s) { 
    if (s == null || s.isEmpty()) return false; 
    for (int x = 0; x < s.length(); x++) { 
    final char c = s.charAt(x); 
    if (x == 0 && (c == '-')) continue; // negative 
    if ((c >= '0') && (c <= '9')) continue; // 0 - 9 
    return false; // invalid 
    } 
    return true; // valid 
} 

利用這一點,在我看來,是過早的優化導致少維護的代碼的典型案例。

+0

這真的很有幫助。非常感謝! –

0

這是不太可能在您的應用程序的大背景下多大關係。這樣的微觀優化很難想象。

更好的辦法是,以儘可能乾淨,然後測量,看看它的性能和瓶頸在哪裏,如果有的話,存在編寫代碼。如果你發現你的表現不可接受,找到最大的瓶頸,並儘可能解決它;沖洗並重復,直到性能可接受爲止。

的問題是,我們沒有人有足夠的智慧「知道」裏的問題會。你最好用數據進行優化而不是猜測。

在你的情況,這是一個未經檢查的異常。你可以忽略它,但那意味着一個壞字符串會把你從循環中移出。將catch放在循環中允許您容忍那些數字解析失敗並繼續運行的小部分輸入字符串。

0

檢查僅限數字的字符串的非異常方法是使用正則表達式。例如:

基於
public static void main(String[] args) throws Exception { 
    String[] array = { 
      "abc", 
      "123", 
      "12A", 
    }; 
    Pattern p = Pattern.compile("\\d*"); 
    for (String s: array) { 
     Matcher m = p.matcher(s); 
     if (m.matches()) { 
      System.out.println(s); 
     } 
    } 
} 

異常處理可能是昂貴的。

正則表達式不是最快的。

試試看看哪個更快。

+1

這不會讓它變得更快。 –

+0

@sudocode:*基於異常的處理可能很昂貴。*您能否詳細說明/指導我如何處理* how *? –

+0

我的答案中的代碼示例顯示瞭如何。在示例執行'System.out.println(s)'的時候,你可以調用'Integer.parseInt(s)'的值,而不會引發異常。 – sudocode

1

效率不高。 您可以查看網絡上的大量資源,瞭解爲什麼拋出異常會被視爲昂貴,例如:http://www.yoda.arachsys.com/csharp/exceptions.html

不幸的是,Java並沒有提供這樣的實用方法OOTB(如C#的tryParse)。您可以枚舉字符串的字符並使用Character.isDigit方法(您甚至可以將驗證和轉換交織爲一個int)。

異常應該用於異常終止某些流程。 執行可能引發異常的操作時,應該始終考慮是否可以執行檢查來節省成本,特別是處理異常的代碼。例如,檢查一個字符串是否是一個數字,而不是試圖解析它,並依靠異常機制來告訴你它是否不是。

相關問題