最近在看Spring Security utilize a response wrapper (FirewalledResponse )的时候发现 Issue 6731 improve performance of checking headers . 主要的原因就是使用了正则,导致效率降低,如果是简单的匹配尽量避免使用正则。
随之想到使用非常频繁的Java.String.replaceAll
, 它的效率是否也比其他不使用正则的替换方法低呢?
之前在使用几个不同替换方法的时候并没有关注效率问题。但如果在非常频繁的使用场景下,替换方法效率的提升是否就非常有意义了呢?
Java 自带replace all方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ReplaceAll { String value; public String replaceAllWithContains () { return value.contains("." ) ? value.replaceAll("\\." , "%2E" ) : value; } public String replaceAll () { return value.replaceAll("\\." , "%2E" ); } public String replace () { return value.replace("." , "%2E" ); } public String replaceWithContains () { return value.contains("." ) ? value.replace("." , "%2E" ) : value; } }
java.lang.replace
replace(CharSequence target, CharSequence replacement),用replacement替换所有的target,两个参数都是字符串。
java.lang.replaceAll
replaceAll(String regex, String replacement),用replacement替换所有的regex匹配项,regex很明显是个正则表达式,replacement是字符串。
对比结果
JDK 11.0.8, OpenJDK 64-Bit Server VM, 11.0.8+10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Benchmark (value) Mode Cnt Score Error Units ReplaceAll.replace avgt 10 3.836 ± 0.060 ns/op ReplaceAll.replaceAll avgt 10 147.857 ± 1.550 ns/op ReplaceAll.replaceAllWithContains avgt 10 3.777 ± 0.069 ns/op ReplaceAll.replaceWithContains avgt 10 3.778 ± 0.075 ns/op ReplaceAll.replace somePathNoDoT avgt 10 7.647 ± 0.646 ns/op ReplaceAll.replaceAll somePathNoDoT avgt 10 156.495 ± 1.751 ns/op ReplaceAll.replaceAllWithContains somePathNoDoT avgt 10 7.640 ± 0.291 ns/op ReplaceAll.replaceWithContains somePathNoDoT avgt 10 7.545 ± 0.298 ns/op ReplaceAll.replace some.Path.With.Dot avgt 10 123.856 ± 1.686 ns/op ReplaceAll.replaceAll some.Path.With.Dot avgt 10 389.632 ± 18.308 ns/op ReplaceAll.replaceAllWithContains some.Path.With.Dot avgt 10 378.527 ± 6.434 ns/op ReplaceAll.replaceWithContains some.Path.With.Dot avgt 10 126.918 ± 0.940 ns/op
可以看出效率由高到低:
不含target时:
replaceWithContains > replace > replaceAllWithContains > replaceAll
含有target时:
replace > replaceWithContains> replaceAllWithContains > replaceAll
结论:
尽量使用replace,而非replaceAll.
其他实现replace all方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import org.apache.commons.lang3.StringUtils;public class ReplaceCustom { String value; public String replace () { return value.replace("." , "/" ); } public String replaceSpring () { return springReplace(value, "." , "/" ); } public String replaceChar () { return value.replace('.' , '/' ); } public String replaceApache () { return StringUtils.replace(value, "." , "/" ); } public String replaceApacheChar () { return StringUtils.replaceChars(value, '.' , '/' ); } public static boolean hasLength (String str) { return (str != null && !str.isEmpty()); } public static String springReplace (String inString, String oldPattern, String newPattern) { if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null ) { return inString; } int index = inString.indexOf(oldPattern); if (index == -1 ) { return inString; } int capacity = inString.length(); if (newPattern.length() > oldPattern.length()) { capacity += 16 ; } StringBuilder sb = new StringBuilder(capacity); int pos = 0 ; int patLen = oldPattern.length(); while (index >= 0 ) { sb.append(inString, pos, index); sb.append(newPattern); pos = index + patLen; index = inString.indexOf(oldPattern, pos); } sb.append(inString, pos, inString.length()); return sb.toString(); } }
java.lang.replace
Reference Links
本文由
Yuankun Li 创作和发表,采用
BY -
NC -
SA 国际许可协议进行许可,转载请注明作者及出处。