说我有这段代码:
public static boolean checkRegex(String regex, String value) {
if (value == null) return false;
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(value);
return matcher.matches();
}
.......
checkRegex("^.+@.+\\..+$", "email@example.com");
我的正则表达式会在编译时编译一次还是在运行时编译多次?
答案 0 :(得分:4)
Pattern.compile(regex)
只是一种对编译器没有特殊意义的方法,因此只能在运行时执行。虽然可以缓存已编译的模式(在其他语言中完成,例如Python),但Sun / Oracle的Pattern
实现不会缓存已编译的Pattern
,这意味着每次执行checkRegex
方法(即使使用相同的正则表达式),您再次编译正则表达式并获得一个新的Pattern
实例。
顺便说一下,你的方法
public static boolean checkRegex(String regex, String value) {
if (value == null) return false;
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(value);
return matcher.matches();
}
可以改写为
public static boolean checkRegex(String regex, String value) {
if (value == null)
return false;
return value.matches(regex);
}
答案 1 :(得分:1)
虽然也许从理论的角度来看,不;不是在编译时,这些都是再次编译的。
但是Pattern
使用 Flyweight 模式,这样一旦正则表达式被编译,它就会存储在内存中,因此不需要在运行时完全编译
从理论的角度来看,编译器可能会执行所谓的constant propagation,从而在编译时解决问题。如果你调用的方法是final(或者在编译时已知被调用者)等等,这可以完成。
如果有人编译你的方法并检查 Java字节码,它会编译为:
public static boolean checkRegex(java.lang.String, java.lang.String);
Code:
0: aload_1
1: ifnonnull 6
4: iconst_0
5: ireturn
6: aload_0
7: invokestatic #15 // Method java/util/regex/Pattern.compile:(Ljava/lang/String;)Ljava/util/regex/Pattern;
10: astore_2
11: aload_2
12: aload_1
13: invokevirtual #16 // Method java/util/regex/Pattern.matcher:(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;
16: astore_3
17: aload_3
18: invokevirtual #17 // Method java/util/regex/Matcher.matches:()Z
21: ireturn
public static void main(java.lang.String[]);
Code:
0: ldc #18 // String ^.+@.+\..+$
2: ldc #19 // String email@example.com
4: invokestatic #20 // Method checkRegex:(Ljava/lang/String;Ljava/lang/String;)Z
7: pop
...
正如您可能看到的那样,这些方法只是简单地转换为Java字节代码,并使用这两个参数调用该方法。
某些编译器(主要是函数和逻辑编程语言的编译器)允许程序专门化:如果使用常量完成某个调用,编译器可以创建该方法的副本并解决已知的问题在编译时。然而,它是一个权衡,因为引入了大量专门的方法,将减少大量的代码库。
运行时如果你深入研究java.util.regex.Pattern
的Java字节码,你会看到:
private static final HashMap<String, CharPropertyFactory> map;
static CharProperty charPropertyFor(String name) {
// <editor-fold defaultstate="collapsed" desc="Compiled Code">
/* 0: getstatic java/util/regex/Pattern$CharPropertyNames.map:Ljava/util/HashMap;
* 3: aload_0
* 4: invokevirtual java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
* 7: checkcast java/util/regex/Pattern$CharPropertyNames$CharPropertyFactory
* 10: astore_1
* 11: aload_1
* 12: ifnonnull 19
* 15: aconst_null
* 16: goto 23
* 19: aload_1
* 20: invokevirtual java/util/regex/Pattern$CharPropertyNames$CharPropertyFactory.make:()Ljava/util/regex/Pattern$CharProperty;
* 23: areturn
* */
// </editor-fold>
}
请注意HashMap
,这意味着Pattern
存储正则表达式的片段及其相应的微型DFA,此行为称为Flyweight。这意味着您只需编译一次正则表达式。显然你仍然需要执行查找,所以这不是免费的优化,但它肯定会有所帮助。