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


91

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

У C ++ я міг створити метод, який прийняв би покажчик на int і дозволив самому методу повернути true або false. Однак, наскільки мені відомо, це неможливо на Java. Я також міг би створити об'єкт, що містить змінну true / false та перетворене значення, але це теж не здається ідеальним. Те саме стосується глобальної цінності, і це може створити мені певні проблеми з багатопотоковістю.

То чи існує чистий спосіб це зробити?


Символи в рядку повинні все бути десятковими цифрами, за винятком того, що перший символ ... . Замість того, щоб обробляти винятки скрізь у коді, просто перевірте формат рядка, перш ніж викликати метод синтаксичного аналізу.
Lightman

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

Відповіді:


142

Ви можете повернути Integerзамість a int, що повертається nullпри відмові аналізу.

Шкода, що Java не надає способу зробити це, не маючи винятку, який буде викинутий всередину - ви можете приховати виняток (захопивши його та повернувши null), але це все одно може бути проблемою продуктивності, якщо ви аналізуєте сотні тисяч бітів даних, наданих користувачем.

EDIT: Код для такого методу:

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

Зауважте, що я не впевнений, що це буде робити, якщо textзначення нуль. Ви повинні врахувати, що - якщо він представляє помилку (тобто ваш код цілком може передавати недійсне значення, але ніколи не повинен передавати значення null), тоді додавання винятку є доцільним; якщо це не являє собою помилку, то вам, мабуть, слід просто повернути null, як для будь-якого іншого недійсного значення.

Спочатку в цій відповіді використовувався new Integer(String)конструктор; тепер він використовує Integer.parseIntі боксерську операцію; таким чином, невеликі значення в кінцевому підсумку потрапляють до кешованих Integerоб'єктів, що робить їх більш ефективними в таких ситуаціях.


1
Як це допомагає? Для виклику сайту потрібно: <b> temp = tryParse (...); if (temp! = Null) {target = temp; } else {виконати дію відновлення}; </b> з можливим винятком кидка в частині відновлення. В оригінальній формулюванні сайт виклику вимагає <b> try target = (...). ParseInt; catch (...) {виконати дію відновлення} </b> з тривіальним виключенням брошення у відновлення, яке реалізується простим видаленням фрази catch. Як пропоноване рішення спрощує це розуміння (воно має магічний трюк) або як-небудь зменшує кількість коду?
Ira Baxter,

15
Як правило, чистіше кодувати для перевірки nullпосилань, ніж регулярно обробляти винятки.
Адам Марас

Ще зрозуміліше уникати передачі нулів як значень, але замість цього якимось чином вказують на те, що сталася помилка en; винятки не слід використовувати для контролю потоку.
Еско

2
@ Стів Куо: Чому? Де вигода? Вони обидва кожного разу створюють нове ціле число? У будь-якому випадку, я маю спокусу використовувати Integer.parseInt і дозволити автобоксу подбати про це, щоб скористатися кешем для невеликих значень.
Джон Скіт,

1
@Vlasec І не просто необов’язкові, а спеціалізовані версії для примітивів, таких як 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 у своєму проекті з інших причин (наприклад, StringUtils), що стає зручним.
Ratata Tata

16

Щоб уникнути обробки винятків, використовуйте регулярний вираз, щоб переконатися, що спочатку у вас є всі цифри:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}

Спасибі за вашу відповідь. Я прочитав більшість відповідей на цій сторінці, я особисто писав рішення "спробуй / злови". однак ось моє питання, хоч і невелике, з цим рішенням. більшість IDE задихаються аналізуючи потік вашого коду, коли у вас є try / catch усередині циклу. ось чому мені потрібно було рішення без try / catch.
віктор н.

4
Будь обережний. Звичайний вираз із збігом цілого числа, що починається з 0, яке потім викличе NumberFormatException. Спробуйте це ^ (?: [1-9] \ d * | 0) $ від stackoverflow.com/questions/12018479/…
Goose

5
Цей конкретний регулярний вираз не обробляє від’ємні числа.
Бред Купіт

7
також це не охоплює діапазони чисел, що виходять за межі цілих чисел
Мохаммад Яхія

10

Є Ints.tryParse()в Гуаві . Він не створює виняток для нечислового рядка, однак викидає виняток для нульового рядка.


4

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

Ви можете повернути 'null', як запропонував Джон, але це більш-менш замінює конструкцію try / catch на null-check. Існує лише невелика різниця в поведінці, якщо ви "забудете" обробляти помилки: якщо ви не вловите виняток, призначення немає, а ліва змінна зберігає його старе значення. Якщо ви не зробите тестування на нуль, можливо, вас вразить JVM (NPE).

пропозиція позіхання виглядає для мене більш елегантною, тому що я не люблю повертати значення null, щоб сигналізувати про деякі помилки чи виняткові стани. Тепер вам потрібно перевірити посилальну рівність заздалегідь визначеним об'єктом, що вказує на проблему. Але, як заперечують інші, якщо ви знову "забудете" перевірити, а рядок не піддається аналізу, програма продовжує роботу із загорнутим int всередині вашого об'єкта "ERROR" або "NULL".

Рішення Миколая ще більше об'єктно-орієнтоване і також буде працювати з методами parseXXX з інших класів обгортки. Але врешті-решт, він просто замінив NumberFormatException на виняток OperationNotSupported - знову вам знадобиться try / catch для обробки недійсних входів.

Отже, мій висновок - не інкапсулювати простий метод 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;
}

}

Мені подобається ваше рішення, використовуючи шаблон pattern. Very haskelly;)
rodrigoelp

1
Це рішення зараз застаріле, оскільки існує java.util.Обов’язково, оскільки Java 8 :)
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

Відповідь, яку дав Джон Скіт, чудова, але я не люблю повертати об’єкт nullInteger. Я вважаю це заплутаним у використанні. З 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 та логічної форми, яка не покладається на пошук винятків. На відміну від 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.


ОП хоче результат перетворення (як посилання) плюс вказівку на те, що перетворення було успішним (чи ні).
позіхання

1
@yawn: І нульове посилання дає саме це вказівку.
Джон Скіт,

@ Джон Скіт: правильно, але я по-іншому прочитав його намір. Він написав щось на зразок використання проміжного об’єкта для розрізнення успіху / невдачі + значення. Виходячи з фону C ++, я зрозумів, що якщо він хоче використовувати null (замість об’єкта), він би взагалі не задавав питання.
позіхання

Існує велика різниця між "значенням" та "об'єктом". Нульове посилання - це чисте значення, але не об’єкт.
Джон Скіт,

1. У Integer.tryParseстандартному Integerкласі Java немає . 2. Робити new Integerнепотрібно (і рекомендується проти), оскільки Java робить бокс і розпаковує автоматично. Ваша Java не просто трохи іржава, вона дуже іржава.
ADTC

1

А як щодо розгалуження методу parseInt ?

Це просто, просто скопіюйте та вставте вміст до нової утиліти, яка повертає Integerабо Optional<Integer>замінює кидки на return. Здається, у базовому коді немає винятків, але краще перевірити .

Пропустивши всю інформацію про обробку винятків, ви можете заощадити час на недійсних введеннях. І метод існує з JDK 1.0, тому навряд чи вам доведеться багато робити, щоб підтримувати його в актуальному стані.


0

Я б запропонував вам розглянути такий метод

 IntegerUtilities.isValidInteger(String s)

який ви потім реалізуєте, як вважаєте за потрібне. Якщо ви хочете, щоб результат повертався - можливо, тому, що ви все одно використовуєте Integer.parseInt () - ви можете скористатися фокусом масиву.

 IntegerUtilities.isValidInteger(String s, int[] 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 (те саме, звичайно, для негативної сторони).
Сірлз

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 () повертає ціле число в діапазоні символу або -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для виконання цієї роботи та своє рішення

  • не використовує потенційно повільний спроб ловлі (на відміну від 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

Таким чином, ви завжди можете перевірити помилку перетворення, але все одно працювати з результатами як цілі екземпляри. Ви також можете налаштувати число, яке NULL представляє (≠ 0).


Що робити, якщо "ціле число" є рядковим літералом "0"? Ви ніколи не дізнаєтесь, чи було недійсне введення.
Барт Кірс,

Я думаю, це залежить від того, порівнює значення == оператор == для двох цілих чисел. Якщо він порівнює значення, проблема існує. Якщо він порівнює посилання, це буде працювати еквівалентно моїй відповіді.
Адам Марас

Чому голос проти? Моя відповідь правильна і надає перевагу (над null), що ви завжди маєте справу з дійсним екземпляром Integer (замість null), позбавляючи вас від необхідності мати справу з NPE.
позіхання

Однак відмінність null від дійсного цілого є корисним . Вам слід перевірити результат на наявність недійсності, щоб дізнатись, вдався аналіз чи ні. Приховуючи, що позаду та іншим придатним для використання об’єктом, є рецепт проблем, IMO.
Джон Скіт,

Більше проти - цікаво! Оскільки / я новачок у 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.