Java中将大写字母转换为小写字母并将小写字母转换为大写字母的最快方法

Jai*_*oya 2 java performance ascii lowercase uppercase

这是关于性能的问题。我可以使用以下代码将大写转换为小写,反之亦然:

从小写到大写:

// 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 + " ");  
    } 
  } 
}
Run Code Online (Sandbox Code Playgroud)

从大写到小写:

// 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 + " ");  
    } 
  } 
}
Run Code Online (Sandbox Code Playgroud)

我知道Java提供了以下方法:.toUpperCase( ).toLowerCase( )。考虑性能,通过使用上面代码中所示的按位运算或使用.toUpperCase( )and .toLowerCase( )方法,最快的转换方法是什么?谢谢。

编辑1:请注意我如何使用十进制65503,即二进制“ 1111111111011111”。我使用的是16位,而不是8位。根据当前的答案,每个字符有多少位?

UTF-16编码的Unicode字符介于16(2个字节)和32位(4个字节)之间,尽管大多数常见字符占用16位。这是Windows内部使用的编码。

我的问题中的代码假设使用UTF-16。

Kar*_*cki 5

您的代码仅适用于 ANSII 字符。对于小写和大写之间没有明确转换的语言,例如德语\xc3\x9f(如果我错了,请纠正我,我的德语很糟糕),或者当使用多字节 UTF-8 代码点编写字母/符号时,该怎么办?正确性优先于性能,如果必须处理 UTF-8,问题就不那么简单了,如String.toLowerCase(Locale)方法中所示。

\n

  • 参数是“String”,迭代是​​在其包含的“char”上进行的,因此编码是 UTF-16,而不是 UTF-8。但你是对的,位翻转对于 Unicode 的许多 50442 字母不起作用。 (2认同)

Kay*_*man 5

是的,如果您选择通过简单的按位运算执行大小写转换,则由您编写的方法会稍快一些,而Java的方法具有更复杂的逻辑来支持Unicode字符,而不仅仅是ASCII字符集。

如果查看String.toLowerCase(),您会发现其中包含很多逻辑,因此,如果您使用的是仅需要处理大量ASCII的软件,而没有别的,您可能实际上会看到一些好处使用更直接的方法。

但是除非您编写的程序大部分时间都在转换ASCII,否则即使使用事件探查器也不会注意到任何区别(如果您正在编写此类程序,则应另谋高就) )。


Jac*_* G. 5

正如所承诺的,这里有两个 JMH 基准;一个与Character#toUpperCase您的按位方法比较Character#toLowerCase,另一个与您的其他按位方法比较。请注意,仅测试了英文字母表中的字符。

第一个基准(大写):

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

第二个基准(小写):

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

我只包含了几个不同的字母(即使所有字母都经过测试),因为它们都有相似的输出。

很明显,您的按位方法更快,主要是由于Character#toUpperCaseCharacter#toLowerCase执行逻辑检查(正如我今天早些时候在评论中提到的)。