Convert int to String in Java (with Performance Comparison)

To convert an int (primitive integer) value into a String, we can use either String.valueOf() or Integer.toString() method. Internally, the former calls the latter, so Integer.toString() should be preferred.

This Java tutorial discusses the following techniques for converting an int to a String, and we’ll conduct a performance comparison to understand the efficiency of each method.

  • Integer.toString() [Fastest and Recommended]
  • String.valueOf()
  • String.format()
  • String template
int num = 100;

String value1 = Integer.toString( num );   // Works for Integer too
String value2 = String.valueOf( num );     // Works for Integer too

1. Using Integer.toString()

The Integer.toString(int) returns a string representing the specified int passed as a method argument. By default, the argument is converted to signed decimal (radix 10) in string format.

String toString(int i);

For example, we can pass any positive or negative value and get its value in a string.

Assertions.assertEquals("0", Integer.toString(0));
Assertions.assertEquals("40", Integer.toString(40));
Assertions.assertEquals("-40", Integer.toString(-40));

1.1. No Exception Thrown

Be careful to not exceed the maximum or minimum value of the int type which is 2147483647 and -2147483648. We will get unexpected results in case we cross the upper or lower bounds.

Assertions.assertEquals("2147483647", Integer.toString(Integer.MAX_VALUE));
Assertions.assertEquals("-2147483648", Integer.toString(Integer.MAX_VALUE + 1));

Assertions.assertEquals("-2147483648", Integer.toString(Integer.MIN_VALUE));
Assertions.assertEquals("2147483647", Integer.toString(Integer.MIN_VALUE - 1));

1.2. Binary, Octal and Hex Strings

Note that we can use several other inbuilt methods if we want to get the String value in other base values. The default base is 10.

  • Integer.toBinaryString(): returns string representation in base 2.
  • Integer.toOctalString(): returns in base 8.
  • Integer.toHexString(): returns in base 16.
Assertions.assertEquals("101000", Integer.toBinaryString(40));
Assertions.assertEquals("50", Integer.toOctalString(40));
Assertions.assertEquals("28", Integer.toHexString(40));

2. Using String.valueOf()

The String.valueOf(int i) returns the string representation of the int argument. It internally invokes the Integer.toString() so the the representations are always the same.

String valueOf(int i);

Let us test out the int values again as in the previous section.

Assertions.assertEquals("0", String.valueOf(0));
Assertions.assertEquals("40", String.valueOf(40));
Assertions.assertEquals("-40", String.valueOf(-40));

Assertions.assertEquals("2147483647", String.valueOf(Integer.MAX_VALUE));
Assertions.assertEquals("-2147483648", String.valueOf(Integer.MAX_VALUE + 1));

Assertions.assertEquals("-2147483648", String.valueOf(Integer.MIN_VALUE));
Assertions.assertEquals("2147483647", String.valueOf(Integer.MIN_VALUE - 1));

3. Performance Comparison

In this section, we will use JMH to test the performance of both discussed methods as well as a few other unconventional approaches as listed below:

  • Integer.toString()
  • String.valueOf()
  • String.format()
  • STR.”\{i}” i.e. String template or string concatenation

These methods also work for a boxed Integer object. Since boxing/unboxing are costly operations, we strive to avoid them unless they are really necessary. But, you never know when an un-boxing operation may sneak “behind the scene” and impact the performance of the application.

We have written the JMH class to benchmark all these methods (in Java 21) as follows:

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@State(Scope.Thread)
public class IntToStringBenchmark {

  private ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

  @Benchmark
  @BenchmarkMode(Mode.AverageTime)
  @OutputTimeUnit(TimeUnit.MICROSECONDS)
  public void methodIntegerToString(Blackhole blackhole) {

    int i =  threadLocalRandom.nextInt(1_00_000, 9_99_999);
    String s = Integer.toString(i);
    blackhole.consume(s);
  }


  @Benchmark
  @BenchmarkMode(Mode.AverageTime)
  @OutputTimeUnit(TimeUnit.MICROSECONDS)
  public void methodStringValueOf(Blackhole blackhole) {

    int i =  threadLocalRandom.nextInt(1_00_000, 9_99_999);
    String s = String.valueOf(i);
    blackhole.consume(s);
  }

  @Benchmark
  @BenchmarkMode(Mode.AverageTime)
  @OutputTimeUnit(TimeUnit.MICROSECONDS)
  public void methodStringFormat(Blackhole blackhole) {

    int i =  threadLocalRandom.nextInt(1_00_000, 9_99_999);
    String s = String.format("%d", i);
    blackhole.consume(s);
  }

  @Benchmark
  @BenchmarkMode(Mode.AverageTime)
  @OutputTimeUnit(TimeUnit.MICROSECONDS)
  public void methodStringTemplate(Blackhole blackhole) {

    int i =  threadLocalRandom.nextInt(1_00_000, 9_99_999);
    String s = STR."\{i}";
    blackhole.consume(s);
  }

  public static void main(String[] args) throws Exception {

    Options opt = new OptionsBuilder()
        .include(IntToStringBenchmark.class.getSimpleName())
        .forks(1)
        .build();

    new Runner(opt).run();
  }
}

The following is the result of the performance tests:

Benchmark MethodSyntax UsedPerformance (Avg Time per Operation)
methodIntegerToStringInteger.toString(int)0.012
methodStringValueOfString.valueOf(int)0.016
methodStringTemplateSTR.”\{i}”0.019
methodStringFormatString.format(“%d”, int)0.0143

I also tried to peek into the bytecode generated for these statements to understand why they perform they are:

//******** methodIntegerToString **********/

13: invokestatic  #25      // Method java/lang/Integer.toString:(I)Ljava/lang/String;

//******** methodStringValueOf **********/

13: invokestatic  #45      // Method java/lang/String.valueOf:(I)Ljava/lang/String;

//******** methodStringFormat **********/

12: ldc           #49     // String %d
14: iconst_1
15: anewarray     #2      // class java/lang/Object
18: dup
19: iconst_0
20: iload_2
21: invokestatic  #37     // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
24: aastore
25: invokestatic  #51     // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

//******** methodStringTemplate **********/

13: invokedynamic #55,  0  // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;

There are two clear conclusions that we can extract from the results:

  • Using the String.format() is the slowest and it should be avoided for int and Integer.
  • The String.valueOf() performs almost equivalent to Integer.toString(). That is oblivious once we realize that String.valueOf() internally invokes Integer.toString().
  • Surprisingly, the string template approach works also a lot faster. Perhaps it utilizes the other performance optimizations done for String concatenation already.

The results of these benchmarks were obtained on an 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz machine with Windows 11 (16GB RAM). Please feel free to test it on different configurations since the JMH results are dependent on the machines too.

4. Conclusion

In Java, converting an int value to a String is not a difficult task but knowing which method may save us a few CPU cycles is worth knowing. In this case, we should always prefer the Integer.toString() to int to String conversions.

Happy Learning !!

Source Code on Github

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode