Хороший способ инкапсулировать 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;
}

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

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

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.