2009-05-27 7 views
5

Мы все знаем, какие эффекты могут быть вызваны множеством исключений из-за производительности наших приложений, поэтому мы должны избегать таких вещей, как использование исключений для потока управления. После этого заявления я должен признаться, что при кодировании мне было все равно, что об этом. Я работал в основном на платформе Java, но в последнее время я делал это на платформе .NET и только что нашел этот удобный метод: public static bool TryParse(string s,out int result) , который позволяет вам преобразовать строку в int без создания исключения. С этого момента я продолжаю использовать его. Я просто хотел спросить вас о ваших предпочтениях относительно использования public static bool TryParse(string s,out int result) или public static int ToInt32(string value).Convert.ToInt32 по сравнению с TryParse

И с точки зрения Java, просто указав, что он отсутствует такой подобный метод, несмотря мы могли получить его через такие вещи, как:

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

Спасибо.

ответ

7

Да, Java отсутствует аналогичный метод, хотя без параметров out на самом деле его довольно сложно выразить (желая вернуть примитив). Как правило, в C# вы должны использовать TryParse, если вы ожидаете, что значение иногда не будет целочисленным, а ToInt32; таким образом, «исключительная» ситуация рассматривается как таковая.

В частности, если производительность является основной причиной для получения TryParse, метод регулярных выражений, который вы публикуете, значительно хуже. Выполнение «расхода» Исключений (которое на самом деле очень минимально) затмевается тем, насколько их использование ошибочно может затруднить понимание потока управления.

+0

Кстати, было бы альтернативные способы получения, что в Java. Можно было бы использовать Integer вместо int, а другой - поместить int внутри массива и передать его методу. –

+0

Да, именно поэтому я упомянул о «желании вернуть примитивную» часть. Это возможно, но никогда не бывает аккуратно. – Calum

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

Я не говорю, что это самый эффективный способ сделать это, но есть еще одна альтернатива для вас без использования регулярных выражений. Удачи!

+1

Что с этим «== ложным» материалом? Я не могу поверить, что вижу это в исходном коде Apache! –

+1

Проблема с «== false» - это то, что происходит, если вы случайно используете только одно «=». Тип выражения по-прежнему является логическим, поэтому он компилируется, но вы получаете то, что может быть тонкой, прерывистой ошибкой. Это просто хорошая привычка выбраться. –

+0

if (! Character.isDigit (str.charAt (i))) –

3

Я не знаю о C#, но в исключениях Java стоят только дорого, когда их действительно бросают, но тогда они очень дороги. Если вы ожидаете, что значительная часть строк будет недействительной, стоит сначала проверить их, даже если вы используете регулярное выражение.

Но не используйте String.matches() или Pattern.matches() для применения регулярного выражения; эти методы перекомпилируют регулярное выражение каждый раз, когда вы их вызываете. Вместо этого скопируйте регулярное выражение раньше времени и сохраните его как объект Pattern, а затем выполните проверку с этим. В моих тестах разбор списка из 10 000 строк, из которых 20% были недействительными, предварительная валидация с помощью шаблона почти в два раза быстрее, чем использование Integer.parseInt() и устранение исключений.

Однако это обсуждение применимо только в том случае, если вы делаете много конверсий в узком цикле. Если вы делаете это только время от времени, например, когда вы принимаете ввод пользователя, разрешение Integer.parseInt() делает проверку правильной. И если вы решите проверить с помощью регулярного выражения, вам понадобится гораздо лучшее регулярное выражение, чем ^\d*$ - это регулярное выражение будет соответствовать пустой строке, а также «номера» больше Integer.MAX_VALUE, и она не будет соответствовать отрицательным числам вообще.

0

Я просто хотел спросить вас о ваших предпочтениях относительно использования public static bool TryParse (string s, out int result) или public static int ToInt32 (строковое значение).

Да, я использую TryParse кроме случаев, когда я ожидаю, что значение всегда быть действительным. Я считаю, что он читает чище, чем с помощью исключений. Даже если я хочу исключение, я обычно хочу настроить сообщение или выбросить собственное собственное исключение; следовательно, я использую TryParse и вручную выдаю исключение.

Как в Java, так и в C#, я пытаюсь уловить минимум набор исключений. В Java это означает, что я должен отдельно перехватывать NullPointerException и NumberFormatException в ответ на Number.ValueOf (...); альтернативно, я могу поймать «Исключение» и рискнуть чем-то непреднамеренным. С TryParse в C# я вообще об этом не беспокоюсь.

1

И с точки зрения Java, просто указав, что он отсутствует такой подобный метод, несмотря мы могли бы получить это через такие вещи, как:

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

Чтобы если Integer.parseInt(myString) предсказать будет бросать исключение, есть еще много работы. Строка может начинаться с -. Кроме того, 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; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^