Чтобы преобразовать значение 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.