skip to content

What do String.indent(int) and String.transform(Function) do (Java 12), and when would you use each?

level: seniorimportance: nice to knowfreq 35%

answer

  1. Both Java 12
  2. indent(n): +n spaces/line (n<0 removes), normalizes to \n
  3. indent forces a trailing \n on every line (gotcha)
  4. transform(f): applies f, returns ANY type R
  5. transform = fluent left-to-right pipeline / pipe-like

basics

~20 s

indent(n) (Java 12) adds n spaces of indentation to each line (or removes up to n with a negative value) and normalizes line endings to \n, ensuring each line ends with a newline. transform(fn) applies a function to the whole string and returns its result, letting you chain custom operations fluently.

solid answer

~50 s

Both arrived in Java 12. String.indent(int n): for n > 0 it prepends n spaces to every line; for n < 0 it removes up to n leading whitespace characters from each line; it also normalizes line terminators to \n and ensures every line ends with a line feed, including the last (so the result is suffixed with \n). It is built on lines(), so it is line-aware. String.transform(Function<? super String, ? extends R> f): applies f to this string and returns f's result (of any type R), enabling fluent method-chaining where you'd otherwise break the chain to call a static helper or parse the string. For example, s.strip().transform(Integer::parseInt) reads left-to-right. transform is general (the return type need not be a String), whereas indent is specifically for block-text formatting. Both are minor convenience additions; indent is most visible in text blocks (Java 15) and code generation.

code

java · 7 lines
java
// indent: normalizes endings and forces a trailing newline per line
String block = "a\nb";
System.out.print(block.indent(2)); // "  a\n  b\n"  (note trailing \n)

// transform: fluent pipeline ending in a non-String result
int value = "  42 ".strip().transform(Integer::parseInt); // 42
String shout = "hi".transform(s -> s.toUpperCase() + "!"); // "HI!"

go deeper

for a junior

Knows indent() shifts each line over by spaces and transform() applies a function to the string.

for a middle

Knows indent normalizes line endings and handles negative n; knows transform enables method chaining and can change the type.

for a senior

Explains the forced trailing newline and \n normalization of indent (built on lines()), and transform's generic return type for fluent pipelines; knows when each adds real value.

for a principal

Decides where these fit in code-generation/formatting utilities and pipeline style guides, weighing the indent trailing-newline surprise and avoiding gratuitous transform that hurts readability.

## Two small Java 12 additions ### String.indent(int n) `indent` adjusts the leading indentation of every line of a multi-line string and normalizes its line structure. Behavior: - **n > 0**: prepend `n` space characters to the start of each line. - **n < 0**: remove up to `n` leading **whitespace** characters from each line (it won't remove non-whitespace, and stops at the first non-whitespace; a line with fewer leading spaces just loses what it has). - **n == 0**: no indentation change, but normalization still happens. Crucially, indent does two normalization things regardless of n: 1. It splits the string into lines using `lines()` (so it understands `\n`, `\r`, `\r\n`). 2. It **terminates every line with `\n`**, including the last line. This means the result almost always **ends with a trailing newline** even if the input didn't. People are frequently surprised that `"abc".indent(2)` returns `" abc\n"` (note the trailing newline). Line terminators in the output are always `\n` (CRLF is normalized away). Use cases: formatting generated source code, indenting a block before printing, and shaping text blocks (the `"""..."""` multi-line string literal added in Java 15). It is line-aware, so it is the right tool versus a manual prefix-on-each-line loop. ### String.transform(Function<? super String, ? extends R>) `transform` applies the supplied function `f` to the string and returns whatever `f` returns. Its signature lets the result be **any type** `R`, not just a String. The whole point is **fluent chaining**: normally to apply a non-method operation you must break out of the dot-chain and either nest calls (inside-out, hard to read) or introduce a temp variable. transform lets you keep reading left-to-right. Compare: - Without: `int n = Integer.parseInt(line.strip());` - With: `int n = line.strip().transform(Integer::parseInt);` Or returning a String: `s.transform(x -> x.toUpperCase() + "!")`. It is analogous to a pipe operator. It does nothing you couldn't do otherwise; it just improves readability for pipelines. ### What is a Function? `java.util.function.Function<T, R>` is a functional interface with one method `R apply(T t)` — it takes a `T` and returns an `R`. You pass it as a lambda (`x -> ...`) or a method reference (`Integer::parseInt`). transform calls `f.apply(this)` and returns the result. ## When to use which - `indent` — formatting/printing multi-line text blocks; remember the forced trailing `\n` and `\n` normalization. - `transform` — when you want a readable, left-to-right pipeline that ends in a custom (possibly non-String) operation. Skip it for trivial single calls where it adds no clarity. ## Deriving the answer at any level Key facts: indent adds/removes leading spaces per line, normalizes to \n, and force-appends a trailing newline (built on lines()); transform applies a Function and returns any type R for fluent chaining. From those you can give a junior-to-principal answer.

  • What does "abc".indent(2) return exactly?
    " abc\n" — two leading spaces AND a trailing newline, because indent terminates every line with \n.
  • Can transform return a non-String type?
    Yes. Its signature is Function<? super String, ? extends R>, so it can return any type R, e.g. an int via Integer::parseInt.

saying these in an interview costs you the question

  • Forgetting indent() appends a trailing newline
  • Thinking transform must return a String
  • Confusing indent's negative-n (remove whitespace) with adding
  • Claiming transform does something a static call couldn't — it's purely about readability

context