나는 일반적으로 문자열을 정수로 변환 할 수 있는지 확인하기 위해 다음 관용구를 사용합니다.
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();
}
}