Java 11 New String Methods

July 17, 20264 min readUpdated 8/20/2026

Java 11 added five small String methods. None of them is clever, and together they delete a surprising amount of the utility code every project used to carry — the null-and-whitespace check, the manual line splitter, the loop that repeats a character.

isBlank()

class Demo {
    void run() {
        System.out.println("".isEmpty());        // true
        System.out.println("   ".isEmpty());     // false — three characters is not empty
        System.out.println("   ".isBlank());     // true  — but it is blank
        System.out.println("\t\n ".isBlank());   // true  — tabs and newlines count
        System.out.println("a".isBlank());       // false
    }
}

isBlank() is what people usually mean when they reach for isEmpty(). A form field containing three spaces is empty as far as your user is concerned, and isEmpty() disagrees.

The everyday check, still needing its own null guard:

class Demo {
    boolean hasContent(String value) {
        return value != null && !value.isBlank();
    }
}

strip() and friends

class Demo {
    void run() {
        String padded = "  hello  ";

        System.out.println("[" + padded.strip() + "]");          // [hello]
        System.out.println("[" + padded.stripLeading() + "]");   // [hello  ]
        System.out.println("[" + padded.stripTrailing() + "]");  // [  hello]
    }
}

These replace trim(), and the difference is not cosmetic. trim() was written in 1995 and removes any character with a code below U+0020 — a definition that predates Unicode having opinions about whitespace. It does not remove a non-breaking space, an em space, or an ideographic space, all of which arrive routinely from copy-paste and from Word documents:

class Demo {
    void run() {
        String nbsp = " hello ";       // non-breaking spaces

        System.out.println("[" + nbsp.trim() + "]");    // [ hello ] — unchanged
        System.out.println("[" + nbsp.strip() + "]");   // [hello]
    }
}

strip() uses Character.isWhitespace, which knows about all of it. Use strip() in new code and treat trim() as legacy. The one exception is if you specifically need the old behaviour for compatibility with something that already depends on it.

lines()

class Demo {
    void run() {
        String text = "first\nsecond\r\nthird\n";

        text.lines().forEach(System.out::println);       // first, second, third

        long count = text.lines().count();
        System.out.println(count);                        // 3 — the trailing newline is not a line

        List<String> nonEmpty = text.lines()
                .map(String::strip)
                .filter(s -> !s.isBlank())
                .toList();
        System.out.println(nonEmpty.size());              // 3
    }
}

It returns a Stream<String>, not an array, so filtering and mapping follow naturally. It also handles all three line-ending conventions — \n, \r\n and a bare \r — which is the part that makes split("\n") a bug on Windows input.

The comparison is worth seeing directly:

class Demo {
    void run() {
        String text = "a\r\nb\n";

        System.out.println(text.split("\n").length);      // 2, but "a" still has a trailing \r
        System.out.println(text.lines().count());         // 2, clean
    }
}

repeat(int)

class Demo {
    void run() {
        System.out.println("-".repeat(30));               // a separator line
        System.out.println("ab".repeat(3));               // ababab
        System.out.println("x".repeat(0));                // "" — legal, empty

        // Indenting, padding, simple tables
        System.out.println(" ".repeat(4) + "indented");
    }
}

A negative count throws IllegalArgumentException; zero is fine and gives an empty string. Before this existed, everyone had a StringUtils.repeat or a loop with a StringBuilder.

Null safety, which these do not give you

Worth being explicit about, because the names suggest otherwise: none of these methods is null-safe. Calling any of them on a null reference throws, exactly as before:

class Demo {
    void run() {
        String value = null;
        // value.isBlank();      // NullPointerException

        System.out.println(Objects.requireNonNullElse(value, "").isBlank());   // true
        System.out.println(Optional.ofNullable(value)
                .map(String::strip)
                .filter(s -> !s.isBlank())
                .orElse("(none)"));                                            // (none)
    }
}

Java 11 did add Predicate.not, which pairs with these nicely and removes an awkward lambda:

class Demo {
    void run() {
        List<String> raw = List.of("Ana", "  ", "Bo", "");

        // Before: a lambda, because there is no isNotBlank
        System.out.println(raw.stream().filter(s -> !s.isBlank()).toList());

        // After
        System.out.println(raw.stream().filter(Predicate.not(String::isBlank)).toList());
        // [Ana, Bo]
    }
}

Where they came from, and why it took so long

It is reasonable to ask why a language in its eleventh major version was still adding repeat. The answer is instructive about how Java evolves.

String is one of the most widely used classes in existence, and every method added to it is permanent — it can never be removed, and it constrains every future implementation. So the bar for adding one is high, and the argument is not "this is useful" but "the absence of this is causing identical code to be written in every project."

By 2018 that was demonstrably true. Apache Commons had StringUtils.isBlank, repeat and stripStart; Guava had its own; and most codebases without either had hand-rolled versions with subtly different edge-case behaviour. Pulling the five most-duplicated helpers into the JDK removed a dependency from a lot of projects that were carrying Commons Lang for little else.

The practical consequence for you: if you are working in a codebase that still imports StringUtils for these, the imports can usually go. Check the null behaviour first, though — StringUtils.isBlank(null) returns true, while null.isBlank() throws, and that difference has caused real bugs during exactly this cleanup.

All five, and what they replace

MethodReturnsReplaces
isBlank()booleantrim().isEmpty()
strip()Stringtrim(), correctly
stripLeading() / stripTrailing()Stringa regex, or a manual index scan
lines()Stream<String>split("\\r?\\n")
repeat(n)Stringa StringBuilder loop

All of them are on the String fundamentals post's list of things worth memorising, and all of them return a new string — String is still immutable, so an unassigned value.strip(); does nothing at all.

Next

The Java 11 file and collection methods is next — another handful of small additions that each remove a helper class.