String templates

Rob Ross rob.ross at gmail.com
Fri Jul 25 02:16:05 UTC 2025


Hello list.

First, I welcome suggestions and feedback on what kind of information is
useful to contribute to the topic of string templates in Java.

I have been developing in Python for about the last two years, but am now
starting a new Java project for the first time in a while. And even though
Python is full of cool features that would be nice to have in Java, I
understand that just because a feature is cool in one language, "coolness"
is not the only consideration in deciding  whether or not to adopt it in
another language.

I just want to give my personal experience in string handling in Python,
specifically "f-strings" or  "formatted string literals". These are string
literals but they can capture values of variables and methods defined in
the current scope. You prefix the string literal with the letter 'f' (for
format). E.g.,

num_hamburgers = 12
print( f"I have eaten {num_hamburgers} today at {time.now}.")

As with printf() and similar string display methods, there are a plethora
of ways to format each replacement field. This isn't a live template - the
replacement fields capture the value at the point they are defined in the
runtime and thereafter have the same string value.

You can also store the template in a regular string and manually call a
format method on it as your data changes as you can in Java. E.g.,

template: str = "Hello {name}, it's now {time} o'clock"
name: str = "Rob"
time: int = 12
print("template: " + template)
print("formated: " + template.format(name=name, time=time))
print("f-string: " + f"Hello {name}, it's now {time} o'clock")

# output:
# template: Hello {name}, it's now {time} o'clock
# formated: Hello Rob, it's now 12 o'clock
# f-string: Hello Rob, it's now 12 o'clock


Using format() behaves essentially identical to what Java has. But the
simplicity of the f-string for capturing state really does increase my
productivity in a meaningful way.

In my last project I used f-strings for two primary use cases.
1. Debugging information during development
2. Formal representation of an object's state in a "toString()" context.

I use the first case far more often. And yes I know how to use a debugger.
:) I have just found that in many (most) cases, a few strategic println()
or logger.info() statements are perfectly adequate for the task. These have
a short lifecycle, sometimes existing only for the 5 minutes of debugging
to identify a problem, or perhaps a little longer as scaffolding until my
code solidifies and has the proper exceptions and logging handling in
place. And for these cases, which occur every day in my life, the f-string
format is much more helpful and less error prone than the current String
format() method. The problem is that it is very easy to have a mismatch of
arguments and format specifiers in Java, which results in me having to
first debug my debugging! And reading such expressions also imposes a
cognitive load that I do not feel with f-strings.

A simple non-trivial example:
```Java
String name = "Alice";
int age = 5;
double score = 93.456;
int rank = 2;

String template = "Name: %1$-10s | Age: %2$02d | Score: %3$07.2f | Rank:
#%4$03d";
String result = String.format(template, name, age, score, rank);
System.out.println(result);
```

```Python
name = "Alice"
age = 5
score = 93.456
rank = 2

result = f"Name: {name:<10} | Age: {age:02} | Score: {score:07.2f} | Rank:
#{rank:03}"
print(result)
```
I find it easier to scan the f-string than the equivalent Java formatted
string.


Now, here's a real-world example of code I am porting from Python to Java,
as part of a JSON pretty-printer. In Python, in a particular context where
I am displaying formatted keys (kf) and values (vf) of a Map member:
indent_str is a string of blank spaces to align the key:value horizontally.

Python:

f"{indent_str}{OPEN_BRACE}{SPACE}{kf}{COLON}{SPACE}{vf}{SPACE}{CLOSE_BRACE}"


the variables here are indent_str, kf, and vf, and the rest are constants.
Using constants instead of literal characters has several benefits that
most developers should understand. I also appreciate the larger
signal-to-noise ratio that the constants display over inline characters.

In Java, my first attempt to duplicate this was hilarious:

"%s%s%s%s%s%s%s%s%s".formatted(indentString,OPEN_BRACE, SPACE, kf,
COLON, SPACE, vf, SPACE, CLOSE_BRACE);


Uhm, is that 8, or 9, or 10 %s ? hmm...

So after some refactoring I ended up with this:

"%s{ %s: %s }".formatted( indentString, kf, vf )


bye-bye constants, you're as useful to me as a 4-assed monkey. (South Park
reference...)

Is this "just as good?" Eh. Did I add an extra space somewhere? Did I
forget a brace? Or did I add an extra one? And if I someday need to add a
new argument, I need to add something in two places, and manually make sure
to coordinate those.... sigh.

So that's my contribution to the topic for the day.

Am I just re-hashing obvious things that everyone knows about already?

 - Rob
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20250724/e6896081/attachment.htm>


More information about the amber-dev mailing list