У меня есть проект, в котором мы часто используем Integer.parseInt()
для преобразования String в int. Когда что-то пойдет не так (например, String
это не число, а буква a
или что-то еще), этот метод вызовет исключение. Однако, если мне приходится обрабатывать исключения в моем коде повсюду, это очень быстро начинает выглядеть очень уродливо. Я хотел бы поместить это в метод, однако я понятия не имею, как вернуть чистое значение, чтобы показать, что преобразование пошло не так.
В C ++ я мог бы создать метод, принимающий указатель на int и позволяющий самому методу возвращать true или false. Однако, насколько мне известно, в Java это невозможно. Я также мог бы создать объект, содержащий переменную true / false и преобразованное значение, но это тоже не кажется идеальным. То же самое и с глобальным значением, и это может вызвать у меня проблемы с многопоточностью.
Так есть ли чистый способ сделать это?
источник
int
а 2147483648 - нет.Ответы:
Вы можете вернуть
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
объекты, что сделает его более эффективным в таких ситуациях.источник
null
ссылок чище, чем для регулярной обработки исключений.Какого поведения вы ожидаете, если это не число?
Если, например, у вас часто используется значение по умолчанию, когда ввод не является числом, тогда может быть полезен такой метод:
public static int parseWithDefault(String number, int defaultVal) { try { return Integer.parseInt(number); } catch (NumberFormatException e) { return defaultVal; } }
Подобные методы могут быть написаны для различного поведения по умолчанию, когда ввод не может быть проанализирован.
источник
В некоторых случаях вам следует обрабатывать ошибки синтаксического анализа как аварийные ситуации, но в других случаях, таких как конфигурация приложения, я предпочитаю обрабатывать отсутствующие входные данные со значениями по умолчанию, используя Apache Commons Lang 3 NumberUtils .
int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
источник
Чтобы избежать обработки исключений, используйте регулярное выражение, чтобы сначала указать все цифры:
//Checking for Regular expression that matches digits if(value.matches("\\d+")) { Integer.parseInt(value); }
источник
Есть
Ints.tryParse()
в Гуаве . Он не генерирует исключение для нечисловой строки, однако он генерирует исключение для нулевой строки.источник
После прочтения ответов на вопрос я думаю, что инкапсуляция или упаковка метода parseInt не нужна, возможно, даже не очень хорошая идея.
Вы можете вернуть null, как предлагал Джон, но это более или менее заменяет конструкцию try / catch проверкой на null. Есть лишь небольшая разница в поведении, если вы «забываете» обработку ошибок: если вы не поймаете исключение, присваивания не будет, и переменная с левой стороны сохраняет свое старое значение. Если вы не проверяете значение null, вы, вероятно, столкнетесь с JVM (NPE).
Предложение yawn кажется мне более элегантным, потому что я не люблю возвращать null, чтобы сигнализировать о некоторых ошибках или исключительных состояниях. Теперь вам нужно проверить ссылочное равенство с предопределенным объектом, что указывает на проблему. Но, как утверждают другие, если вы снова «забываете» проверить, а String не может быть проанализирован, программа продолжит работу с обернутым int внутри вашего объекта «ERROR» или «NULL».
Решение Николая еще более объектно-ориентировано и будет работать с методами parseXXX из других классов-оболочек. Но в конце концов он просто заменил NumberFormatException на исключение OperationNotSupported - опять же, вам нужно попробовать / уловить, чтобы обработать неразборчивые входные данные.
Итак, мой вывод - не инкапсулировать простой метод parseInt. Я бы только инкапсулировал, если бы я мог добавить некоторую (зависящую от приложения) обработку ошибок.
источник
Может быть, вы можете использовать что-то вроде этого:
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; } }
источник
Вы также можете очень просто воспроизвести желаемое поведение 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]
содержит проанализированное значение.Лично я бы остановился на перехвате исключения.
источник
Ответ, данный Джоном Скитом, прекрасен, но мне не нравится возвращать
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 в будущем, но я не знаю, произойдет ли это когда-нибудь.
источник
Если вы используете Java 8 или новее, вы можете использовать только что выпущенную мной библиотеку: https://github.com/robtimus/try-parse . Он поддерживает int, long и boolean, который не полагается на перехват исключений. В отличие от Ints.tryParse Guava, он возвращает OptionalInt / OptionalLong / Optional, как и в https://stackoverflow.com/a/38451745/1180351, но более эффективно.
источник
Моя 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
.источник
Integer.tryParse
в стандартномInteger
классе Java . 2. Вnew Integer
этом нет необходимости (и не рекомендуется), поскольку Java автоматически выполняет упаковку и распаковку. Ваша Java не просто немного ржавая, она очень ржавая.А как насчет разветвления метода parseInt ?
Это просто, просто скопируйте и вставьте содержимое в новую утилиту, которая возвращает
Integer
илиOptional<Integer>
заменяет выбросы возвратами. Кажется, что в базовом коде нет исключений, но лучше проверьте .Пропустив всю обработку исключений, вы можете сэкономить время на недопустимых входных данных. И этот метод существует с JDK 1.0, поэтому вряд ли вам придется много делать, чтобы поддерживать его в актуальном состоянии.
источник
Я предлагаю вам рассмотреть такой метод, как
которые вы затем реализуете по своему усмотрению. Если вы хотите вернуть результат - возможно, потому что вы все равно используете Integer.parseInt () - вы можете использовать трюк с массивом.
IntegerUtilities.isValidInteger(String s, int[] result)
где вы устанавливаете result [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 +" из конструкции, а методы ничего не делать.
источник
Вы можете использовать свой собственный, но его так же просто использовать
StringUtils.isNumeric()
метод commons lang . Он использует Character.isDigit () для перебора каждого символа в строке.источник
Я справляюсь с этой проблемой рекурсивно. Например при чтении данных из консоли:
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; }
источник
Чтобы избежать исключения, вы можете использовать
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]);
источник
У меня тоже была такая же проблема. Это метод, который я написал, чтобы попросить пользователя ввести ввод и не принимать ввод, если он не является целым числом. Обратите внимание, что я новичок, поэтому, если код работает не так, как ожидалось, вините мою неопытность!
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(); }
источник
Это ответ на вопрос 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()); } }
источник
Попробуйте использовать регулярное выражение и аргумент параметров по умолчанию
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
источник
Я хотел бы добавить еще одно предложение, которое работает, если кто-то конкретно запрашивает целые числа: просто используйте 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; }
источник
Учитывая существующие ответы, я скопировал и улучшил исходный код
Integer.parseInt
для выполнения этой работы, и мое решение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); }
источник
Возможно, кто-то ищет более общий подход, поскольку в 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);
источник
Вы можете использовать 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).
источник
Вы не должны использовать исключения для проверки своих значений .
Для одиночного символа есть простое решение:
Для более длинных значений лучше использовать утилиты. NumberUtils, предоставляемый Apache, здесь отлично подойдет:
Пожалуйста, проверьте https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html
источник
Integer.parseInt
.