阅读《Effective Java》作者提到了对String.matches()方法的优化
一. String.matches()的源码:
java.util.regex.Pattern#matches
public static boolean matches(String regex, CharSequence input) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
return m.matches();
}
private Pattern(String p, int f) {
pattern = p;
flags = f;
// to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
if ((flags & UNICODE_CHARACTER_CLASS) != 0)
flags |= UNICODE_CASE;
// Reset group index count
capturingGroupCount = 1;
localCount = 0;
if (pattern.length() > 0) {
try {
compile();
} catch (StackOverflowError soe) {
throw error("Stack overflow during pattern compilation");
}
} else {
root = new Start(lastAccept);
matchRoot = lastAccept;
}
}
可以看到, 源码中每次都会使用Pattern的构造器创建一个Pattern的实例, 却只用了一次, 之后就会被垃圾回收了, 看完源码你会发现创建Pattern实例的成本很高, 因为需要将正则编译成一个有限状态机
为了提升性能, 可以显式的将正则表达式编译成一个Pattern实例(不可变的), 通过类初始化来实现, 并将它缓存起来, 这样每次调用方法就重用一个实例, 测试代码如下:
private static final Pattern P = Pattern.compile("[A-Z]");
@Test
public void test02() {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
P.matcher("b");
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
@Test
public void test03() {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
"B".matches("[A-Z]");
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
如果方法被频繁的调用, (比如在循环中判断字符串是否匹配), 会显示出明显的性能优势