Преобразование int в String в Java (со сравнением производительности)

Чтобы преобразовать значение int(примитивное целое) в String, мы можем использовать метод String.valueOf() или Integer.toString(). Внутренне первый вызывает последний, поэтому Integer.toString() следует предпочесть.

В этом руководстве по Java рассматриваются следующие методы преобразования int в String, а также мы проведем сравнение производительности, чтобы понять эффективность каждого метода.

  • Integer.toString() [Самый быстрый и рекомендуемый]
  • Строка.valueOf()
  • Формат строки()
  • Шаблон строки
int num = 100;String value1 = Integer.toString( num ); // Works for Integer tooString value2 = String.valueOf( num ); // Works for Integer too

1. Использование Integer.toString()

Integer.toString(int) возвращает строку, представляющую указанный int, переданный как аргумент метода. По умолчанию аргумент преобразуется в знаковую десятичную систему счисления(основание 10) в строковом формате.

String toString(int i);

Например, мы можем передать любое положительное или отрицательное значение и получить его значение в строке.

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

1.1 Исключение не выдано

Будьте осторожны, чтобы не превысить максимальное или минимальное значение типа int, которое равно 2147483647 и -2147483648. Мы получим неожиданные результаты, если пересечем верхнюю или нижнюю границы.

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 Двоичные, восьмеричные и шестнадцатеричные строки

Обратите внимание, что мы можем использовать несколько других встроенных методов, если мы хотим получить значение String в других базовых значениях. База по умолчанию — 10.

  • Integer.toBinaryString(): возвращает строковое представление в системе счисления с основанием 2.
  • Integer.toOctalString(): возвращает число в системе счисления с основанием 8.
  • Integer.toHexString(): возвращает число в системе счисления с основанием 16.
Assertions.assertEquals("101000", Integer.toBinaryString(40));Assertions.assertEquals("50", Integer.toOctalString(40));Assertions.assertEquals("28", Integer.toHexString(40));

2. Использование String.valueOf()

String.valueOf(int i) возвращает строковое представление аргумента int. Он внутренне вызывает Integer.toString(), поэтому представления всегда одинаковы.

String valueOf(int i);

Давайте снова проверим значения int, как в предыдущем разделе.

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. Сравнение производительности

В этом разделе мы будем использовать JMH для проверки производительности обоих обсуждаемых методов, а также нескольких других нетрадиционных подходов, перечисленных ниже:

  • Целое.toString()
  • Строка.valueOf()
  • Формат строки()
  • STR.”\{i}” т.е. шаблон строки или конкатенация строк

Эти методы также работают для упакованного объекта Integer. Поскольку упаковка/распаковка являются дорогостоящими операциями, мы стараемся избегать их, если только они действительно не необходимы. Но никогда не знаешь, когда операция распаковки может проскользнуть «за кулисы» и повлиять на производительность приложения.

Мы написали класс JMH для тестирования всех этих методов(в Java 21) следующим образом:

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();}}

Ниже приведены результаты испытаний производительности:

Метод сравнительного анализа Используемый синтаксис Производительность(среднее время на операцию)
методIntegerToString Целое.toString(целое) 0,012
methodStringValueOf Строка.valueOf(целое) 0,016
методStringTemplate СТР.”\{i}” 0,019
методStringFormat Строка.формат(«%d», целое) 0,0143

Я также попытался заглянуть в байт-код, сгенерированный для этих операторов, чтобы понять, почему они работают. Вот они:

//******** 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 %d14: iconst_115: anewarray #2 // class java/lang/Object18: dup19: iconst_020: iload_221: invokestatic #37 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;24: aastore25: 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;

Из полученных результатов можно сделать два четких вывода:

  • Использование String.format() является самым медленным и его следует избегать для int и Integer.
  • String.valueOf() выполняет почти эквивалент Integer.toString(). Это становится очевидным, когда мы понимаем, что String.valueOf() внутренне вызывает Integer.toString().
  • Удивительно, но подход с шаблоном строки также работает намного быстрее. Возможно, он использует другие оптимизации производительности, уже сделанные для конкатенации строк.

Результаты этих тестов были получены на машине Intel(R) Core(TM) i5-1135G7 11-го поколения @ 2.40GHz с Windows 11(16GB RAM). Пожалуйста, не стесняйтесь тестировать его на разных конфигурациях, так как результаты JMH также зависят от машин.

4. Заключение

В Java преобразование значения int в String не является сложной задачей, но стоит знать, какой метод может сэкономить нам несколько циклов ЦП. В этом случае мы всегда должны предпочитать Integer.toString() преобразованиям int в String.

Исходный код на Github

Прокрутить вверх