0

I am looking for arguments that would allow me to show the light that in Java

int myInt = 1;
...
String s = "" + myInt;

is indeed a perfectly correct and compiling implementation of String.valueOf(myInt) but that doing that "is not the canonical way it's done in Java".

"it looks nicer" is the argument that I am getting, and "I expect the compiler to deal with that".

I have tried sending a link to https://godbolt.org/ (Compiler Explorer) which shows the generated JVM instructions; arguing about "canonical ways" or "least surprise" or "implementation patterns" or "maintainability" will not be effective.

I am lost - any suggestions?

  • For the record - this is really about *just* converting a plain integer value to String. If this was in a broader context, going through formatters would clearly be better, and, as far as I can tell, this is also understood. – Stefan Hoffmeister Oct 15 '21 at 06:34
  • 2
    Who says it's "not the way that it's done"? – Roddy of the Frozen Peas Oct 15 '21 at 07:04
  • The *crudest* and most technical argument is: `"" + myInt` results in demonstrably suboptimal code generation for the JVM (and JIT will not be able to repair that) "not the way that it's done"- to be honest, I have never seen it done in code that I deem of high quality, presumably because of the technical argument, see above. – Stefan Hoffmeister Oct 15 '21 at 07:15
  • 1
    "results in demonstrably suboptimal code generation for the JVM" please demonstrate that. It results in _different_ code generation, for sure; it's the assertion that it's practically less good that I'm questioning. – Andy Turner Oct 15 '21 at 08:29
  • Whilst you are asking about converting 1 int to a string, consider how your rule should extend to, say, `"" + a + b`: would you write that as `String.valueOf(a) + String.valueOf(b)` (verbose); `String.valueOf(a) + b` (inconsistent); `a + "" + b` (more clear that it's string concatenation, but a bit odd that would be allowed, but not the tokens in a different order); `String.format("%d%d", a, b)` (slow, because of having to parse the format string each time). – Andy Turner Oct 15 '21 at 10:23

4 Answers4

4

In matters of style (and this is a matter of style; run a micro-benchmark to prove and quantify run-time performance differences) I would follow these rules:

  1. if your project has a style guide that recommends one particular choice, follow the style guide
  2. if it has existing code that consistently follows one choice, follow that choice
  3. if neither applies, make a choice and stick to it

The source for the JDK is freely available. In Java 8, I count 276 files with one or more occurrences of "" + (and in the ones that I looked at, numbers often followed). Of course, there are >3k files with calls to .toString, and I have not looked at .valueOf at all, so this is hardly conclusive. Therefore, use of "" + number-to-string conversion does not appear to be uncommon or frowned upon in well-written Java code.

Not that good Java developers would concatenate strings inside loops; a frequent use seems to be generating error messages for exceptions.

Oracle's ancient Java style guide, and the more recent ones by Google and Spring do not appear to have a say on the matter. Therefore, I feel that there is no right answer, and if coding together on a project, and you care enough about this, you should apply Rule 3: iron out a compromise, document it in your project's style guide, and stick to it.

On a personal note, I find "" + o easier to read than many of the alternatives, as syntactic sugar for a call to toString() that works regardless of the type of o (and even when o is null).


I actually tried this out using caliper on JDK 11, and results show minimal run-time difference, and no memory or object-count difference, when performing 1k int-to-string conversions by these 3 methods:

 t (ms)   method

 12,30    "" + j
 12,57    Integer.toString(j)
 12.58    String.valueOf(j)

Code to reproduce:

package org.example;

import com.google.caliper.BeforeExperiment;
import com.google.caliper.Benchmark;
import com.google.caliper.Param;
import com.google.caliper.runner.CaliperMain;

public class Main {

    @Param({"10", "100", "1000"})
    int size;

    private String[] output;

    @BeforeExperiment
    void setUp() {
        output = new String[size];
    }

    @Benchmark void quote(int reps) {
        for (int i = 0; i < reps; i++) {
            for (int j = 0; j < size; j++) {
                output[j] = "" + j;
            }
        }
    }

    @Benchmark void toString(int reps) {
        for (int i = 0; i < reps; i++) {
            for (int j = 0; j < size; j++) {
                output[j] = Integer.toString(j);
            }
        }
    }

    @Benchmark void valueOf(int reps) {
        for (int i = 0; i < reps; i++) {
            for (int j = 0; j < size; j++) {
                output[j] = String.valueOf(j);
            }
        }
    }

    public static void main(String[] args) {
        CaliperMain.main(Main.class, args);
    }
}
tucuxi
  • 17,561
  • 2
  • 43
  • 74
  • You should perhaps consider contributing the data from this answer to https://stackoverflow.com/questions/653990/what-is-the-most-efficient-way-to-convert-an-int-to-a-string: the benchmarks in the top answer are from 2009, and so are very different from yours. – Andy Turner Oct 15 '21 at 10:14
  • @AndyTurner good suggestion - my results are very different from theirs, but then again, they did not use an actual microbenchmark, and there are big pitfalls from Not Doing It Right (tm) – tucuxi Oct 15 '21 at 10:38
2

In it current form, it is OK, but add a little change

    int myInt = 1;
    int myInt2 = 2;
    String s = "" + myInt + myInt2;

    System.out.println(s);

vs.

    System.out.println(String.format("%d", myInt + myInt2));

is this what you are asking

Scary Wombat
  • 44,617
  • 6
  • 35
  • 64
  • Not sure whether this question is a really good fit for this place (isnt it more code review, SE practices) ... but your answer is great, for sure! – GhostCat Oct 15 '21 at 06:41
  • I would like to point out that my question was about mentoring a person and how to specifically address the case where a single integer was converted to a string. In a comment to my question I added the note that in broader contexts formatters would apply, but that this specifically was not the question. – Stefan Hoffmeister Oct 15 '21 at 07:18
2

Yould show the evaluation happening.

String s = String.valueOf(myInt);      // 1

String s = "" + myInt;                 // 1
String s = "" + String.valueOf(myInt); // 2
String s = result of plus;             // 3
  • "" + int is an extra artifact.

  • One would also not write 0.0 + n instead of (double) nto convert int n to a double.

  • The compiler is allowed to generate dumb java byte code:

      public class IntToString {
          public String intToStringConverting(int n) {
              return String.valueOf(n);
          }
          public String intToStringWithPlus(int n) {
              return "" + n;
          }
      }
    

    javap -c IntToString.class

    public java.lang.String intToStringConverting(int);
      Code:
         0: iload_1
         1: invokestatic  #7 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
         4: areturn
    
    public java.lang.String intToStringWithPlus(int);
      Code:
         0: iload_1
         1: invokedynamic #13,  0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
         6: areturn
    

As one sees extra code, first calling makeConcatWithConstants.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • "The compiler is allowed to generate dumb java byte code" but is this bytecode practically worse? My experiments (rerunning the method described in https://stackoverflow.com/a/654031/3788176 on a much-more-recent Java version) show that `"" + n` actually runs faster (with the standard caveats about "this is not how you write a correct microbenchmark). – Andy Turner Oct 15 '21 at 09:11
  • The `"" + ` is definitely worse when it comes to the generated code: It is longer. From a real invocation point of view, the JIT engine might introduce optimizations which fold everything down to a simple invocation of Integer.toString(), which is an intrinsic - but that adds load to the JITer. – Stefan Hoffmeister Oct 15 '21 at 09:19
  • @AndyTurner yes, in my first edit I formulated it a bit stronger. So you do not seem to agree with the teacher that straight coded is better. – Joop Eggen Oct 15 '21 at 09:19
  • But the real point is: Why concatenate a string and an integer if the goal is simply "convert this integer to string" - the mentoring aspect. – Stefan Hoffmeister Oct 15 '21 at 09:20
  • @JoopEggen I do not agree: I think either is acceptable. – Andy Turner Oct 15 '21 at 09:21
  • @StefanHoffmeister stylistic and pedagogical and even mental I agree with you fully. Unfortunately compilers are the first form of software more intelligent than us. – Joop Eggen Oct 15 '21 at 09:21
1

You may use the form, according to the context. In my experience, I use String.valueOf() and Integer.toString(). I think the implementation is similar, but I like the second one. Using String.format, it's a bit slow because you must parse the expression.

int myInt = 1;
...
String s1 = String.format("%d", myInt);
String s2 = String.valueOf(myInt);
String s3 = Integer.toString(myInt);  // I use this
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
hardyx
  • 31
  • 4