此代码比标准String.toUpperCase()函数快3倍:
public static String toUpperString(String pString) {
if (pString != null) {
char[] retChar = pString.toCharArray();
for (int idx = 0; idx < pString.length(); idx++) {
char c = retChar[idx];
if (c >= 'a' && c <= 'z') {
retChar[idx] = (char) (c & -33);
}
}
return new String(retChar);
} else {
return null;
}
}
为什么这么快? String.toUpperCase()还做了什么其他的工作呢? 换句话说,是否存在此代码不起作用的情况?
执行2,000,000次随机长字符串(纯文本)的基准测试结果:
toUpperString(String):3514.339 ms - 约3.5秒
String.toUpperCase():9705.397 ms - 差不多10秒
**更新
我添加了“拉丁”支票并将其用作基准(对于那些不相信我的人):
public class BenchmarkUpperCase {
public static String[] randomStrings;
public static String nextRandomString() {
SecureRandom random = new SecureRandom();
return new BigInteger(500, random).toString(32);
}
public static String customToUpperString(String pString) {
if (pString != null) {
char[] retChar = pString.toCharArray();
for (int idx = 0; idx < pString.length(); idx++) {
char c = retChar[idx];
if (c >= 'a' && c <= 'z') {
retChar[idx] = (char) (c & -33);
} else if (c >= 192) { // now catering for other than latin...
retChar[idx] = Character.toUpperCase(c);
}
}
return new String(retChar);
} else {
return null;
}
}
public static void main(String... args) {
long timerStart, timePeriod = 0;
randomStrings = new String[1000];
for (int idx = 0; idx < 1000; idx++) {
randomStrings[idx] = nextRandomString();
}
String dummy = null;
for (int count = 1; count <= 5; count++) {
timerStart = System.nanoTime();
for (int idx = 0; idx < 20000000; idx++) {
dummy = randomStrings[idx % 1000].toUpperCase();
}
timePeriod = System.nanoTime() - timerStart;
System.out.println(count + " String.toUpper() : " + (timePeriod / 1000000));
}
for (int count = 1; count <= 5; count++) {
timerStart = System.nanoTime();
for (int idx = 0; idx < 20000000; idx++) {
dummy = customToUpperString(randomStrings[idx % 1000]);
}
timePeriod = System.nanoTime() - timerStart;
System.out.println(count + " customToUpperString() : " + (timePeriod / 1000000));
}
}
}
我得到了这些结果:
1 String.toUpper() : 10724
2 String.toUpper() : 10551
3 String.toUpper() : 10551
4 String.toUpper() : 10660
5 String.toUpper() : 10575
1 customToUpperString() : 6687
2 customToUpperString() : 6684
3 customToUpperString() : 6686
4 customToUpperString() : 6693
5 customToUpperString() : 6710
这仍然快约60%。
答案 0 :(得分:4)
我运行了简单的jmh基准测试来比较两个方法#toUpperString
和默认的j8 #toUpperCase
,结果&#39; s是:
Benchmark Mode Cnt Score Error Units
MyBenchmark.customToString avgt 20 3307.137 ± 81.192 ns/op
MyBenchmark.defaultToString avgt 20 3384.921 ± 75.357 ns/op
测试实施是:
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(value = 1, warmups = 1)
@Threads(1)
public class MyBenchmark {
public static String toUpperString(String pString) {
if (pString != null) {
char[] retChar = pString.toCharArray();
for (int idx = 0; idx < pString.length(); idx++) {
char c = retChar[idx];
if (c >= 'a' && c <= 'z') {
retChar[idx] = (char) (c & -33);
}
}
return new String(retChar);
} else {
return null;
}
}
private SecureRandom random = new SecureRandom();
public String nextSessionId() {
return new BigInteger(130, random).toString(32);
}
@Setup
public void init() {
}
@Benchmark
public Object customToString() {
return toUpperString(nextSessionId());
}
@Benchmark
public String defaultToString() {
return nextSessionId().toUpperCase();
}
}
根据此测试的score
,此方法不比默认值快3倍。
答案 1 :(得分:3)
检查java.lang.String
的{{3}}是有益的:
标准版本相当长,以避免在不需要时创建新字符串。这需要在字符串上进行两次传递。
标准版本使用区域设置对象对所有字符进行大小写转换。您只对大于192的字符执行此操作。虽然这可能适用于常见的区域设置,但某些区域设置(当前或将来...或自定义)可能具有适用于小于192的字符的“有趣”大小写规则好。
标准版本正在通过Unicode代码点而不是代码单元转换为大写。 (如果字符串包含代理字符,则按代码单位转换可能会破坏或给出错误的答案。)
“正确执行”的惩罚是toUppercase
的标准版本比版本 1 慢。但是如果您的版本没有,它会给出正确的答案。
请注意,由于您正在测试ASCII字符串,因此您不会遇到toUppercase
版本给出错误答案的情况。
1 - 根据您的基准......但请参阅其他答案!
答案 2 :(得分:0)
换句话说,是否存在此代码不起作用的情况?
是。即使您更新的代码也无法正常用于德语,因为它不包括'ß'的特殊情况。 此字母仅作为小写字母存在,并且在大写字母中转换为double s:
String bla = "blöße";
System.out.println(customToUpperString(bla)); // BLÖßE <- wrong
System.out.println(bla.toUpperCase(Locale.GERMANY)); // BLÖSSE <- right
我确信在其他语言中还有更多这样的特殊情况。