Boa maneira de encapsular Integer.parseInt ()

88

Tenho um projeto no qual costumamos usar Integer.parseInt()para converter uma String em um int. Quando algo dá errado (por exemplo, o Stringnão é um número, mas a letra aou o que quer que seja), esse método lançará uma exceção. No entanto, se eu tiver que lidar com exceções em meu código em todos os lugares, isso começa a ficar muito feio muito rapidamente. Gostaria de colocar isso em um método, no entanto, não tenho ideia de como retornar um valor limpo para mostrar que a conversão deu errado.

Em C ++, eu poderia ter criado um método que aceitasse um ponteiro para um int e deixasse o próprio método retornar verdadeiro ou falso. No entanto, até onde eu sei, isso não é possível em Java. Eu também poderia criar um objeto que contenha uma variável verdadeiro / falso e o valor convertido, mas isso também não parece ideal. A mesma coisa vale para um valor global, e isso pode me dar alguns problemas com multithreading.

Então, há uma maneira limpa de fazer isso?

Cavalo Mau
fonte
Os caracteres na seqüência devem ser todos dígitos decimais, exceto que o primeiro caractere ... . Em vez de manipular exceções em todo o código, verifique o formato da string antes de chamar o método de análise.
Lightman de
É quase impossível escrever uma regex que capture todos os inteiros válidos com sinal de 32 bits e nenhum inválido. 2147483647 é legal, intenquanto 2147483648 não é.
Seva Alekseyev

Respostas:

140

Você poderia retornar um em Integervez de um int, retornando nullna falha de análise.

É uma pena que o Java não forneça uma maneira de fazer isso sem que haja uma exceção lançada internamente - você pode ocultar a exceção (capturando-a e retornando nulo), mas ainda pode ser um problema de desempenho se você estiver analisando centenas de milhares de bits de dados fornecidos pelo usuário.

EDIT: Código para tal método:

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

Observe que não tenho certeza de início do que isso fará se textfor nulo. Você deve considerar que - se representar um bug (ou seja, seu código pode muito bem passar um valor inválido, mas nunca deve passar nulo), então lançar uma exceção é apropriado; se não representar um bug, você provavelmente deve retornar nulo como faria para qualquer outro valor inválido.

Originalmente, essa resposta usava o new Integer(String)construtor; agora usa Integer.parseIntuma operação de boxe; desta forma, pequenos valores acabarão sendo encaixotados em Integerobjetos em cache , tornando-o mais eficiente nessas situações.

Jon Skeet
fonte
1
Como isso ajuda? O site da chamada exigirá: <b> temp = tryParse (...); if (temp! = Null) {target = temp; } else {do ​​recovery action}; </b> com uma provável exceção de lançamento na parte de recuperação. Na formulação original, o site de chamada requer <b> try target = (...). ParseInt; catch (...) {do recovery action} </b> com uma exceção de lançamento trivial na recuperação sendo implementada simplesmente removendo a cláusula catch. Como a solução proposta torna isso mais simples de entender (tem um truque de mágica) ou reduz a quantidade de código de alguma forma?
Ira Baxter
14
Geralmente, é mais limpo codificar para verificar as nullreferências do que lidar com exceções regularmente.
Adam Maras
É ainda mais limpo para evitar a passagem de nulos como valores, mas em vez disso, indica que ocorreu um erro; as exceções não devem ser usadas para controle de fluxo.
Esko
2
@Steve Kuo: Por quê? Onde está o benefício? Ambos criam um novo número inteiro a cada vez? No mínimo, estou tentado a usar Integer.parseInt e deixar o autoboxing cuidar disso, para aproveitar o cache para pequenos valores.
Jon Skeet
1
@Vlasec E não apenas opcional, mas versões especializadas para primitivas, como OptionalInt.
Joshua Taylor
36

Que comportamento você espera quando não é um número?

Se, por exemplo, você costuma ter um valor padrão para usar quando a entrada não é um número, um método como este pode ser útil:

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

Métodos semelhantes podem ser escritos para diferentes comportamentos padrão quando a entrada não pode ser analisada.

Joachim Sauer
fonte
29

Em alguns casos, você deve lidar com erros de análise como situações de falha rápida, mas em outros casos, como configuração de aplicativo, prefiro lidar com a entrada ausente com valores padrão usando Apache Commons Lang 3 NumberUtils .

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
Bryan W. Wagner
fonte
Na maioria das vezes, você já está usando o apache commons em seu projeto por outros motivos (como StringUtils), que se torna útil.
Ratata Tata
17

Para evitar o tratamento de exceções, use uma expressão regular para garantir que você tenha todos os dígitos primeiro:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}
Papai
fonte
Obrigado pela sua resposta. Li a maioria das respostas nesta página, pessoalmente escrevi a solução try / catch. no entanto, aqui está o meu problema, embora pequeno, com essa solução. a maioria dos IDEs vai engasgar com a análise do fluxo do seu código quando você tem um try / catch dentro de um loop. é por isso que eu precisava de uma solução sem try / catch.
victor n.
4
Seja cuidadoso. A regex com corresponde a um inteiro começando com 0, que então lançará uma NumberFormatException. Experimente ^ (?: [1-9] \ d * | 0) $ de stackoverflow.com/questions/12018479/…
Goose
4
Este regex particular não lidaria com números negativos.
Brad Cupit
6
também não cobre intervalos de números fora dos limites inteiros
Mohammad Yahia,
10

Existe Ints.tryParse()na Goiaba . Ele não lança exceção em uma string não numérica, no entanto, ele lança uma exceção em uma string nula.

Husayt
fonte
4

Depois de ler as respostas à pergunta, acho que encapsular ou envolver o método parseInt não é necessário, talvez até não seja uma boa ideia.

Você poderia retornar 'nulo' como Jon sugeriu, mas isso é mais ou menos substituindo uma construção try / catch por uma verificação de nulo. Há apenas uma pequena diferença no comportamento se você 'esquecer' o tratamento de erros: se você não capturar a exceção, não há atribuição e a variável do lado esquerdo mantém o valor antigo. Se você não testar o valor nulo, provavelmente será atingido pelo JVM (NPE).

A sugestão do yawn me parece mais elegante, porque não gosto de retornar null para sinalizar alguns erros ou estados excepcionais. Agora você tem que verificar a igualdade referencial com um objeto predefinido, que indica um problema. Mas, como outros argumentam, se novamente você 'esquecer' de verificar e uma String não puder ser analisada, o programa continuará com o int dentro do seu objeto 'ERROR' ou 'NULL'.

A solução de Nikolay é ainda mais orientada a objetos e também funcionará com métodos parseXXX de outras classes de wrapper. Mas, no final, ele apenas substituiu NumberFormatException por uma exceção OperationNotSupported - mais uma vez, você precisa de um try / catch para lidar com entradas não analisáveis.

Portanto, minha conclusão é não encapsular o método parseInt simples. Eu apenas encapsularia se pudesse adicionar também algum tratamento de erros (dependente do aplicativo).

Andreas Dolk
fonte
4

Pode ser que você possa usar algo assim:

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

}
Nikolay Ivanov
fonte
Gosto da sua solução usando o padrão talvez. Muito haskelly;)
rodrigoelp
1
Esta solução está desatualizada, pois existe java.util.Optional desde Java 8 :)
Vlasec
2

Você também pode replicar o comportamento C ++ que deseja de forma muito simples

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

Você usaria o método assim:

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

Depois disso, a variável resulté verdadeira se tudo correr bem e byRef[0]contiver o valor analisado.

Pessoalmente, eu me limitaria a pegar a exceção.


fonte
2

A resposta dada por Jon Skeet é boa, mas eu não gosto de devolver um nullobjeto Integer. Acho isso confuso de usar. Desde Java 8 existe uma opção melhor (na minha opinião), usando o OptionalInt:

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

Isso torna explícito que você deve lidar com o caso em que nenhum valor está disponível. Eu preferiria que esse tipo de função fosse adicionado à biblioteca java no futuro, mas não sei se isso acontecerá.

Marc
fonte
2

Se estiver usando Java 8 ou superior, você pode usar uma biblioteca que acabei de lançar: https://github.com/robtimus/try-parse . Ele tem suporte para int, long e boolean que não depende da captura de exceções. Ao contrário do Ints.tryParse do Guava, ele retorna OptionalInt / OptionalLong / Optional, bem como em https://stackoverflow.com/a/38451745/1180351, mas mais eficiente.

Rob Spoor
fonte
1

Meu Java está um pouco enferrujado, mas deixe-me ver se posso indicar a direção certa:

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

}

Se o seu valor de retorno for null, você tem um valor ruim. Caso contrário, você tem um válido Integer.

Adam Maras
fonte
O OP deseja o resultado da conversão (como referência) mais uma indicação de que a conversão foi bem-sucedida (ou não).
bocejo
1
@yawn: E uma referência nula dá exatamente essa indicação.
Jon Skeet
@John Skeet: correto, mas eu li sua intenção de forma diferente. Ele escreveu algo como usar um objeto intermediário para diferenciar sucesso / falha + valor. Vindo de um background de C ++, percebi que se ele quisesse usar null (em vez de um objeto), ele não teria feito a pergunta em primeiro lugar.
bocejo
Há uma grande diferença entre "valor" e "objeto". Uma referência nula é um valor limpo, mas não um objeto.
Jon Skeet
1. Não há nenhum Integer.tryParsena Integerclasse Java padrão . 2. Fazer new Integeré desnecessário (e não recomendado), pois Java faz boxing e unboxing automaticamente. Seu Java não está apenas um pouco enferrujado, está muito enferrujado.
ADTC
1

E quanto ao método parseInt ?

É fácil, basta copiar e colar o conteúdo em um novo utilitário que retorna Integerou Optional<Integer>e substitui lança por retorna. Parece que não há exceções no código subjacente, mas é melhor verificar .

Ao pular todo o material de tratamento de exceções, você pode economizar algum tempo com entradas inválidas. E o método existe desde o JDK 1.0, portanto, não é provável que você precise fazer muito para mantê-lo atualizado.

Vlasec
fonte
0

Eu sugiro que você considere um método como

 IntegerUtilities.isValidInteger(String s)

que você então implementa conforme achar adequado. Se você quiser que o resultado volte - talvez porque você usa Integer.parseInt () de qualquer maneira - você pode usar o truque do array.

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

onde você define result [0] para o valor inteiro encontrado no processo.

Thorbjørn Ravn Andersen
fonte
0

Isso é um pouco semelhante à solução de Nikolay:

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

O método principal demonstra o código. Outra forma de implementar a interface do Parser seria obviamente apenas definir "\ D +" da construção e fazer com que os métodos não fizessem nada.

Carl
fonte
0

Você pode rolar o seu próprio, mas é tão fácil de usar o StringUtils.isNumeric() método de commons lang . Ele usa Character.isDigit () para iterar sobre cada caractere na String.

James Bassett
fonte
Então, não funcionaria se o dígito contiver um número muito grande. Integer.parseInt lança uma exceção para números maiores que Integer.MAX_VALUE (o mesmo, é claro, para o lado negativo).
Searles de
0

A maneira como lido com esse problema é recursivamente. Por exemplo, ao ler dados do console:

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
fonte
0

Para evitar uma exceção, você pode usar o Format.parseObjectmétodo Java . O código abaixo é basicamente uma versão simplificada da classe IntegerValidator do 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;
}

Você pode usar AtomicIntegerou o int[]truque da matriz, dependendo de sua preferência.

Aqui está o meu teste que o usa -

int[] i = new int[1];
Assert.assertTrue(IntUtils.tryParse("123", i));
Assert.assertEquals(123, i[0]);
Josh Unger
fonte
0

Eu também estava tendo o mesmo problema. Este é um método que escrevi para pedir uma entrada ao usuário e não aceitar a entrada a menos que seja um inteiro. Por favor, note que eu sou um iniciante, então se o código não estiver funcionando como esperado, culpe minha inexperiência!

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();
}
Abhinav Mathur
fonte
1
Não use System.out.println (é uma prática ruim). O problema de usá-lo é que seu programa irá esperar até que a impressão termine. A melhor abordagem é usar uma estrutura de registro.
Omar Hrynkiewicz
0

Esta é uma resposta à pergunta 8391979, "O java tem um int.tryparse que não lança uma exceção para dados inválidos? [Duplicado]", que está fechado e vinculado a esta pergunta.

Editar 2016 08 17: Métodos ltrimZeroes adicionados e chamados em tryParse (). Sem zeros à esquerda em numberString pode dar resultados falsos (veja os comentários no código). Agora existe também o método público estático String ltrimZeroes (String numberString) que funciona para "números" positivos e negativos (END Edit)

Abaixo você encontra uma classe Wrapper (boxing) rudimentar para int com um método tryParse () otimizado de alta velocidade (semelhante ao C #) que analisa a própria string e é um pouco mais rápido do que Integer.parseInt (String s) do 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;
    }
}

Teste / programa de exemplo para a classe 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());
    }
}
Peter Sulzer
fonte
0

Tente com expressão regular e argumento de parâmetros padrão

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

se você estiver usando apache.commons.lang3, use NumberUtils :

int testId = NumberUtils.toInt("test", 0);
System.out.print(testId); // 0
Krunal
fonte
0

Eu gostaria de apresentar outra proposta que funciona se alguém solicitar números inteiros especificamente: Basta usar long e Long.MIN_VALUE para casos de erro. Isso é semelhante à abordagem que é usada para chars em Reader, onde Reader.read () retorna um inteiro no intervalo de um char ou -1 se o leitor estiver vazio.

Para Float e Double, o NaN pode ser usado de maneira semelhante.

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
fonte
0

Considerando as respostas existentes, copiei e melhorei o código-fonte do Integer.parseIntpara fazer o trabalho, e minha solução

  • não usa try-catch potencialmente lento (ao contrário de Lang 3 NumberUtils ),
  • não usa regexps que não podem pegar números muito grandes,
  • evita o boxe (ao contrário do Goiaba Ints.tryParse() ),
  • não necessita de quaisquer alocações (ao contrário int[], Box,OptionalInt ),
  • aceita CharSequenceparte ou parte dele em vez de um todoString ,
  • pode usar qualquer raiz que Integer.parseInt possa, ou seja, [2,36],
  • não depende de nenhuma biblioteca.

A única desvantagem é que não há diferença entre toIntOfDefault("-1", -1)e 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
fonte
-1

Você pode usar um objeto nulo da seguinte forma:

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

    }

}

O resultado de main neste exemplo é:

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

Dessa forma, você sempre pode testar a falha na conversão, mas ainda assim trabalhar com os resultados como instâncias inteiras. Você também pode querer ajustar o número que NULL representa (≠ 0).

bocejar
fonte
E se 'String inteiro' for a string literal "0"? Você nunca saberá se houve uma entrada inválida.
Bart Kiers
Acho que depende se o operador == para dois inteiros compara valores ou referências. Se comparar valores, o problema existe. Se comparar referências, funcionará de forma equivalente à minha resposta.
Adam Maras
Por que o downvote? Minha resposta está correta e oferece a vantagem (sobre nulo) que você sempre lida com uma instância válida de Integer (em vez de nulo), o que o livra de ter que lidar com NPEs.
bocejo
Distinguir nulo de um inteiro real é útil . Você deve testar o resultado quanto à nulidade, para saber se a análise foi bem-sucedida ou não. Esconder isso atrás de um objeto utilizável é uma receita para problemas, IMO.
Jon Skeet
Mais votos negativos - interessante! Visto que sou novo no SO e todos, um dos eleitores poderia me explicar o porquê?
bocejo
-1

Você não deve usar exceções para validar seus valores .

Para um único caractere, há uma solução simples:

Character.isDigit()

Para valores mais longos, é melhor usar alguns utilitários. NumberUtils fornecidos pelo Apache funcionariam perfeitamente aqui:

NumberUtils.isNumber()

Verifique https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

Bogdan Aksonenko
fonte
«Verifica se a String é um número Java válido. Os números válidos incluem hexadecimal marcado com o qualificador 0x, notação científica e números marcados com um qualificador de tipo (por exemplo, 123L). » Não é isso que pode ser analisado Integer.parseInt.
Miha_x64