Integer.parseInt ()를 캡슐화하는 좋은 방법


91

Integer.parseInt()String을 int로 변환하는 데 자주 사용하는 프로젝트가 있습니다. 무언가 잘못되었을 때 (예를 들어, String숫자가 아니라 문자 a등)이 메서드는 예외를 발생시킵니다. 그러나 모든 곳에서 내 코드에서 예외를 처리해야한다면 이것은 매우 빠르게보기 흉하게 보이기 시작합니다. 나는 이것을 메소드에 넣고 싶지만 변환이 잘못되었음을 보여주기 위해 깨끗한 값을 반환하는 방법에 대한 단서가 없습니다.

C ++에서는 int에 대한 포인터를 받아들이고 메서드 자체가 true 또는 false를 반환하도록하는 메서드를 만들 수 있습니다. 그러나 내가 아는 한 이것은 Java에서 가능하지 않습니다. 참 / 거짓 변수와 변환 된 값을 포함하는 개체를 만들 수도 있지만 이것도 이상적이지 않습니다. 같은 일이 전역 값에 적용되며 이것은 다중 스레딩에 문제를 일으킬 수 있습니다.

이 작업을 수행하는 깨끗한 방법이 있습니까?


문자열의 문자는 첫 번째 문자 ...를 제외하고 모두 10 진수 여야합니다 . 코드의 모든 곳에서 예외를 처리하는 대신 parse 메서드를 호출하기 전에 문자열 형식을 확인하기 만하면됩니다.
Lightman

모든 유효한 32 비트 부호있는 정수를 캡처하고 유효하지 않은 정수는 캡처하지 않는 정규식을 작성하는 것은 거의 불가능합니다. 2147483647은 합법적 int이지만 2147483648은 그렇지 않습니다.
Seva Alekseyev

답변:


142

Integer대신을 int반환 null하여 구문 분석 실패시 반환 할 수 있습니다.

내부적으로 예외가 발생하지 않고 Java가이 작업을 수행하는 방법을 제공하지 않는 것은 부끄러운 일입니다. 예외를 포착하고 null을 반환하여 예외를 숨길 수 있지만 수백을 구문 분석하는 경우 여전히 성능 문제가 될 수 있습니다. 수천 비트의 사용자 제공 데이터.

편집 : 이러한 방법에 대한 코드 :

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

textnull 인 경우 이것이 무엇을할지 내 머리 꼭대기에서 확실하지 않습니다 . -버그를 나타내는 경우 (즉, 코드가 유효하지 않은 값을 전달할 수 있지만 null을 전달해서는 안 됨) 예외를 던지는 것이 적절합니다. 버그를 나타내지 않는 경우 다른 잘못된 값과 마찬가지로 null을 반환해야합니다.

원래이 답변은 new Integer(String)생성자를 사용했습니다 . 이제는 Integer.parseInt권투 작업을 사용 합니다. 이런 식으로 작은 값은 캐시 된 Integer개체 에 상자로 묶여 이러한 상황에서 더 효율적으로 만듭니다.


1
이것이 어떻게 도움이됩니까? 호출 사이트에는 다음이 필요합니다. <b> temp = tryParse (...); if (temp! = Null) {target = temp; } else {do ​​recovery action}; </ b> 복구 부분에 예외 발생 가능성이 있습니다. 원래 공식에서 호출 사이트에는 <b> try target = (...). parseInt; catch (...) {do recovery action} </ b> 간단한 catch 절을 제거하여 구현되는 복구에서 사소한 throw 예외가 있습니다. 제안 된 솔루션이이를 이해하기 쉽게 만들거나 (매직 트릭이 있음) 어떤 식 으로든 코드 양을 줄이는 방법은 무엇입니까?
Ira Baxter

15
일반적으로 null예외를 정기적으로 처리하는 것보다 참조 를 확인하는 코드가 더 깔끔 합니다.
Adam Maras

null을 값으로 전달하는 것을 피하는 것이 더 깨끗하지만 대신 en 오류가 발생했음을 나타냅니다. 흐름 제어에 예외를 사용해서는 안됩니다.
Esko

2
@Steve Kuo : 왜? 혜택은 어디에 있습니까? 둘 다 매번 새로운 정수를 생성합니까? 어쨌든 Integer.parseInt를 사용하고 오토 박싱이 처리하도록하여 작은 값에 대해 캐시를 활용하고 싶습니다.
Jon Skeet

1
@Vlasec 그리고 Optional이 아니라 OptionalInt와 같은 프리미티브를위한 특수 버전.
Joshua Taylor

37

숫자가 아닌 경우 어떤 행동을 기대합니까?

예를 들어 입력이 숫자가 아닐 때 사용할 기본값이있는 경우 다음과 같은 방법이 유용 할 수 있습니다.

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

입력을 구문 분석 할 수없는 경우 다른 기본 동작에 대해 유사한 메서드를 작성할 수 있습니다.


29

어떤 경우에는 파싱 오류를 fail-fast 상황으로 처리해야하지만 애플리케이션 구성과 같은 다른 경우에는 Apache Commons Lang 3 NumberUtils를 사용하여 누락 된 입력을 기본값으로 처리하는 것을 선호합니다 .

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);

다른 이유로 (StringUtils와 같은) 프로젝트에서 이미 아파치 커먼즈를 사용하고있는 대부분의 경우 편리합니다.
Ratata Tata

16

예외 처리를 방지하려면 정규식을 사용하여 먼저 모든 숫자가 있는지 확인하십시오.

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

답변 주셔서 감사합니다. 이 페이지의 대부분의 답변을 읽었으며 개인적으로 try / catch 솔루션을 작성했습니다. 그러나 여기에 그 해결책에 대한 내 문제가 있습니다. 대부분의 IDE는 루프 내부에 try / catch가있을 때 코드 흐름을 분석하는 데 방해가됩니다. 그래서 try / catch가없는 솔루션이 필요한 것입니다.
빅터 n.

4
조심해. 0으로 시작하는 정수와 일치하는 정규식은 NumberFormatException을 발생시킵니다. this ^ (? : [1-9] \ d * | 0) $ from stackoverflow.com/questions/12018479/…
Goose

5
이 특정 정규식은 음수를 처리하지 않습니다.
Brad Cupit

7
이 정수의 범위 외에 해당 번호의 범위를 커버하지 않습니다
모하마드 야히아

10

Ints.tryParse()구아바 . 숫자가 아닌 문자열에는 예외가 발생하지 않지만 null 문자열에는 예외가 발생합니다.


4

질문에 대한 답변을 읽은 후 parseInt 메서드를 캡슐화하거나 래핑하는 것은 필요하지 않으며 좋은 생각이 아닐 수도 있습니다.

Jon이 제안한대로 'null'을 반환 할 수 있지만 이는 try / catch 구조를 null 검사로 대체하는 것입니다. 오류 처리를 '잊는'경우 동작에는 약간의 차이가 있습니다. 예외를 포착하지 않으면 할당이없고 왼쪽 변수가 이전 값을 유지합니다. null을 테스트하지 않으면 JVM (NPE)에 맞을 것입니다.

하품의 제안은 나에게 더 우아하게 보입니다. 왜냐하면 나는 일부 오류나 예외적 인 상태를 알리기 위해 null을 반환하는 것을 좋아하지 않기 때문입니다. 이제 문제를 나타내는 미리 정의 된 개체를 사용하여 참조 동등성을 확인해야합니다. 그러나 다른 사람들이 주장 하듯이 다시 확인하는 것을 '잊고'문자열을 구문 분석 할 수없는 경우 프로그램은 'ERROR'또는 'NULL'개체 내부에 래핑 된 int와 연속됩니다.

Nikolay의 솔루션은 훨씬 더 객체 지향적이며 다른 래퍼 클래스의 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;
}

}

어쩌면 패턴을 사용하는 솔루션이 마음에 듭니다. 매우 haskelly;)
rodrigoelp 2013-10-31

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

Jon Skeet의 대답은 괜찮지 만 nullInteger 객체 를 돌려주는 것을 좋아하지 않습니다 . 나는 이것을 사용하는 것이 혼란 스럽습니다. Java 8 이후에는 다음을 사용하는 더 나은 옵션이 있습니다 OptionalInt.

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

이는 사용 가능한 값이없는 경우를 처리해야 함을 명시합니다. 앞으로 이런 종류의 함수가 자바 라이브러리에 추가되면 좋겠지 만 그럴지는 모르겠습니다.



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는 변환 결과 (참조로)와 변환이 성공했는지 (또는 실패했는지) 표시를 원합니다.
09:29에 하품

1
@yawn : 그리고 null 참조는 정확히 그 표시를 제공합니다.
Jon Skeet

@John Skeet : 맞지만 그의 의도를 다르게 읽었습니다. 그는 성공 / 실패 + 가치를 구별하기 위해 중간 객체를 사용하는 것과 같은 것을 썼습니다. C ++ 배경에서 왔기 때문에 (객체 대신) null을 사용하고 싶다면 처음에 질문하지 않았을 것이라고 생각했습니다.
09:36에 하품

"값"과 "객체"사이에는 큰 차이가 있습니다. null 참조는 깨끗한 값이지만 개체는 아닙니다.
Jon Skeet

1. Integer.tryParse표준 Java Integer클래스 에는 없습니다 . 2. new IntegerJava가 자동으로 boxing 및 unboxing을 수행 하므로 수행 할 필요가 없으며 권장되지 않습니다. 귀하의 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

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

주요 방법은 코드를 시연합니다. Parser 인터페이스를 구현하는 또 다른 방법은 구성에서 "\ D +"를 설정하고 메서드가 아무 작업도 수행하지 않도록하는 것입니다.


0

당신은 할 수 자신의 롤하지만 사용 공유지에 그냥 쉽게 랭의의 StringUtils.isNumeric() 방법 . 그것은 사용 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

예외를 피하기 위해 Java의 Format.parseObject메소드를 사용할 수 있습니다 . 아래 코드는 기본적으로 Apache Common의 IntegerValidator 클래스 의 단순화 된 버전입니다 .

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이 끝날 때까지 기다릴 것이라는 것입니다. 더 나은 접근 방식은 로깅 프레임 워크를 사용하는 것입니다.
Omar Hrynkiewicz

0

이것은 8391979, "Java에 잘못된 데이터에 대한 예외를 발생시키지 않는 int.tryparse가 있습니까? [중복]"라는 질문에 대한 답변입니다.

2016 08 17 편집 : ltrimZeroes 메서드를 추가하고 tryParse ()에서 호출했습니다. numberString의 앞에 0이 없으면 잘못된 결과가 나타날 수 있습니다 (코드의 주석 참조). 이제 양수 및 음수 "숫자"에 대해 작동하는 공용 정적 문자열 ltrimZeroes (String numberString) 메소드도 있습니다 (END 편집).

아래에는 문자열 자체를 구문 분석하고 Java의 Integer.parseInt (String s)보다 조금 더 빠른 속도로 최적화 된 tryParse () 메서드 (C #에서와 유사)가있는 int에 대한 기초적인 래퍼 (복싱) 클래스가 있습니다.

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하여 작업을 수행하기 위해 소스 코드를 복사하여 붙여넣고 개선했습니다.

  • 잠재적으로 느린 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) 를 조정할 수도 있습니다 .


'문자열 정수'가 문자열 리터럴 "0"이면 어떻게됩니까? 잘못된 입력이 있었는지 결코 알 수 없습니다.
Bart Kiers

두 정수에 대한 == 연산자가 값이나 참조를 비교하는지 여부에 따라 다릅니다. 값을 비교하면 문제가있는 것입니다. 참조를 비교하면 내 대답과 동일한 방식으로 작동합니다.
Adam Maras

왜 반대 투표입니까? 내 대답은 정확하며 항상 유효한 Integer 인스턴스 (null 대신)를 처리하여 NPE를 처리 할 필요가 없도록하는 이점 (null 이상)을 제공합니다.
09:25에 하품

null을 실수 정수와 구별하는 것은 하지만 유용합니다 . 당신은 해야 구문 분석에 성공했는지 여부를 알고, 무효의 결과를 테스트 할 수. 그 뒤에 사용 가능한 물건을 숨기는 것은 문제의 처방입니다.
Jon Skeet

더 많은 반대표-흥미 롭습니다! / me가 처음이므로 유권자 중 한 명이 나에게 이유를 설명 할 수 있습니까?
09:33에 하품

-1

값의 유효성을 검사하기 위해 예외를 사용해서는 안됩니다 .

단일 문자의 경우 간단한 해결책이 있습니다.

Character.isDigit()

더 긴 값의 경우 일부 유틸리티를 사용하는 것이 좋습니다. Apache에서 제공하는 NumberUtils는 여기서 완벽하게 작동합니다.

NumberUtils.isNumber()

https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html을 확인 하십시오.


«문자열이 유효한 Java 번호인지 확인합니다. 유효한 숫자에는 0x 한정자로 표시된 16 진수, 과학적 표기법 및 유형 한정자로 표시된 숫자 (예 : 123L)가 포함됩니다.» 이것은으로 구문 분석 할 수있는 것이 아닙니다 Integer.parseInt.
Miha_x64
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.