The accepted answer already explains how to do it. I would like to add some nuance about when and when not to do it. It wouldn't be possible to explain this with examples in a comment. I suspect many might find this question in the future for the same reasons as in the OP question.
I think that refactoring to a StringBuilder in cases like in the question is done for the wrong reasons. It's a common case of cargo cult programming.
There is a common misconception that a string expression like this "It is " + LocalTime.now() + " o'clock";
causes a string concatenation for each "+" and thus O(n^2) time and space complexity.
However, Java uses a StringBuilder under the hood if all of the segments are known at compile time, even when some of them are calculated or formatted dynamically, like LocalTime.now()
in this example. The fact that it implicitly uses a StringBuilder is actually an uninteresting implementation detail; the important thing is that it can determine the total length of the string as the sum of the individual string lengths, then allocate a single string and fill it once.
So when should a StringBuilder be used? If you pass a string builder to methods, which then append to it, or if you append conditionally (if (example) { stringBuilder.append("...") }
), especially in a loop.
In your particular example, there is no performance penalty for using normal concatenation syntax vs. a StringBuilder, so there is no trade-off between readability and performance. I would argue that with some better formatting for the original version, your string will be much easier to read than when using a string builder. It is kind of subjective, but in my professional circles this generally tends to be considered to be true. I will add both examples next to each other and let you judge. The important point is to know why we make the decision.
Original code
this.path = DESTINY + deploy.name() + FILE_SEPARATOR + delivery.getSystem().getCode()
+ FILE_SEPARATOR + delivery.getName() + FILE_SEPARATOR + delivery.getEnviroment().getName();
With StringBuilder
StringBuilder tmpPath = new StringBuilder();
tmpPath.append(DESTINY);
tmpPath.append(deploy.name());
tmpPath.append(FILE_SEPARATOR);
tmpPath.append(delivery.getSystem().getCode());
tmpPath.append(FILE_SEPARATOR);
tmpPath.append(delivery.getName());
tmpPath.append(FILE_SEPARATOR);
tmpPath.append(delivery.getEnviroment().getName());
this.path = tmpPath.toString();
Original code with improved formatting (recommended)
this.path = DESTINY + deploy.name() + FILE_SEPARATOR
+ delivery.getSystem().getCode() + FILE_SEPARATOR
+ delivery.getName() + FILE_SEPARATOR
+ delivery.getEnviroment().getName();
Another option (recommended)
I recommend this option when joining string segments with a separator.
this.path = String.join(FILE_SEPARATOR,
DESTINY + deploy.name(),
delivery.getSystem().getCode(),
delivery.getName(),
delivery.getEnviroment().getName());
StringBuilder
after the refactor is IntelliJ recommending to replace the StringBuilder with String concatenation? – Particularism