在Java中将大写转换为小写和小写转换为大写的最快方法
这是一个关于性能的问题。我可以使用以下代码将大写字母转换为小写字母,反之亦然: 从小写到大写:在Java中将大写转换为小写和小写转换为大写的最快方法,java,performance,ascii,uppercase,lowercase,Java,Performance,Ascii,Uppercase,Lowercase,这是一个关于性能的问题。我可以使用以下代码将大写字母转换为小写字母,反之亦然: 从小写到大写: // Uppercase letters. class UpperCase { public static void main(String args[]) { char ch; for (int i = 0; i < 10; i++) { ch = (char) ('a' + i); System.out.print(ch);
// Uppercase letters.
class UpperCase {
public static void main(String args[]) {
char ch;
for (int i = 0; i < 10; i++) {
ch = (char) ('a' + i);
System.out.print(ch);
// This statement turns off the 6th bit.
ch = (char) ((int) ch & 65503); // ch is now uppercase
System.out.print(ch + " ");
}
}
}
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(3)
public class Test {
@Param({"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"})
public char c;
@Benchmark
public char toUpperCaseNormal() {
return Character.toUpperCase(c);
}
@Benchmark
public char toUpperCaseBitwise() {
return (char) (c & 65503);
}
}
//大写字母。
类大写字母{
公共静态void main(字符串args[]){
char ch;
对于(int i=0;i<10;i++){
ch=(char)('a'+i);
系统输出打印(ch);
//此语句关闭第6位。
ch=(char)((int)ch&65503);//ch现在是大写
系统输出打印(ch+“”);
}
}
}
从大写到小写:
// Lowercase letters.
class LowerCase {
public static void main(String args[]) {
char ch;
for (int i = 0; i < 10; i++) {
ch = (char) ('A' + i);
System.out.print(ch);
ch = (char) ((int) ch | 32); // ch is now lowercase
System.out.print(ch + " ");
}
}
}
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(3)
public class Test {
@Param({"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"})
public char c;
@Benchmark
public char toLowerCaseNormal() {
return Character.toUpperCase(c);
}
@Benchmark
public char toLowerCaseBitwise() {
return (char) (c | 32);
}
}
//小写字母。
类小写{
公共静态void main(字符串args[]){
char ch;
对于(int i=0;i<10;i++){
ch=(char)('A'+i);
系统输出打印(ch);
ch=(char)((int)ch | 32);//ch现在是小写的
系统输出打印(ch+“”);
}
}
}
我知道Java提供了以下方法:.toUpperCase()
和.toLowerCase()
。考虑到性能,通过使用我在上面代码中显示的按位操作,或者使用.toUpperCase()
和.toLowerCase()
方法,最快的转换方式是什么?多谢各位
编辑1:注意我是如何使用十进制65503的,它是二进制的1111111111011111. 我用的是16位,不是8位。根据目前投票率较高的答案:
UTF-16编码中的Unicode字符介于16位(2字节)和32位(4字节)之间,尽管大多数常用字符采用16位。这是Windows内部使用的编码
我问题中的代码假设为UTF-16。只需遵循提供的方法
.toLowerCase()
和.toUpperCase()
。添加两个单独的类来执行java.lang提供的两个方法是一种过分的做法,它会降低程序的速度(只有很小的余量)。您的代码只适用于ANSII字符。对于小写和大写之间不存在明确转换的语言,例如德语ß
(如果我错了,请纠正我,我的德语很糟糕),或者使用多字节UTF-8码点编写字母/符号时,该怎么办。正确性先于性能,如果必须处理UTF-8,问题就不那么简单了,这在String.toLowerCase(Locale)
方法中很明显。是的,如果您选择使用简单的按位操作执行大小写转换,您编写的方法会稍微快一点,而Java的方法有更复杂的逻辑来支持unicode字符,而不仅仅是ASCII字符集
如果你看一下,你会注意到其中有很多逻辑,所以如果你使用的软件只需要处理大量的ASCII,而不需要其他任何东西,你可能会发现使用更直接的方法会带来一些好处
但是除非您编写的程序大部分时间都在转换ASCII,否则即使使用探查器,您也不会注意到任何差异(如果您正在编写这种程序……您应该另找工作)。如承诺的那样,这里有两个JMH基准;一个将
Character#toupercase
与按位方法进行比较,另一个将Character#toLowerCase
与其他按位方法进行比较。请注意,仅测试英语字母表中的字符
第一个基准(大写):
输出:
Benchmark (c) Mode Cnt Score Error Units
Test.toUpperCaseNormal a avgt 30 2.447 ± 0.028 ns/op
Test.toUpperCaseNormal b avgt 30 2.438 ± 0.035 ns/op
Test.toUpperCaseNormal c avgt 30 2.506 ± 0.083 ns/op
Test.toUpperCaseNormal d avgt 30 2.411 ± 0.010 ns/op
Test.toUpperCaseNormal e avgt 30 2.417 ± 0.010 ns/op
Test.toUpperCaseNormal f avgt 30 2.412 ± 0.005 ns/op
Test.toUpperCaseNormal g avgt 30 2.410 ± 0.004 ns/op
Test.toUpperCaseBitwise a avgt 30 1.758 ± 0.007 ns/op
Test.toUpperCaseBitwise b avgt 30 1.789 ± 0.032 ns/op
Test.toUpperCaseBitwise c avgt 30 1.763 ± 0.005 ns/op
Test.toUpperCaseBitwise d avgt 30 1.763 ± 0.012 ns/op
Test.toUpperCaseBitwise e avgt 30 1.757 ± 0.003 ns/op
Test.toUpperCaseBitwise f avgt 30 1.755 ± 0.003 ns/op
Test.toUpperCaseBitwise g avgt 30 1.759 ± 0.003 ns/op
Benchmark (c) Mode Cnt Score Error Units
Test.toLowerCaseNormal A avgt 30 2.084 ± 0.007 ns/op
Test.toLowerCaseNormal B avgt 30 2.079 ± 0.006 ns/op
Test.toLowerCaseNormal C avgt 30 2.081 ± 0.005 ns/op
Test.toLowerCaseNormal D avgt 30 2.083 ± 0.010 ns/op
Test.toLowerCaseNormal E avgt 30 2.080 ± 0.005 ns/op
Test.toLowerCaseNormal F avgt 30 2.091 ± 0.020 ns/op
Test.toLowerCaseNormal G avgt 30 2.116 ± 0.061 ns/op
Test.toLowerCaseBitwise A avgt 30 1.708 ± 0.006 ns/op
Test.toLowerCaseBitwise B avgt 30 1.705 ± 0.018 ns/op
Test.toLowerCaseBitwise C avgt 30 1.721 ± 0.022 ns/op
Test.toLowerCaseBitwise D avgt 30 1.718 ± 0.010 ns/op
Test.toLowerCaseBitwise E avgt 30 1.706 ± 0.009 ns/op
Test.toLowerCaseBitwise F avgt 30 1.704 ± 0.004 ns/op
Test.toLowerCaseBitwise G avgt 30 1.711 ± 0.007 ns/op
第二个基准(小写):
输出:
Benchmark (c) Mode Cnt Score Error Units
Test.toUpperCaseNormal a avgt 30 2.447 ± 0.028 ns/op
Test.toUpperCaseNormal b avgt 30 2.438 ± 0.035 ns/op
Test.toUpperCaseNormal c avgt 30 2.506 ± 0.083 ns/op
Test.toUpperCaseNormal d avgt 30 2.411 ± 0.010 ns/op
Test.toUpperCaseNormal e avgt 30 2.417 ± 0.010 ns/op
Test.toUpperCaseNormal f avgt 30 2.412 ± 0.005 ns/op
Test.toUpperCaseNormal g avgt 30 2.410 ± 0.004 ns/op
Test.toUpperCaseBitwise a avgt 30 1.758 ± 0.007 ns/op
Test.toUpperCaseBitwise b avgt 30 1.789 ± 0.032 ns/op
Test.toUpperCaseBitwise c avgt 30 1.763 ± 0.005 ns/op
Test.toUpperCaseBitwise d avgt 30 1.763 ± 0.012 ns/op
Test.toUpperCaseBitwise e avgt 30 1.757 ± 0.003 ns/op
Test.toUpperCaseBitwise f avgt 30 1.755 ± 0.003 ns/op
Test.toUpperCaseBitwise g avgt 30 1.759 ± 0.003 ns/op
Benchmark (c) Mode Cnt Score Error Units
Test.toLowerCaseNormal A avgt 30 2.084 ± 0.007 ns/op
Test.toLowerCaseNormal B avgt 30 2.079 ± 0.006 ns/op
Test.toLowerCaseNormal C avgt 30 2.081 ± 0.005 ns/op
Test.toLowerCaseNormal D avgt 30 2.083 ± 0.010 ns/op
Test.toLowerCaseNormal E avgt 30 2.080 ± 0.005 ns/op
Test.toLowerCaseNormal F avgt 30 2.091 ± 0.020 ns/op
Test.toLowerCaseNormal G avgt 30 2.116 ± 0.061 ns/op
Test.toLowerCaseBitwise A avgt 30 1.708 ± 0.006 ns/op
Test.toLowerCaseBitwise B avgt 30 1.705 ± 0.018 ns/op
Test.toLowerCaseBitwise C avgt 30 1.721 ± 0.022 ns/op
Test.toLowerCaseBitwise D avgt 30 1.718 ± 0.010 ns/op
Test.toLowerCaseBitwise E avgt 30 1.706 ± 0.009 ns/op
Test.toLowerCaseBitwise F avgt 30 1.704 ± 0.004 ns/op
Test.toLowerCaseBitwise G avgt 30 1.711 ± 0.007 ns/op
我只包含了几个不同的字母(尽管所有字母都经过测试),因为它们都有相似的输出
很明显,您的按位方法更快,主要是因为
Character#toUpperCase
和Character#toLowerCase
执行逻辑检查(正如我今天早些时候在评论中提到的).为什么要关心像案例转换这样无关紧要的事情呢?如果到那时还没有,我将在几个小时内与JMH一起对此进行基准测试。我怀疑按位运算符的性能会更好,因为Character#toLowerCase
和Character#toUpperCase
都会对参数执行大量检查。无论您使用什么,都应该比toUpperCase()/toLowerCase()
@JaimeMontoya更快,但您无法证明微优化是正确的。你在浪费时间做一些无关紧要的事情。或者你真的通过分析你的软件将案例转换识别为性能热点吗?@JacobG。我怀疑按位运算符的速度更快,但我试图确定。参数是String
,迭代在其包含的char
s上,因此编码是UTF-16,而不是UTF-8。但是你是对的,位翻转对许多Unicode的50442个字母都不起作用。在我在问题中使用的代码中,编码是UTF-16以支持Unicode。注意我在代码中是如何使用值65503 decimal的,它是二进制的:1111111111011111. 这是16位,而不是8位,这意味着Unicode的UTF-16。在我看来,按位版本应该进行某种检查,以查看字符是否确实需要处理(我指的是类似于if的内容)(c>='a'&&c我正在运行一个非常敏感的应用程序,逐位操作给了我一个可测量的性能提升。toLowerCase@JohnD你能在Jacob G的答案中运行JMH基准测试,看看结果是否相似吗?性能提升是否是由于环境差异(JDK等)造成的,它们可能很有趣,所以你可以将它们作为另一个答案发布。TBH我在leetcode上进行编程竞赛,32位运算比String.toLowerCase少7毫秒。leetcode有排行榜,所以我认为它们是原因之一,但无论是哪种情况,这一变化都让我在这项任务中仅击败了46%的解决方案承诺击败超过98%的投稿人