在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%的投稿人