Java 带参数的Pattern.compile()
假设我有这个代码:Java 带参数的Pattern.compile(),java,regex,Java,Regex,假设我有这个代码: 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;
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(value);
return matcher.matches();
}
.......
checkRegex("^.+@.+\\..+$", "email@example.com");
我的正则表达式是在编译时编译一次还是在运行时编译多次?模式。compile(regex)
只是一个对编译器没有特殊意义的方法,因此它只能在运行时执行。虽然可以缓存已编译的模式(这是用其他语言完成的,如Python),但Sun/Oracle的模式
实现不会缓存已编译的模式
,这意味着每次执行checkRegex
方法时(即使使用相同的regex),重新编译正则表达式,得到一个新的模式
实例
顺便说一下,你的方法
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);
}
Pattern.compile(regex)
只是一个对编译器没有特殊意义的方法,因此它只能在运行时执行。虽然可以缓存已编译的模式(这是用其他语言完成的,如Python),但Sun/Oracle的模式
实现不会缓存已编译的模式
,这意味着每次执行checkRegex
方法时(即使使用相同的regex),重新编译正则表达式,得到一个新的模式
实例
顺便说一下,你的方法
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);
}
简短回答
虽然从理论角度来看可能,不;不是在编译时,它们将再次编译
但是Pattern
使用Flyweight模式,这样一旦编译了regex,它就会存储在内存中,因此运行时不需要进行完整编译
编译时
从理论上看,编译器有可能执行已知的操作,从而在编译时解决问题。如果您调用的方法是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字节码,并使用两个参数调用该方法
一些编译器(主要是函数和逻辑编程语言的编译器)允许程序专门化:如果某个调用是用常量完成的,编译器可以创建该方法的副本,并在编译时解析已知的内容。然而,这是一种折衷,因为引入大量的专门方法将减少大量代码
运行时的Flyweight模式
如果深入研究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>
}
私有静态最终哈希映射;
静态CharProperty charPropertyFor(字符串名称){
//
/*0:getstaticjava/util/regex/Pattern$CharPropertyNames.map:Ljava/util/HashMap;
*3:aload_0
*4:invokevirtualjava/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:invokeVirtualJava/util/regex/Pattern$CharPropertyNames$CharPropertyFactory.make:()Ljava/util/regex/Pattern$CharProperty;
*23:轮到你了
* */
//
}
注意HashMap
,这意味着模式
存储正则表达式的片段及其相应的微DFA,这种行为称为。这意味着您只编译正则表达式一次。显然,您仍然需要执行查找,因此这不是免费的优化,但肯定会有所帮助。简短回答
虽然从理论角度来看可能,不;不是在编译时,它们将再次编译
但是Pattern
使用Flyweight模式,这样一旦编译了regex,它就会存储在内存中,因此运行时不需要进行完整编译
编译时
从理论上看,编译器有可能执行已知的操作,从而在编译时解决问题。如果您调用的方法是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字节码,并使用两个参数调用该方法
一些编译器(主要是函数和逻辑编程语言的编译器)允许程序专门化:如果某个调用是用常量完成的,编译器可以创建该方法的副本,并在编译时解析已知的内容。然而,这是一种折衷,因为引入大量的专门方法将减少大量代码
运行时的Flyweight模式
如果深入研究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>
}
私有静态最终哈希映射;
静态CharProperty charPropertyFor(字符串名称){
//
/*0:getstaticjava/util/regex/Pattern$CharPropertyNames.map:Ljava/util/HashMap;
*3:aload_0
*4:invokevirtualjava/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:invokeVirtualJava/util/regex/Pattern$CharPropertyNames$CharPropertyFactory.make:()Ljava/util/regex/Pattern$CharProperty;
*23:轮到你了
* */
//
}
注意HashMap
,这意味着模式
存储正则表达式的片段及其相应的微DFA,这种行为称为。这意味着您只编译正则表达式一次。显然你会