[java] String이 Java에서 정수를 나타내는 지 확인하는 가장 좋은 방법은 무엇입니까?

나는 일반적으로 문자열을 정수로 변환 할 수 있는지 확인하기 위해 다음 관용구를 사용합니다.

public boolean isInteger( String input ) {
    try {
        Integer.parseInt( input );
        return true;
    }
    catch( Exception e ) {
        return false;
    }
}

그것은 단지 나입니까, 아니면 약간의 해킹처럼 보입니까? 더 좋은 방법은 무엇입니까?


내가 왜 내 입장을 바꾸었고이 문제에 대한 Jonas Klemming의 답변 을 받아들 였는지 알아 보려면 내 답변 ( CodingWithSpike이전 답변 을 기반으로 한 벤치 마크 포함 )을 참조하십시오 . 필자는이 원본 코드를 구현하는 것이 더 빠르고 유지 관리가 용이하기 때문에 대부분의 사람들이이 코드를 사용한다고 생각하지만 정수가 아닌 데이터가 제공되면 수십 배 느립니다.



답변

잠재적 오버플로 문제에 대해 걱정하지 않으면이 기능은을 사용하는 것보다 약 20-30 배 더 빠르게 수행됩니다 Integer.parseInt().

public static boolean isInteger(String str) {
    if (str == null) {
        return false;
    }
    int length = str.length();
    if (length == 0) {
        return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
        if (length == 1) {
            return false;
        }
        i = 1;
    }
    for (; i < length; i++) {
        char c = str.charAt(i);
        if (c < '0' || c > '9') {
            return false;
        }
    }
    return true;
}


답변

당신은 그것을 가지고 있지만, 당신은 잡아야 NumberFormatException합니다.


답변

빠른 벤치 마크를했습니다. 여러 메소드를 다시 시작하지 않고 JVM이 실행 스택을 가져 오기 위해 많은 작업을 수행하지 않는 한 실제로는 그렇게 많은 비용이 들지 않습니다. 같은 방법으로 머무를 때, 그들은 나쁜 수행자가 아닙니다.

 public void RunTests()
 {
     String str = "1234567890";

     long startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByException(str);
     long endTime = System.currentTimeMillis();
     System.out.print("ByException: ");
     System.out.println(endTime - startTime);

     startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByRegex(str);
     endTime = System.currentTimeMillis();
     System.out.print("ByRegex: ");
     System.out.println(endTime - startTime);

     startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByJonas(str);
     endTime = System.currentTimeMillis();
     System.out.print("ByJonas: ");
     System.out.println(endTime - startTime);
 }

 private boolean IsInt_ByException(String str)
 {
     try
     {
         Integer.parseInt(str);
         return true;
     }
     catch(NumberFormatException nfe)
     {
         return false;
     }
 }

 private boolean IsInt_ByRegex(String str)
 {
     return str.matches("^-?\\d+$");
 }

 public boolean IsInt_ByJonas(String str)
 {
     if (str == null) {
             return false;
     }
     int length = str.length();
     if (length == 0) {
             return false;
     }
     int i = 0;
     if (str.charAt(0) == '-') {
             if (length == 1) {
                     return false;
             }
             i = 1;
     }
     for (; i < length; i++) {
             char c = str.charAt(i);
             if (c <= '/' || c >= ':') {
                     return false;
             }
     }
     return true;
 }

산출:

예외 : 31

ByRegex : 453 (참고 : 매번 패턴을 다시 컴파일)

바이 조나스 : 16

Jonas K의 솔루션이 가장 강력하다는 데 동의합니다. 그가이기는 것 같습니다 🙂


답변

사람들이 여전히 여기에 방문하여 벤치 마크 후에 Regex에 대해 편견을 가질 가능성이 있기 때문에 … 그래서 컴파일 된 버전의 Regex로 벤치 마크의 업데이트 버전을 제공 할 것입니다. 이전 벤치 마크와 달리이 솔루션은 Regex 솔루션의 성능이 지속적으로 우수함을 보여줍니다.

Bill the Lizard에서 복사하고 컴파일 된 버전으로 업데이트했습니다.

private final Pattern pattern = Pattern.compile("^-?\\d+$");

public void runTests() {
    String big_int = "1234567890";
    String non_int = "1234XY7890";

    long startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByException(big_int);
    long endTime = System.currentTimeMillis();
    System.out.print("ByException - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByException(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByException - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByRegex - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
            IsInt_ByCompiledRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByCompiledRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
            IsInt_ByCompiledRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByCompiledRegex - non-integer data: ");
    System.out.println(endTime - startTime);


    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByJonas - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByJonas - non-integer data: ");
    System.out.println(endTime - startTime);
}

private boolean IsInt_ByException(String str)
{
    try
    {
        Integer.parseInt(str);
        return true;
    }
    catch(NumberFormatException nfe)
    {
        return false;
    }
}

private boolean IsInt_ByRegex(String str)
{
    return str.matches("^-?\\d+$");
}

private boolean IsInt_ByCompiledRegex(String str) {
    return pattern.matcher(str).find();
}

public boolean IsInt_ByJonas(String str)
{
    if (str == null) {
            return false;
    }
    int length = str.length();
    if (length == 0) {
            return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
            if (length == 1) {
                    return false;
            }
            i = 1;
    }
    for (; i < length; i++) {
            char c = str.charAt(i);
            if (c <= '/' || c >= ':') {
                    return false;
            }
    }
    return true;
}

결과 :

ByException - integer data: 45
ByException - non-integer data: 465

ByRegex - integer data: 272
ByRegex - non-integer data: 131

ByCompiledRegex - integer data: 45
ByCompiledRegex - non-integer data: 26

ByJonas - integer data: 8
ByJonas - non-integer data: 2


답변

org.apache.commons.lang.StringUtils.isNumeric 

Java의 표준 lib는 실제로 그러한 유틸리티 기능을 그리워합니다.

Apache Commons는 모든 Java 프로그래머에게 “필수 사항”이라고 생각합니다

너무 나빠 아직 Java5로 포팅되지 않았습니다.


답변

“정수로 변환 할 수 있습니다”라는 의미에 부분적으로 의존합니다.

“Java에서 int로 변환 할 수있다”는 것을 의미한다면 Jonas의 대답은 좋은 출발이지만 작업을 끝내지는 못합니다. 예를 들어 999999999999999999999999999999를 전달합니다. 메서드 끝에 자신의 질문에서 일반적인 try / catch 호출을 추가합니다.

문자 별 검사는 “정수가 아닌”경우를 효율적으로 거부하여 “정수이지만 Java가 처리 할 수 ​​없습니다”라는 경우를 제외하고 느린 예외 경로에 의해 포착됩니다. 당신은 할 수 너무 손이 비트를 할 수 있지만, 그것은 것 많이 더 복잡.


답변

regexp에 대한 한 가지 의견. 여기에 제공된 모든 예가 잘못되었습니다!. regexp를 사용하려면 패턴을 컴파일하는 데 많은 시간이 걸린다는 것을 잊지 마십시오. 이:

str.matches("^-?\\d+$")

또한 이것 :

Pattern.matches("-?\\d+", input);

모든 메소드 호출에서 패턴을 컴파일합니다. 올바르게 사용하려면 다음을 수행하십시오.

import java.util.regex.Pattern;

/**
 * @author Rastislav Komara
 */
public class NaturalNumberChecker {
    public static final Pattern PATTERN = Pattern.compile("^\\d+$");

    boolean isNaturalNumber(CharSequence input) {
        return input != null && PATTERN.matcher(input).matches();
    }
}