Pre-compile the regex pattern into a Pattern object and reuse

This commit is contained in:
Fabio Silva 2019-12-06 10:02:29 -03:00
parent 9b801298ca
commit 61ef5289a5
3 changed files with 170 additions and 0 deletions

View File

@ -0,0 +1,31 @@
package com.baeldung.pattern;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class PatternJava11UnitTest {
private static final String VALID_NAME = "Fabio Silva";
private static final String INVALID_NAME = "Fabio Luis Silva";
private static final List<String> NAMES_TO_VALIDATE = Arrays.asList(VALID_NAME, INVALID_NAME);
private static final Pattern FIRST_LAST_NAME_PRE_COMPILED_PATTERN = Pattern.compile("[a-zA-Z]{3,} [a-zA-Z]{3,}");
@Test
public void givenPreCompiledPattern_whenCallAsMatchPredicate_thenReturnMatchPredicateToMatchesThePatternInTheListElements() {
Predicate<String> patternAsMatchPredicate = FIRST_LAST_NAME_PRE_COMPILED_PATTERN.asMatchPredicate();
List<String> validatedNames = NAMES_TO_VALIDATE.stream()
.filter(patternAsMatchPredicate)
.collect(Collectors.toList());
assertTrue(validatedNames.contains(VALID_NAME));
assertFalse(validatedNames.contains(INVALID_NAME));
}
}

View File

@ -0,0 +1,71 @@
package com.baeldung.pattern;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternPerformanceComparison {
private static final String PATTERN = "\\d*[02468]";
private static List<String> values;
public static void main(String[] args) {
loadValues();
// 5_000_000 Pattern objects created
// 5_000_000 Matcher objects created
Instant start = Instant.now();
for (String value : values) {
value.matches(PATTERN);
}
System.out.println(Duration.between(start, Instant.now()).toMillis() + "ms -> String.matchs(regex)");
// Above approach "value.matches(PATTERN)" makes this internally
// 5_000_000 Pattern objects created
// 5_000_000 Matcher objects created
start = Instant.now();
for (String value : values) {
Pattern.matches(PATTERN, value);
}
System.out.println(Duration.between(start, Instant.now()).toMillis() + "ms -> Pattern.matches(regex, charSequence)");
// Above approach "Pattern.matches(PATTERN, value)" makes this internally
// 5_000_000 Pattern objects created
// 5_000_000 Matcher objects created
start = Instant.now();
for (String value : values) {
Pattern.compile(PATTERN).matcher(value).matches();
}
System.out.println(Duration.between(start, Instant.now()).toMillis() + "ms -> Pattern.compile(regex).matcher(charSequence).matches()");
// With pre-compiled pattern
// 1 Pattern object created
// 5_000_000 Matcher objects created
Pattern preCompiledPattern = Pattern.compile(PATTERN);
start = Instant.now();
for (String value : values) {
preCompiledPattern.matcher(value).matches();
}
System.out.println(Duration.between(start, Instant.now()).toMillis() + "ms -> preCompiledPattern.matcher(value).matches()");
//With pre-compiled pattern and reusing the matcher
// 1 Pattern object created
// 1 Matcher objects created
Matcher matcherFromPreCompiledPattern = preCompiledPattern.matcher("");
start = Instant.now();
for (String value : values) {
matcherFromPreCompiledPattern.reset(value).matches();
}
System.out.println(Duration.between(start, Instant.now()).toMillis() + "ms -> matcherFromPreCompiledPattern.reset(value).matches()");
}
private static void loadValues() {
values = new ArrayList<>();
for (int x = 1; x <= 5_000_000; x++) {
values.add(String.valueOf(x));
}
}
}

View File

@ -0,0 +1,68 @@
package com.baeldung.pattern;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.*;
public class PatternUnitTest {
private static final Pattern FIRST_LAST_NAME_PRE_COMPILED_PATTERN = Pattern.compile("[a-zA-Z]{3,} [a-zA-Z]{3,}");
private static final String VALID_NAME = "Fabio Silva";
private static final String INVALID_NAME = "Mr. Silva";
private static final List<String> NAMES_TO_VALIDATE = Arrays.asList(VALID_NAME, INVALID_NAME);
private static final Pattern SPLIT_PRE_COMPILED_PATTERN = Pattern.compile("__");
private static final String TEXT_TO_SPLIT = "My_Name__is__Fabio_Silva";
@Test
public void givenPreCompiledPattern_whenCallMatcher_thenReturnAMatcherToMatches() {
Matcher matcherName1 = FIRST_LAST_NAME_PRE_COMPILED_PATTERN.matcher(VALID_NAME);
Matcher matcherName2 = FIRST_LAST_NAME_PRE_COMPILED_PATTERN.matcher(INVALID_NAME);
boolean matchesName1 = matcherName1.matches();
boolean matchesName2 = matcherName2.matches();
assertTrue(matchesName1);
assertFalse(matchesName2);
}
@Test
public void givenPreCompiledPattern_whenCallAsPredicate_thenReturnPredicateToFindThePatternInTheListElements() {
Predicate<String> patternsAsPredicate = FIRST_LAST_NAME_PRE_COMPILED_PATTERN.asPredicate();
List<String> validNames = NAMES_TO_VALIDATE.stream()
.filter(patternsAsPredicate)
.collect(Collectors.toList());
assertEquals(1,validNames.size());
assertTrue(validNames.contains(VALID_NAME));
}
@Test
public void givenPreCompiledPattern_whenCallSplit_thenReturnArrayWithValuesSplitByThePattern() {
String[] textSplit = SPLIT_PRE_COMPILED_PATTERN.split(TEXT_TO_SPLIT);
assertEquals("My_Name", textSplit[0]);
assertEquals("is", textSplit[1]);
assertEquals("Fabio_Silva", textSplit[2]);
}
@Test
public void givenPreCompiledPattern_whenCallSplitAsStream_thenReturnArrayWithValuesSplitByThePattern() {
Stream<String> textSplitAsStream = SPLIT_PRE_COMPILED_PATTERN.splitAsStream(TEXT_TO_SPLIT);
String[] textSplit = textSplitAsStream.toArray(String[]::new);
assertEquals("My_Name", textSplit[0]);
assertEquals("is", textSplit[1]);
assertEquals("Fabio_Silva", textSplit[2]);
}
}