Some changes in the is-numeric (#8171)
* Perform a null-check instead of catching NPE's * Use pre-compiled regular expressions and perform a null-check before testing it against the regex * Made the test usable with two modes, one using a single values and another one using a more realistic workload. * Upgraded the commons-lang version
This commit is contained in:
parent
8095153e25
commit
76a4694c42
|
@ -58,7 +58,7 @@
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<commons-lang3.version>3.8.1</commons-lang3.version>
|
<commons-lang3.version>3.9</commons-lang3.version>
|
||||||
<assertj.version>3.6.1</assertj.version>
|
<assertj.version>3.6.1</assertj.version>
|
||||||
<commons-codec.version>1.10</commons-codec.version>
|
<commons-codec.version>1.10</commons-codec.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.baeldung.isnumeric;
|
package com.baeldung.isnumeric;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
@ -14,6 +17,8 @@ import org.openjdk.jmh.runner.options.Options;
|
||||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
public class Benchmarking {
|
public class Benchmarking {
|
||||||
|
private static final TestMode MODE = TestMode.DIVERS;
|
||||||
|
|
||||||
public static void main(String[] args) throws RunnerException {
|
public static void main(String[] args) throws RunnerException {
|
||||||
Options opt = new OptionsBuilder().include(Benchmarking.class.getSimpleName())
|
Options opt = new OptionsBuilder().include(Benchmarking.class.getSimpleName())
|
||||||
.forks(1)
|
.forks(1)
|
||||||
|
@ -22,52 +27,89 @@ public class Benchmarking {
|
||||||
new Runner(opt).run();
|
new Runner(opt).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final IsNumeric subject = new IsNumeric();
|
||||||
|
|
||||||
@State(Scope.Thread)
|
@State(Scope.Thread)
|
||||||
public static class ExecutionPlan {
|
public static class ExecutionPlan {
|
||||||
public String number = Integer.toString(Integer.MAX_VALUE);
|
private final Map<String, Boolean> testPlan = testPlan();
|
||||||
public boolean isNumber = false;
|
|
||||||
public IsNumeric isNumeric = new IsNumeric();
|
void validate(Function<String, Boolean> functionUnderTest) {
|
||||||
|
testPlan.forEach((key, value) -> {
|
||||||
|
Boolean result = functionUnderTest.apply(key);
|
||||||
|
|
||||||
|
assertEquals(value, result, key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertEquals(Boolean expectedResult, Boolean result, String input) {
|
||||||
|
if (result != expectedResult) {
|
||||||
|
throw new IllegalStateException("The output does not match the expected output, for input: " + input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Boolean> testPlan() {
|
||||||
|
HashMap<String, Boolean> plan = new HashMap<>();
|
||||||
|
plan.put(Integer.toString(Integer.MAX_VALUE), true);
|
||||||
|
|
||||||
|
if (MODE == TestMode.SIMPLE) {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
plan.put("x0", false);
|
||||||
|
plan.put("0..005", false);
|
||||||
|
plan.put("--11", false);
|
||||||
|
plan.put("test", false);
|
||||||
|
plan.put(null, false);
|
||||||
|
for (int i = 0; i < 94; i++) {
|
||||||
|
plan.put(Integer.toString(i), true);
|
||||||
|
}
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
public void usingCoreJava(ExecutionPlan plan) {
|
public void usingCoreJava(ExecutionPlan plan) {
|
||||||
plan.isNumber = plan.isNumeric.usingCoreJava(plan.number);
|
plan.validate(subject::usingCoreJava);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
public void usingRegularExpressions(ExecutionPlan plan) {
|
public void usingRegularExpressions(ExecutionPlan plan) {
|
||||||
plan.isNumber = plan.isNumeric.usingRegularExpressions(plan.number);
|
plan.validate(subject::usingPreCompiledRegularExpressions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
public void usingNumberUtils_isCreatable(ExecutionPlan plan) {
|
public void usingNumberUtils_isCreatable(ExecutionPlan plan) {
|
||||||
plan.isNumber = plan.isNumeric.usingNumberUtils_isCreatable(plan.number);
|
plan.validate(subject::usingNumberUtils_isCreatable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
public void usingNumberUtils_isParsable(ExecutionPlan plan) {
|
public void usingNumberUtils_isParsable(ExecutionPlan plan) {
|
||||||
plan.isNumber = plan.isNumeric.usingNumberUtils_isParsable(plan.number);
|
plan.validate(subject::usingNumberUtils_isParsable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
public void usingStringUtils_isNumeric(ExecutionPlan plan) {
|
public void usingStringUtils_isNumeric(ExecutionPlan plan) {
|
||||||
plan.isNumber = plan.isNumeric.usingStringUtils_isNumeric(plan.number);
|
plan.validate(subject::usingStringUtils_isNumeric);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
public void usingStringUtils_isNumericSpace(ExecutionPlan plan) {
|
public void usingStringUtils_isNumericSpace(ExecutionPlan plan) {
|
||||||
plan.isNumber = plan.isNumeric.usingStringUtils_isNumericSpace(plan.number);
|
plan.validate(subject::usingStringUtils_isNumericSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum TestMode {
|
||||||
|
SIMPLE, DIVERS
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,20 +1,33 @@
|
||||||
package com.baeldung.isnumeric;
|
package com.baeldung.isnumeric;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
import org.apache.commons.lang3.math.NumberUtils;
|
||||||
|
|
||||||
public class IsNumeric {
|
public class IsNumeric {
|
||||||
|
private final Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?");
|
||||||
|
|
||||||
public boolean usingCoreJava(String strNum) {
|
public boolean usingCoreJava(String strNum) {
|
||||||
|
if (strNum == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Double.parseDouble(strNum);
|
Double.parseDouble(strNum);
|
||||||
} catch (NumberFormatException | NullPointerException nfe) {
|
} catch (NumberFormatException nfe) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean usingRegularExpressions(String strNum) {
|
public boolean usingPreCompiledRegularExpressions(String strNum) {
|
||||||
return strNum.matches("-?\\d+(\\.\\d+)?");
|
if (strNum == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pattern.matcher(strNum)
|
||||||
|
.matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean usingNumberUtils_isCreatable(String strNum) {
|
public boolean usingNumberUtils_isCreatable(String strNum) {
|
||||||
|
|
|
@ -13,8 +13,8 @@ public class IsNumericDriver {
|
||||||
boolean res = isNumeric.usingCoreJava("1001");
|
boolean res = isNumeric.usingCoreJava("1001");
|
||||||
LOG.info("Using Core Java : " + res);
|
LOG.info("Using Core Java : " + res);
|
||||||
|
|
||||||
res = isNumeric.usingRegularExpressions("1001");
|
res = isNumeric.usingPreCompiledRegularExpressions("1001");
|
||||||
LOG.info("Using Regular Expressions : " + res);
|
LOG.info("Using Pre-compiled Regular Expressions : " + res);
|
||||||
|
|
||||||
res = isNumeric.usingNumberUtils_isCreatable("1001");
|
res = isNumeric.usingNumberUtils_isCreatable("1001");
|
||||||
LOG.info("Using NumberUtils.isCreatable : " + res);
|
LOG.info("Using NumberUtils.isCreatable : " + res);
|
||||||
|
|
|
@ -6,9 +6,13 @@ import org.junit.Test;
|
||||||
|
|
||||||
public class CoreJavaIsNumericUnitTest {
|
public class CoreJavaIsNumericUnitTest {
|
||||||
public static boolean isNumeric(String strNum) {
|
public static boolean isNumeric(String strNum) {
|
||||||
|
if (strNum == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
double d = Double.parseDouble(strNum);
|
Double.parseDouble(strNum);
|
||||||
} catch (NumberFormatException | NullPointerException nfe) {
|
} catch (NumberFormatException nfe) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,11 +2,19 @@ package com.baeldung.isnumeric;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class RegularExpressionsUnitTest {
|
public class RegularExpressionsUnitTest {
|
||||||
public static boolean isNumeric(String strNum) {
|
private final Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?");
|
||||||
return strNum.matches("-?\\d+(\\.\\d+)?");
|
|
||||||
|
public boolean isNumeric(String strNum) {
|
||||||
|
if (strNum == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return pattern.matcher(strNum)
|
||||||
|
.matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -17,6 +25,7 @@ public class RegularExpressionsUnitTest {
|
||||||
assertThat(isNumeric("-200")).isTrue();
|
assertThat(isNumeric("-200")).isTrue();
|
||||||
|
|
||||||
// Invalid Numbers
|
// Invalid Numbers
|
||||||
|
assertThat(isNumeric(null)).isFalse();
|
||||||
assertThat(isNumeric("abc")).isFalse();
|
assertThat(isNumeric("abc")).isFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue