Хороший способ инкапсулировать Integer.parseInt ()

93

У меня есть проект, в котором мы часто используем Integer.parseInt()для преобразования String в int. Когда что-то пойдет не так (например, Stringэто не число, а буква aили что-то еще), этот метод вызовет исключение. Однако, если мне приходится обрабатывать исключения в моем коде повсюду, это очень быстро начинает выглядеть очень уродливо. Я хотел бы поместить это в метод, однако я понятия не имею, как вернуть чистое значение, чтобы показать, что преобразование пошло не так.

В C ++ я мог бы создать метод, принимающий указатель на int и позволяющий самому методу возвращать true или false. Однако, насколько мне известно, в Java это невозможно. Я также мог бы создать объект, содержащий переменную true / false и преобразованное значение, но это тоже не кажется идеальным. То же самое и с глобальным значением, и это может вызвать у меня проблемы с многопоточностью.

Так есть ли чистый способ сделать это?

Плохая лошадь
источник
Символы в строке должны все быть десятичными цифрами, за исключением того, что первый символ ... . Вместо того, чтобы обрабатывать исключения повсюду в коде, просто проверьте формат строки перед вызовом метода синтаксического анализа.
Лайтман
Практически невозможно написать регулярное выражение, которое будет захватывать все действительные 32-битные целые числа со знаком и ни одно из недопустимых. 2147483647 является законным, intа 2147483648 - нет.
Сева Алексеев

Ответы:

142

Вы можете вернуть Integerвместо int, возвращаясь nullпри ошибке синтаксического анализа.

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

РЕДАКТИРОВАТЬ: Код для такого метода:

public static Integer tryParse(String text) {
  try {
    return Integer.parseInt(text);
  } catch (NumberFormatException e) {
    return null;
  }
}

Обратите внимание, что я не совсем уверен, что это будет делать, если textравно null. Вы должны учитывать, что - если он представляет собой ошибку (т.е. ваш код вполне может передавать недопустимое значение, но никогда не должен передавать значение null), тогда уместно генерировать исключение; если он не представляет собой ошибку, вам, вероятно, следует просто вернуть null, как и для любого другого недопустимого значения.

Первоначально в этом ответе использовался new Integer(String)конструктор; теперь он использует Integer.parseIntи операцию бокса; таким образом небольшие значения будут помещены в кэшированные Integerобъекты, что сделает его более эффективным в таких ситуациях.

Джон Скит
источник
1
Как это помогает? Сайт вызова потребует: <b> temp = tryParse (...); если (temp! = Null) {target = temp; } else {выполнить действие восстановления}; </b> с вероятным исключением выброса в части восстановления. В исходной формулировке для сайта вызова требуется <b> try target = (...). ParseInt; catch (...) {выполнить действие восстановления} </b> с тривиальным исключением исключения при восстановлении, реализуемом простым удалением предложения catch. Как предлагаемое решение упрощает понимание (в нем есть фокус) или каким-либо образом сокращает объем кода?
Ира Бакстер,
15
Как правило, код для проверки nullссылок чище, чем для регулярной обработки исключений.
Адам Марас
Еще проще избежать передачи нулей в качестве значений, а вместо этого каким-то образом указать, что произошла ошибка en; исключения не должны использоваться для управления потоком.
Esko
2
@ Стив Куо: Почему? Где выгода? Они оба каждый раз создают новое целое число? Во всяком случае, у меня возникает соблазн использовать Integer.parseInt и позволить автобоксу позаботиться об этом, чтобы воспользоваться кешем для небольших значений.
Джон Скит,
1
@Vlasec И не только Optional, но и специализированные версии для примитивов, такие как OptionalInt.
Джошуа Тейлор
37

Какого поведения вы ожидаете, если это не число?

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

public static int parseWithDefault(String number, int defaultVal) {
  try {
    return Integer.parseInt(number);
  } catch (NumberFormatException e) {
    return defaultVal;
  }
}

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

Иоахим Зауэр
источник
29

В некоторых случаях вам следует обрабатывать ошибки синтаксического анализа как аварийные ситуации, но в других случаях, таких как конфигурация приложения, я предпочитаю обрабатывать отсутствующие входные данные со значениями по умолчанию, используя Apache Commons Lang 3 NumberUtils .

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
Брайан В. Вагнер
источник
В большинстве случаев вы уже используете apache commons в своем проекте по другим причинам (например, StringUtils), это становится удобно.
Ratata Tata
16

Чтобы избежать обработки исключений, используйте регулярное выражение, чтобы сначала указать все цифры:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}
Папа
источник
Спасибо за ваш ответ. Я прочитал большинство ответов на этой странице, я лично написал решение try / catch. однако вот моя проблема, хотя и небольшая, с этим решением. большинство IDE будут задыхаться от анализа потока вашего кода, когда у вас есть try / catch внутри цикла. вот почему решение без попытки / улова было тем, что мне нужно.
победитель Н.
4
Быть осторожен. Регулярное выражение с целым числом, начинающимся с 0, затем вызовет исключение NumberFormatException. Попробуйте это ^ (?: [1-9] \ d * | 0) $ из stackoverflow.com/questions/12018479/…
Гусь
5
Это конкретное регулярное выражение не обрабатывает отрицательные числа.
Брэд Купит, 06
7
также это не распространяется на диапазоны чисел, выходящие за рамки целых чисел
Мохаммад Яхия
10

Есть Ints.tryParse()в Гуаве . Он не генерирует исключение для нечисловой строки, однако он генерирует исключение для нулевой строки.

Хусайт
источник
4

После прочтения ответов на вопрос я думаю, что инкапсуляция или упаковка метода parseInt не нужна, возможно, даже не очень хорошая идея.

Вы можете вернуть null, как предлагал Джон, но это более или менее заменяет конструкцию try / catch проверкой на null. Есть лишь небольшая разница в поведении, если вы «забываете» обработку ошибок: если вы не поймаете исключение, присваивания не будет, и переменная с левой стороны сохраняет свое старое значение. Если вы не проверяете значение null, вы, вероятно, столкнетесь с JVM (NPE).

Предложение yawn кажется мне более элегантным, потому что я не люблю возвращать null, чтобы сигнализировать о некоторых ошибках или исключительных состояниях. Теперь вам нужно проверить ссылочное равенство с предопределенным объектом, что указывает на проблему. Но, как утверждают другие, если вы снова «забываете» проверить, а String не может быть проанализирован, программа продолжит работу с обернутым int внутри вашего объекта «ERROR» или «NULL».

Решение Николая еще более объектно-ориентировано и будет работать с методами parseXXX из других классов-оболочек. Но в конце концов он просто заменил NumberFormatException на исключение OperationNotSupported - опять же, вам нужно попробовать / уловить, чтобы обработать неразборчивые входные данные.

Итак, мой вывод - не инкапсулировать простой метод parseInt. Я бы только инкапсулировал, если бы я мог добавить некоторую (зависящую от приложения) обработку ошибок.

Андреас Долк
источник
4

Может быть, вы можете использовать что-то вроде этого:

public class Test {
public interface Option<T> {
    T get();

    T getOrElse(T def);

    boolean hasValue();
}

final static class Some<T> implements Option<T> {

    private final T value;

    public Some(T value) {
        this.value = value;
    }

    @Override
    public T get() {
        return value;
    }

    @Override
    public T getOrElse(T def) {
        return value;
    }

    @Override
    public boolean hasValue() {
        return true;
    }
}

final static class None<T> implements Option<T> {

    @Override
    public T get() {
        throw new UnsupportedOperationException();
    }

    @Override
    public T getOrElse(T def) {
        return def;
    }

    @Override
    public boolean hasValue() {
        return false;
    }

}

public static Option<Integer> parseInt(String s) {
    Option<Integer> result = new None<Integer>();
    try {
        Integer value = Integer.parseInt(s);
        result = new Some<Integer>(value);
    } catch (NumberFormatException e) {
    }
    return result;
}

}
Николай Иванов
источник
Мне нравится ваше решение с использованием шаблона «возможно». Very haskelly;)
rodrigoelp
1
Это решение уже устарело, поскольку с Java 8 есть java.util.Optional :)
Vlasec
2

Вы также можете очень просто воспроизвести желаемое поведение C ++.

public static boolean parseInt(String str, int[] byRef) {
    if(byRef==null) return false;
    try {
       byRef[0] = Integer.parseInt(prop);
       return true;
    } catch (NumberFormatException ex) {
       return false;
    }
}

Вы могли бы использовать такой метод:

int[] byRef = new int[1];
boolean result = parseInt("123",byRef);

После этого переменная resultверна, если все прошло хорошо, и byRef[0]содержит проанализированное значение.

Лично я бы остановился на перехвате исключения.


источник
2

Ответ, данный Джоном Скитом, прекрасен, но мне не нравится возвращать nullобъект Integer. Я считаю, что это сбивает с толку. Начиная с Java 8, есть лучший вариант (на мой взгляд), используя OptionalInt:

public static OptionalInt tryParse(String value) {
 try {
     return OptionalInt.of(Integer.parseInt(value));
  } catch (NumberFormatException e) {
     return OptionalInt.empty();
  }
}

Это делает очевидным, что вы должны обрабатывать случай, когда значение недоступно. Я бы предпочел, чтобы такая функция была добавлена ​​в библиотеку java в будущем, но я не знаю, произойдет ли это когда-нибудь.

Марк
источник
2

Если вы используете Java 8 или новее, вы можете использовать только что выпущенную мной библиотеку: https://github.com/robtimus/try-parse . Он поддерживает int, long и boolean, который не полагается на перехват исключений. В отличие от Ints.tryParse Guava, он возвращает OptionalInt / OptionalLong / Optional, как и в https://stackoverflow.com/a/38451745/1180351, но более эффективно.

Роб Спур
источник
1

Моя Java немного заржавела, но позвольте мне посмотреть, смогу ли я указать вам в правильном направлении:

public class Converter {

    public static Integer parseInt(String str) {
        Integer n = null;

        try {
            n = new Integer(Integer.tryParse(str));
        } catch (NumberFormatException ex) {
            // leave n null, the string is invalid
        }

        return n;
    }

}

Если ваше возвращаемое значение равно null, у вас неверное значение. В противном случае у вас есть действующий Integer.

Адам Марас
источник
OP хочет получить результат преобразования (как ссылку) плюс указание на то, что преобразование было успешным (или нет).
зевнул
1
@yawn: И пустая ссылка дает именно это указание.
Джон Скит,
@ Джон Скит: верно, но я по-другому понимаю его намерения. Он написал что-то вроде использования промежуточного объекта, чтобы различать успех / неудачу + ценность. Исходя из опыта работы с C ++, я решил, что если бы он хотел использовать null (вместо объекта), он бы вообще не задавал этот вопрос.
зевнуть
Между «ценностью» и «объектом» есть большая разница. Пустая ссылка - это чистое значение, но не объект.
Джон Скит,
1. Нет Integer.tryParseв стандартном Integerклассе Java . 2. В new Integerэтом нет необходимости (и не рекомендуется), поскольку Java автоматически выполняет упаковку и распаковку. Ваша Java не просто немного ржавая, она очень ржавая.
ADTC
1

А как насчет разветвления метода parseInt ?

Это просто, просто скопируйте и вставьте содержимое в новую утилиту, которая возвращает Integerили Optional<Integer>заменяет выбросы возвратами. Кажется, что в базовом коде нет исключений, но лучше проверьте .

Пропустив всю обработку исключений, вы можете сэкономить время на недопустимых входных данных. И этот метод существует с JDK 1.0, поэтому вряд ли вам придется много делать, чтобы поддерживать его в актуальном состоянии.

Власец
источник
0

Я предлагаю вам рассмотреть такой метод, как

 IntegerUtilities.isValidInteger(String s)

которые вы затем реализуете по своему усмотрению. Если вы хотите вернуть результат - возможно, потому что вы все равно используете Integer.parseInt () - вы можете использовать трюк с массивом.

 IntegerUtilities.isValidInteger(String s, int[] result)

где вы устанавливаете result [0] в целое число, найденное в процессе.

Торбьёрн Равн Андерсен
источник
0

Это несколько похоже на решение Николая:

 private static class Box<T> {
  T me;
  public Box() {}
  public T get() { return me; }
  public void set(T fromParse) { me = fromParse; }
 }

 private interface Parser<T> {
  public void setExclusion(String regex);
  public boolean isExcluded(String s);
  public T parse(String s);
 }

 public static <T> boolean parser(Box<T> ref, Parser<T> p, String toParse) {
  if (!p.isExcluded(toParse)) {
   ref.set(p.parse(toParse));
   return true;
  } else return false;
 }

 public static void main(String args[]) {
  Box<Integer> a = new Box<Integer>();
  Parser<Integer> intParser = new Parser<Integer>() {
   String myExclusion;
   public void setExclusion(String regex) {
    myExclusion = regex;
   }
   public boolean isExcluded(String s) {
    return s.matches(myExclusion);
   }
   public Integer parse(String s) {
    return new Integer(s);
   }
  };
  intParser.setExclusion("\\D+");
  if (parser(a,intParser,"123")) System.out.println(a.get());
  if (!parser(a,intParser,"abc")) System.out.println("didn't parse "+a.get());
 }

Основной метод демонстрирует код. Другой способ реализовать интерфейс Parser, очевидно, состоял бы в том, чтобы просто установить "\ D +" из конструкции, а методы ничего не делать.

Карл
источник
0

Вы можете использовать свой собственный, но его так же просто использовать StringUtils.isNumeric() метод commons lang . Он использует Character.isDigit () для перебора каждого символа в строке.

Джеймс Бассетт
источник
Тогда это не сработает, если цифра содержит слишком большое число. Integer.parseInt генерирует исключение для чисел, больших, чем Integer.MAX_VALUE (то же самое, конечно, для отрицательной стороны).
Searles
0

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

Java.util.Scanner keyboard = new Java.util.Scanner(System.in);

public int GetMyInt(){
    int ret;
    System.out.print("Give me an Int: ");
    try{
        ret = Integer.parseInt(keyboard.NextLine());

    }
    catch(Exception e){
        System.out.println("\nThere was an error try again.\n");
        ret = GetMyInt();
    }
    return ret;
}
Boboman
источник
0

Чтобы избежать исключения, вы можете использовать Format.parseObjectметод Java . Приведенный ниже код в основном представляет собой упрощенную версию класса IntegerValidator Apache Common .

public static boolean tryParse(String s, int[] result)
{
    NumberFormat format = NumberFormat.getIntegerInstance();
    ParsePosition position = new ParsePosition(0);
    Object parsedValue = format.parseObject(s, position);

    if (position.getErrorIndex() > -1)
    {
        return false;
    }

    if (position.getIndex() < s.length())
    {
        return false;
    }

    result[0] = ((Long) parsedValue).intValue();
    return true;
}

Вы можете использовать AtomicIntegerили int[]трюк с массивом в зависимости от ваших предпочтений.

Вот мой тест, который его использует -

int[] i = new int[1];
Assert.assertTrue(IntUtils.tryParse("123", i));
Assert.assertEquals(123, i[0]);
Джош Унгер
источник
0

У меня тоже была такая же проблема. Это метод, который я написал, чтобы попросить пользователя ввести ввод и не принимать ввод, если он не является целым числом. Обратите внимание, что я новичок, поэтому, если код работает не так, как ожидалось, вините мою неопытность!

private int numberValue(String value, boolean val) throws IOException {
    //prints the value passed by the code implementer
    System.out.println(value);
    //returns 0 is val is passed as false
    Object num = 0;
    while (val) {
        num = br.readLine();
        try {
            Integer numVal = Integer.parseInt((String) num);
            if (numVal instanceof Integer) {
                val = false;
                num = numVal;
            }
        } catch (Exception e) {
            System.out.println("Error. Please input a valid number :-");
        }
    }
    return ((Integer) num).intValue();
}
Абхинав Матур
источник
1
Не используйте System.out.println (это плохая практика). Проблема с его использованием в том, что ваша программа будет ждать, пока println не завершится. Лучше всего использовать структуру ведения журнала.
Омар Грынкевич
0

Это ответ на вопрос 8391979 «Есть ли в java int.tryparse, который не генерирует исключение для неверных данных? [Дубликат]», который закрыт и связан с этим вопросом.

Изменить 2016 08 17: добавлены методы ltrimZeroes и вызваны их в tryParse (). Без ведущих нулей в numberString могут быть ложные результаты (см. Комментарии в коде). Теперь существует также общедоступный статический метод String ltrimZeroes (String numberString), который работает для положительных и отрицательных «чисел» (END Edit).

Ниже вы найдете рудиментарный класс Wrapper (бокс) для int с высокоскоростным оптимизированным методом tryParse () (аналогично C #), который анализирует саму строку и работает немного быстрее, чем Integer.parseInt (String s) из Java:

public class IntBoxSimple {
    // IntBoxSimple - Rudimentary class to implement a C#-like tryParse() method for int
    // A full blown IntBox class implementation can be found in my Github project
    // Copyright (c) 2016, Peter Sulzer, Fürth
    // Program is published under the GNU General Public License (GPL) Version 1 or newer

    protected int _n; // this "boxes" the int value

    // BEGIN The following statements are only executed at the
    // first instantiation of an IntBox (i. e. only once) or
    // already compiled into the code at compile time:
    public static final int MAX_INT_LEN =
            String.valueOf(Integer.MAX_VALUE).length();
    public static final int MIN_INT_LEN =
            String.valueOf(Integer.MIN_VALUE).length();
    public static final int MAX_INT_LASTDEC =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(1));
    public static final int MAX_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(0, 1));
    public static final int MIN_INT_LASTDEC =
            -Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(2));
    public static final int MIN_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(1,2));
    // END The following statements...

    // ltrimZeroes() methods added 2016 08 16 (are required by tryParse() methods)
    public static String ltrimZeroes(String s) {
        if (s.charAt(0) == '-')
            return ltrimZeroesNegative(s);
        else
            return ltrimZeroesPositive(s);
    }
    protected static String ltrimZeroesNegative(String s) {
        int i=1;
        for ( ; s.charAt(i) == '0'; i++);
        return ("-"+s.substring(i));
    }
    protected static String ltrimZeroesPositive(String s) {
        int i=0;
        for ( ; s.charAt(i) == '0'; i++);
        return (s.substring(i));
    }

    public static boolean tryParse(String s,IntBoxSimple intBox) {
        if (intBox == null)
            // intBoxSimple=new IntBoxSimple(); // This doesn't work, as
            // intBoxSimple itself is passed by value and cannot changed
            // for the caller. I. e. "out"-arguments of C# cannot be simulated in Java.
            return false; // so we simply return false
        s=s.trim(); // leading and trailing whitespace is allowed for String s
        int len=s.length();
        int rslt=0, d, dfirst=0, i, j;
        char c=s.charAt(0);
        if (c == '-') {
            if (len > MIN_INT_LEN) { // corrected (added) 2016 08 17
                s = ltrimZeroesNegative(s);
                len = s.length();
            }
            if (len >= MIN_INT_LEN) {
                c = s.charAt(1);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MIN_INT_LEN || dfirst > MIN_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 2; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            }
            if (len < MIN_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            } else {
                if (dfirst >= MIN_INT_FIRSTDIGIT && rslt < MIN_INT_LASTDEC)
                    return false;
                rslt -= dfirst * j;
            }
        } else {
            if (len > MAX_INT_LEN) { // corrected (added) 2016 08 16
                s = ltrimZeroesPositive(s);
                len=s.length();
            }
            if (len >= MAX_INT_LEN) {
                c = s.charAt(0);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MAX_INT_LEN || dfirst > MAX_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 1; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (len < MAX_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (dfirst >= MAX_INT_FIRSTDIGIT && rslt > MAX_INT_LASTDEC)
                return false;
            rslt += dfirst*j;
        }
        intBox._n=rslt;
        return true;
    }

    // Get the value stored in an IntBoxSimple:
    public int get_n() {
        return _n;
    }
    public int v() { // alternative shorter version, v for "value"
        return _n;
    }
    // Make objects of IntBoxSimple (needed as constructors are not public):
    public static IntBoxSimple makeIntBoxSimple() {
        return new IntBoxSimple();
    }
    public static IntBoxSimple makeIntBoxSimple(int integerNumber) {
        return new IntBoxSimple(integerNumber);
    }

    // constructors are not public(!=:
    protected IntBoxSimple() {} {
        _n=0; // default value an IntBoxSimple holds
    }
    protected IntBoxSimple(int integerNumber) {
        _n=integerNumber;
    }
}

Тестовая / примерная программа для класса IntBoxSimple:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IntBoxSimpleTest {
    public static void main (String args[]) {
        IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple();
        String in = null;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        do {
            System.out.printf(
                    "Enter an integer number in the range %d to %d:%n",
                        Integer.MIN_VALUE, Integer.MAX_VALUE);
            try { in = br.readLine(); } catch (IOException ex) {}
        } while(! IntBoxSimple.tryParse(in, ibs));
        System.out.printf("The number you have entered was: %d%n", ibs.v());
    }
}
Питер Зульцер
источник
0

Попробуйте использовать регулярное выражение и аргумент параметров по умолчанию

public static int parseIntWithDefault(String str, int defaultInt) {
    return str.matches("-?\\d+") ? Integer.parseInt(str) : defaultInt;
}


int testId = parseIntWithDefault("1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("test1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("-1001", 0);
System.out.print(testId); // -1001

int testId = parseIntWithDefault("test", 0);
System.out.print(testId); // 0

если вы используете apache.commons.lang3, то с помощью NumberUtils :

int testId = NumberUtils.toInt("test", 0);
System.out.print(testId); // 0
Крунал
источник
0

Я хотел бы добавить еще одно предложение, которое работает, если кто-то конкретно запрашивает целые числа: просто используйте long и используйте Long.MIN_VALUE для случаев ошибок. Это похоже на подход, который используется для символов в Reader, где Reader.read () возвращает целое число в диапазоне от char или -1, если средство чтения пусто.

Для Float и Double аналогичным образом можно использовать NaN.

public static long parseInteger(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        return Long.MIN_VALUE;
    }
}


// ...
long l = parseInteger("ABC");
if (l == Long.MIN_VALUE) {
    // ... error
} else {
    int i = (int) l;
}
Searles
источник
0

Учитывая существующие ответы, я скопировал и улучшил исходный код Integer.parseIntдля выполнения этой работы, и мое решение

  • не использует потенциально медленный try-catch (в отличие от Lang 3 NumberUtils ),
  • не использует регулярные выражения, которые не могут поймать слишком большие числа,
  • избегает бокса (в отличие от Гуавы Ints.tryParse()),
  • не требует каких - либо ассигнований ( в отличие от int[], Box, OptionalInt),
  • принимает его CharSequenceили его часть вместо целого String,
  • может использовать любую систему счисления Integer.parseInt, например [2,36],
  • не зависит ни от каких библиотек.

Единственный недостаток в том, что нет разницы между toIntOfDefault("-1", -1)и toIntOrDefault("oops", -1).

public static int toIntOrDefault(CharSequence s, int def) {
    return toIntOrDefault0(s, 0, s.length(), 10, def);
}
public static int toIntOrDefault(CharSequence s, int def, int radix) {
    radixCheck(radix);
    return toIntOrDefault0(s, 0, s.length(), radix, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int def) {
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, 10, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int radix, int def) {
    radixCheck(radix);
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, radix, def);
}
private static int toIntOrDefault0(CharSequence s, int start, int endExclusive, int radix, int def) {
    if (start == endExclusive) return def; // empty

    boolean negative = false;
    int limit = -Integer.MAX_VALUE;

    char firstChar = s.charAt(start);
    if (firstChar < '0') { // Possible leading "+" or "-"
        if (firstChar == '-') {
            negative = true;
            limit = Integer.MIN_VALUE;
        } else if (firstChar != '+') {
            return def;
        }

        start++;
        // Cannot have lone "+" or "-"
        if (start == endExclusive) return def;
    }
    int multmin = limit / radix;
    int result = 0;
    while (start < endExclusive) {
        // Accumulating negatively avoids surprises near MAX_VALUE
        int digit = Character.digit(s.charAt(start++), radix);
        if (digit < 0 || result < multmin) return def;
        result *= radix;
        if (result < limit + digit) return def;
        result -= digit;
    }
    return negative ? result : -result;
}
private static void radixCheck(int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        throw new NumberFormatException(
                "radix=" + radix + " ∉ [" +  Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
}
private static void boundsCheck(int start, int endExclusive, int len) {
    if (start < 0 || start > len || start > endExclusive)
        throw new IndexOutOfBoundsException("start=" + start + " ∉ [0, min(" + len + ", " + endExclusive + ")]");
    if (endExclusive > len)
        throw new IndexOutOfBoundsException("endExclusive=" + endExclusive + " > s.length=" + len);
}
Miha_x64
источник
0

Возможно, кто-то ищет более общий подход, поскольку в Java 8 есть пакет, java.util.functionкоторый позволяет определять функции поставщика. У вас может быть функция, которая принимает поставщика и значение по умолчанию, как показано ниже:

public static <T> T tryGetOrDefault(Supplier<T> supplier, T defaultValue) {
    try {
        return supplier.get();
    } catch (Exception e) {
        return defaultValue;
    }
}

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

Integer i = tryGetOrDefault(() -> Integer.parseInt(stringValue), 0);
Long l = tryGetOrDefault(() -> Long.parseLong(stringValue), 0l);
Double d = tryGetOrDefault(() -> Double.parseDouble(stringValue), 0d);
А. Маркоци
источник
-1

Вы можете использовать Null-Object так:

public class Convert {

    @SuppressWarnings({"UnnecessaryBoxing"})
    public static final Integer NULL = new Integer(0);

    public static Integer convert(String integer) {

        try {
            return Integer.valueOf(integer);
        } catch (NumberFormatException e) {
            return NULL;
        }

    }

    public static void main(String[] args) {

        Integer a = convert("123");
        System.out.println("a.equals(123) = " + a.equals(123));
        System.out.println("a == NULL " + (a == NULL));

        Integer b = convert("onetwothree");
        System.out.println("b.equals(123) = " + b.equals(123));
        System.out.println("b == NULL " + (b == NULL));

        Integer c = convert("0");
        System.out.println("equals(0) = " + c.equals(0));
        System.out.println("c == NULL " + (c == NULL));

    }

}

Результат main в этом примере:

a.equals(123) = true
a == NULL false
b.equals(123) = false
b == NULL true
c.equals(0) = true
c == NULL false

Таким образом, вы всегда можете протестировать неудачное преобразование, но по-прежнему работать с результатами как с экземплярами Integer. Вы также можете настроить число, представляющее NULL (≠ 0).

зевать
источник
Что, если 'String integer' - это строковый литерал "0"? Вы никогда не узнаете, был ли ввод недопустимым.
Барт Кирс,
Я предполагаю, что это зависит от того, сравнивает ли оператор == для двух целых чисел значения или ссылки. Если он сравнивает значения, проблема существует. Если он сравнит ссылки, он будет работать аналогично моему ответу.
Адам Марас
Почему голос против? Мой ответ правильный и дает преимущество (по сравнению с null) в том, что вы всегда имеете дело с действительным экземпляром Integer (вместо null), избавляя вас от необходимости иметь дело с NPE.
зевнуть
Тем не менее, отличать null от действительного целого числа полезно . Вы должны проверить результат на недействительность, чтобы узнать, успешно ли разобрался. Скрытие этого за и в противном случае пригодного для использования объекта - это рецепт проблем, ИМО.
Джон Скит,
Больше голосов против - интересно! Так как / я новичок в SO, и может ли один из голосующих объяснить мне, почему?
зевнуть
-1

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

Для одиночного символа есть простое решение:

Character.isDigit()

Для более длинных значений лучше использовать утилиты. NumberUtils, предоставляемый Apache, здесь отлично подойдет:

NumberUtils.isNumber()

Пожалуйста, проверьте https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

Богдан Аксоненко
источник
«Проверяет, является ли строка допустимым номером Java. Допустимые числа включают шестнадцатеричные числа, отмеченные квалификатором 0x, научное представление и числа, отмеченные квалификатором типа (например, 123L) ». Это не то, с чем можно разбираться Integer.parseInt.
Miha_x64