Улавливает ли NumberFormatException плохую практику?

Мне нужно проанализировать строку, которая может принимать шестнадцатеричные значения или другие значения без шестнадцатеричных

0xff, 0x31 или A, PC, label и т.д.

Я использую этот код для разделения двух случаев:

String input = readInput();

try {
    int hex = Integer.decode(input);            
    // use hex ...

} catch (NumberFormatException e) {
   // input is not a hex, continue parsing
}

Можно ли считать этот код "уродливым" или трудночитаемым? Существуют ли другие (возможно, более элегантные) решения?

EDIT: Я хочу уточнить, что (в моем случае) неверный ввод не существует: мне просто нужно различать, является ли это шестнадцатеричным номером, или нет. И только для полноты, я делаю простой assebler для DCPU-16.

Ответ 1

Обработка исключений является неотъемлемой частью (и одной из целей дизайна) языка программирования Java... вы не должны отбрасывать их только потому, что считаете, что они "уродливые".

Тем не менее, если вы хотите простой и понятный способ обработки NumberFormatException s, вы можете вместо этого использовать класс NumberUtils,

Метод toInt(String str, int defaultValue) преобразует String в int, возвращая значение по умолчанию, если преобразование завершается с ошибкой. Если строка null, возвращается значение по умолчанию.

 NumberUtils.toInt(null, 1) = 1
 NumberUtils.toInt("", 1)   = 1
 NumberUtils.toInt("1", 0)  = 1

Метод инкапсулирует захват и обработку исключений, как показано в исходный код ниже. В результате клиенту требуется только один вызов метода.

public static int toInt(String str, int defaultValue) {         
    if(str == null) {
        return defaultValue;
    }
    try {
        return Integer.parseInt(str);
    } catch (NumberFormatException nfe) {
        return defaultValue;
    }
}

Ответ 2

Ваш второй вопрос, который я видел сегодня, спрашивая об этом.

Нет, это прекрасно подходит для исключения этого исключения.

И это определенно лучше форма, чтобы поймать более явное исключение (например, "NumberFormatException" ), чем общее "Исключение".

ИМХО...

PS: Где вы помещаете исключение: на этом уровне или выше, это другой вопрос.

Эмпирическое правило - это "самый низкий уровень, где вы знаете, что произошло, и как лучше всего восстановить".

Или, иначе говоря (цитируя ссылку ниже):

"Метод должен поймать исключение только тогда, когда он сможет обработать его каким-то разумным способом".

Вот несколько обсуждений:

Ответ 3

Нет, это не "плохая практика". Это просто зависит от ситуации.

Например, в качестве Android, если пользователь вводит строку "123a" в текстовое поле, которое должно принимать только целые числа, а затем анализируется, будет вызываться исключение, вызывающее сбой приложения. В этом случае было бы разумно поймать исключение и предложить пользователю повторно ввести текст.

Ответ 4

В вашем случае я бы предпочел бы что-то вроде метода isHexDigit использовать NumberFormatException, если не будут допущены некоторые предположения, которые вы можете сделать о формате ваших данных, - из вашего описания кажется, что таких предположений нет о том, когда вы столкнетесь с шестнадцатеричными числами или без шестнадцатеричных чисел.

Это связано с тем, что для обработки исключительных условий следует использовать исключения, и если ожидания от ваших данных: либо шестнадцатеричные цифры, либо шестнадцатеричные цифры, разделенные пробелами, то нет ничего исключительного в том, что вы сталкиваетесь с токеном, отличным от шестнадцатеричный разряд.

Кроме того, использование Exception делает код менее читаемым: без комментариев о данных он скрывает тот факт, что вкрапленные без шестнадцатеричных цифр являются приемлемыми и ожидаемыми вводами.

Сформулировав это предпочтение, я мог бы использовать обработку исключений для обработки этого случая, и я, конечно, вижу много кода, который делает это. В этой комбинации декодирования /parseInt/NumberFormatException добавляется множество хороших функциональных возможностей. Я бы не использовал это без явного комментария, который четко объясняет, что я делаю.

Ответ 5

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

Ответ 6

Его Not about how good you code looks, но how good your code works.......... Ya offcourse it should be readable, Как хорошо сказано...

Любой дурак может написать код, который может понять компьютер, но только отличные программисты пишут коды, которые люди могут понять.

Совершенно прекрасно в некоторых случаях, когда вам нужно иметь такие исключения на месте.

When you want to catch multiple exceptions which belong to the same inheritance tree, then create a try block, and multiple catch blocks from more specific to more abstract.

например:

`Animal <--- Carnivores <--- Dog`

Теперь предположим, что существует DogException, CarnivoresException, AnimalException.

Тогда он должен быть таким,

try{

           // your code 

     }
      catch(DogException d){}
      catch(CarnivoresException c){}
      catch( AnimalException a){}

Выше уловы были каскадированы от более специфичных до более абстрактных, так что исключение попадает в это очень часто.

Если наследования нет, тогда улов может быть в любом порядке...

Ответ 7

Это лучшее, что вы можете сделать. Метод либо собирается вернуть какой-то индикатор успеха/ошибки, либо он собирается выбросить исключение, это просто вопрос, который наиболее удобен. Здесь Sun приняла решение для нас, поэтому нет необходимости в дебатах.

Что меня об этом беспокоит, так это то, что исключение будет включать полную трассировку стека! В вашем конкретном случае, если вы читаете миллионы этих строк, вы заметите (совершенно ненужную) плохую работу. Если это имеет для вас значение, вы можете подумать о том, чтобы написать собственный метод (вы можете использовать код Sun в качестве руководства.) Тогда вы можете сами решить, хотите ли вы использовать исключение или нет. Если вы это сделаете, сохраните статическую копию исключения и всегда бросайте ее, чтобы сохранить время распределения. И переопределите fillInStackTrace, чтобы он ничего не делал и у вас не было бессмысленной трассировки стека в вашем исключении.