What do String.indent(int) and String.transform(Function) do (Java 12), and when would you use each?
answer
- Both Java 12
- indent(n): +n spaces/line (n<0 removes), normalizes to \n
- indent forces a trailing \n on every line (gotcha)
- transform(f): applies f, returns ANY type R
- transform = fluent left-to-right pipeline / pipe-like
basics
~20 sindent(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 sBoth 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// 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
Knows indent() shifts each line over by spaces and transform() applies a function to the string.
Knows indent normalizes line endings and handles negative n; knows transform enables method chaining and can change the type.
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.
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