25

While writing unit tests for a function returning boolean that takes two Strings, and I needed to test every character of the alphabet ('a'-'z') in sequence as one of the parameters, one-by-one, so I wrote this to do that:

for(char c = 'a'; c <= 'z'; c++)
{
    assertTrue(MyClass.MyFunction(testSubject, new String(c));
} 

I would have thought this was permissible, but it wasn't, so I just did it like this instead:

for(char c = 'a'; c <= 'z'; c++)
{
    assertTrue(MyClass.MyFunction(testSubject, ((Character) c).toString());
} 

Is this a reliable method to convert a char to a String in Java? Is it the preferred way? I don't know a whole lot about Java so would like some clarification on this.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • 2
    Not directly to your question, but I would `IntStream.range(0, 26).mapToObj(i -> Character.toString((char) ('a' + i))).forEach(x -> assertTrue(MyClass.MyFunction(testSubject, x)));` – Elliott Frisch Apr 28 '20 at 00:42
  • 4
    @ElliottFrisch but why? Streams are unnecessary here, but even if you insist on using streams for every loop, why not at least use `IntStream.rangeClosed('a', 'z')`? – PhilipRoman Apr 28 '20 at 09:43
  • 2
    There is no single 'correct' way. There are probably at least five ways to do this: which you choose depends on fashion as much as scientific fact. Most of the time it simply doesn't matter, and a test program is certainly one of those cases. – user207421 Apr 28 '20 at 10:17
  • @PhilipRoman Because it is there (Edmund Hillary). Because I can. Because we want to (Billie Piper, I think). That's a cool approach too. – Elliott Frisch Apr 28 '20 at 18:55
  • _I would have thought this was permissible_ You thought it was permissible to invoke a `String` constructor that doesn't exist? Correct me if I'm wrong, but as far as I am aware, there is not constructor in class [`String`](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/String.html) that takes a single `char` argument. Note that `char` is not the same as `char[]`. – Abra May 02 '20 at 06:41

1 Answers1

36

The shortest solution:

char c = 'a';
String s = "" + c;

The cleanest (and probably most efficient1) solutions:

char c = 'a';

String s1 = String.valueOf(c);
// or
String s2 = Character.toString(c);

Compared to your approach, the above prevents the overhead of having to box the primitive into a Character object.


1 The slight inefficiency of the string concatenation in the first approach might be optimized away by the compiler or runtime, so one (if one were so inclined) would really have to run a micro-benchmark to determine actual performance. Micro-optimizations like this are rarely worth the effort, and relying on concatenation to force string conversion just doesn't look very nice.

Robby Cornelissen
  • 91,784
  • 22
  • 134
  • 156
  • 8
    Last time I looked, Sun's `javac` compiler automatically transforms `String s = "" + c;` into `String s = String.valueOf(c);`, so the performance would be the same. – Neil Apr 28 '20 at 14:00
  • 4
    @Neil Whew! I was beginning to think that the type of person I wrote that footnote for no longer existed on Stack Overflow :) – Robby Cornelissen Apr 28 '20 at 15:08
  • @Neil: Weird! For me both javac 1.8.0_101 and Eclipse compiler emits code for creating the `StringBuilder` and calling `append`. Javac 10.0.1 emits an invoke-dynamic instruction. Maybe they trusted the JIT more in later years, instead of making compile time optimizations. – Lii May 11 '20 at 10:51