Arrays.stream/String.split

Since String.split returns an array String[], I always recommend Arrays.stream as the canonical idiom for streaming over an array.

String input = "dog,cat,bird";
Stream<String> stream = Arrays.stream(input.split( "," ));
stream.forEach(System.out::println);

Stream.of/String.split

Stream.of is a varargs method which just happens to accept an array, due to the fact that varargs methods are implemented via arrays and there were compatibility concerns when varargs were introduced to Java and existing methods retrofitted to accept variable arguments.

Stream<String> stream = Stream.of(input.split(","));     // works, but is non-idiomatic
Stream<String> stream = Stream.of("dog", "cat", "bird"); // intended use case

Pattern.splitAsStream

Pattern.compile(",").splitAsStream(string) has the advantage of streaming directly rather than creating an intermediate array. So for a large number of sub-strings, this can have a performance benefit. On the other hand, if the delimiter is trivial, i.e. a single literal character, the String.split implementation will go through a fast path instead of using the regex engine. So in this case, the answer is not trivial.

Stream<String> stream = Pattern.compile(",").splitAsStream(input);

If the streaming happens inside another stream, e.g. .flatMap(Pattern.compile(pattern) ::splitAsStream) there is the advantage that the pattern has to be analyzed only once, rather than for every string of the outer stream.

Stream<String> stream = Stream.of("a,b", "c,d,e", "f", "g,h,i,j")
    .flatMap(Pattern.compile(",")::splitAsStream);

This is a property of method references of the form expression::name, which will evaluate the expression and capture the result when creating the instance of the functional interface, as explained in What is the equivalent lambda expression for System.out::println and java.lang.NullPointerException is thrown using a method-reference but not a lambda expression

Answer from Holger on Stack Overflow
Top answer
1 of 3
138

Arrays.stream/String.split

Since String.split returns an array String[], I always recommend Arrays.stream as the canonical idiom for streaming over an array.

String input = "dog,cat,bird";
Stream<String> stream = Arrays.stream(input.split( "," ));
stream.forEach(System.out::println);

Stream.of/String.split

Stream.of is a varargs method which just happens to accept an array, due to the fact that varargs methods are implemented via arrays and there were compatibility concerns when varargs were introduced to Java and existing methods retrofitted to accept variable arguments.

Stream<String> stream = Stream.of(input.split(","));     // works, but is non-idiomatic
Stream<String> stream = Stream.of("dog", "cat", "bird"); // intended use case

Pattern.splitAsStream

Pattern.compile(",").splitAsStream(string) has the advantage of streaming directly rather than creating an intermediate array. So for a large number of sub-strings, this can have a performance benefit. On the other hand, if the delimiter is trivial, i.e. a single literal character, the String.split implementation will go through a fast path instead of using the regex engine. So in this case, the answer is not trivial.

Stream<String> stream = Pattern.compile(",").splitAsStream(input);

If the streaming happens inside another stream, e.g. .flatMap(Pattern.compile(pattern) ::splitAsStream) there is the advantage that the pattern has to be analyzed only once, rather than for every string of the outer stream.

Stream<String> stream = Stream.of("a,b", "c,d,e", "f", "g,h,i,j")
    .flatMap(Pattern.compile(",")::splitAsStream);

This is a property of method references of the form expression::name, which will evaluate the expression and capture the result when creating the instance of the functional interface, as explained in What is the equivalent lambda expression for System.out::println and java.lang.NullPointerException is thrown using a method-reference but not a lambda expression

2 of 3
3

Robustness

I can see no difference in the robustness of the three approaches.

Readability

I am not aware of any credible scientific studies on code readability involving experienced Java programmers, so readability is a matter of opinion. Even then, you never know if someone giving their opinion is making an objective distinction between actual readability, what they have been taught about readability, and their own personal taste.

So I will leave it to you to make your own judgements on readability ... noting that you do consider this to be a high priority.

FWIW, the only people whose opinions on this matter are you and your team.

Performance

I think that the answer to that is to carefully benchmark the three alternatives. Holger provides an analysis based on his study of some versions of Java. But:

  1. He was not able to come to a definite conclusion on which was fastest.
  2. Strictly speaking, his analysis only applies to the versions of Java he looked at. (Some aspects of his analysis could be different on (say) Android Java, or some future Oracle / OpenJDK version.)
  3. The relative performance is likely depend on the length of the string being split, the number of fields, and the complexity of the separator regex.
  4. In a real application, the relative performance may also depend what you do with the Stream object, what garbage collector you have selected (since the different versions apparently generate different amounts of garbage), and other issues.

So if you (or anyone else) are really concerned with the performance, you should write a micro-benchmark and run it on your production platform(s). Then do some application specific benchmarking. And you should consider looking at solutions that don't involve streams.

🌐
Baeldung
baeldung.com › home › java › java streams › string operations with java streams
String Operations with Java and Stream API | Baeldung
January 8, 2024 - Java 8 has introduced a new Stream API that lets us process data in a declarative manner. In this quick article, we would learn how to use the Stream API to split a comma-separated String into a list of Strings and how to join a String array into a comma-separated String.
🌐
Medium
medium.com › @AlexanderObregon › javas-pattern-splitasstream-method-explained-99ca4b345ccd
Java's Pattern.splitAsStream() Method Explained
October 29, 2024 - The splitAsStream() method from the java.util.regex.Pattern class is a powerful feature introduced in Java 8. It allows for splitting strings into a stream based on a regular expression, making it a great tool for processing large text files ...
🌐
Mkyong
mkyong.com › home › java › how to split a string in java
How to split a string in Java | mkyong.com
February 9, 2022 - The example uses the regex pattern \\r?\\n to split a string by new lines and return a stream; later, we trim and filter the empty lines. ... package com.mkyong.string.split; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StringSplitNewLines { public static void main(String[] args) { StringBuilder sb = new StringBuilder(); sb.append("aaa \n"); sb.append("bbb \r\n"); sb.append("ccc\n"); sb.append("\n"); sb.append("ddd\r\n"); sb.append("\r\n"); sb.append("eee\n"); String text = sb.toString(); System.out.println("---Original---"); System.out.println(text); System.out.println("---Split---"); // split by new line, trim and filter empty line List<String> lines = Arrays.stream(text.split("\\r?\\n")) .map(x -> x.trim()) .filter(x -> x.length() > 0) .collect(Collectors.toList()); for (String line : lines) { System.out.println(line); } } }
🌐
Coderanch
coderanch.com › t › 724831 › java › Splitting-string-flatMapping-creating-objects
Splitting string, flatMapping it and creating objects using Java streams? (Features new in Java 8 forum at Coderanch)
January 4, 2020 - For your case: 1. When you are using String::split to remove "seats=" prefix, the first part is an empty string, and the second part is the string that you want. So, you should use [1] to access that part. So, you should remove Arrays::stream method, because you have only one part per "seats=xx" string.
🌐
Baeldung
baeldung.com › home › java › java string › split a string in java
Split a String in Java | Baeldung
January 8, 2024 - We can achieve the same result ... .toArray(String[]::new); We can split a string into two parts by getting its midpoint and using substring() to get the separated parts....
🌐
ZetCode
zetcode.com › java › splitstring
Java split string - splitting strings in Java
We can split strings with Pattern in a functional way using streams. ... import java.util.List; import java.util.regex.Pattern; import java.util.stream.Collectors; void main() { String phoneNumber = "202-555-0154"; List<String> output = Pattern.compile("-") .splitAsStream(phoneNumber) .collect(Collectors.toList()); output.forEach(System.out::println); }
Find elsewhere
Top answer
1 of 7
1

Instead of applying replaceAll on a line, do it on words of the line as follows:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        String str = "Harry is a good cricketer. Tanya is an intelligent student. Bravo!";
        List<String> words = Arrays.stream(str.split("\\s+")).map(s -> s.replaceAll("[^A-Za-z0-9 ]", ""))
                .collect(Collectors.toList());
        System.out.println(words);
    }
}

Output:

[Harry, is, a, good, cricketer, Tanya, is, an, intelligent, student, Bravo]

Note: The regex, \\s+ splits a string on space(s).

2 of 7
1

try this:

    String fileName = "file.txt";
        try {
        Map<String, Long> wordCount = Files.lines(Path.of(fileName))
                .flatMap(line -> Arrays.stream(line.split("\\s+")))
                     .filter(w->w.matches("[a-zA-Z]+"))
                     .sorted(Comparator.comparing(String::length)
                            .thenComparing(String.CASE_INSENSITIVE_ORDER))  
                        .collect(Collectors.groupingBy(w -> w, 
         LinkedHashMap::new, Collectors.counting()));
        wordCount.entrySet().forEach(System.out::println);
        }catch (Exception e) {
            e.printStackTrace();
        }

This is relatively simple. It just splits on white space and counts the words by putting them in a map where the Key is the word and the Value is a long containing the count.

I included a filter to only capture words of nothing but letters. The way this works is that the Lines put into a stream. Each line is then split into words using String.split. Since this creates an array, the flatMap converts all these individual streams of words into a single stream where they are processed. The work horse of this is the Collectors.groupingBy which will group the values in a particular way for each key. In this case, I specified the Collectors.counting() method to increase the count each time the key (i.e. word) appeared.

As an option, I sorted the words first on length and then alphabetically, ignoring case.

🌐
Benchresources
benchresources.net › home › java › java 8 – how to split a string and collect to any collection ?
Java 8 - How to split a String and Collect to any Collection ? - BenchResources.Net
September 28, 2022 - Original comma-separted String :- Grapes, Apple, Mango, Banana, Orange, Melons Iterating &amp; printing split-ted String from List :- Grapes Apple Mango Banana Orange Melons · Initially, we got a String with colon-separated values · Inside Arrays.stream(), split a String using colon as delimiter using String’s split() method
🌐
Techie Delight
techiedelight.com › home › java › split string in java using a given delimiter
Split String in Java using a given delimiter | Techie Delight
July 7, 2026 - Note that this returns an Iterable instead of an array of strings. ... From Java 8 onwards, we can also use the splitAsStream() method, which returns the stream of strings computed by splitting the input around matches of the given pattern.
🌐
CodingTechRoom
codingtechroom.com › question › split-string-stream-java
How to Split a String into a Stream of Strings in Java? - CodingTechRoom
import java.util.Arrays; import java.util.regex.Pattern; import java.util.stream.Stream; public class HelloWorld { public static void main(String[] args) { stream1().forEach(System.out::println); stream2().forEach(System.out::println); stream3().forEach(System.out::println); } private static Stream<String> stream1() { return Arrays.stream("b,l,a".split(",")); } private static Stream<String> stream2() { return Stream.of("b,l,a".split(",")); } private static Stream<String> stream3() { return Pattern.compile(",").splitAsStream("b,l,a"); } }
Top answer
1 of 2
16

Using flatMap is not the right tool for the job. What you apparently want to do is

strings.map(string -> string.split(" ", 2))
       .map(array  -> new MyClass(array[0], array[1]))

You may process the stream further by using .collect(Collectors.toList()) to get a List<MyClass> or .findAny() to get a single MyClass instance (if any).

Generally, streaming an array is only useful if you want to treat all elements uniformly, i.e. not if their position has a special meaning which has to be preserved for subsequent operations.


And if you really want to create a flat stream of words or tokens, you shouldn’t use the combination of String.split and Arrays.stream as that will create and fill an unnecessary intermediate array. In this case use

strings.flatMap(Pattern.compile(" ")::splitAsStream)

see Pattern.splitAsStream

2 of 2
3

It was an interesting challenge even if streams should not be used for such simple tasks. Here's the complete code:

public class Example {
    public static void main(String[] args) {
        String[] strings = {"randomText1 randomText2"};
        MyClass myClass = Arrays.stream(strings)
                .map(string -> string.split(" "))
                .flatMap(Arrays::stream)
                .collect(new MyCollector());
        System.out.println("myClass = " + myClass.toString());
    }
}

class MyCollector implements Collector<String, List<String>, MyClass> {
    @Override
    public BiConsumer<List<String>, String> accumulator() {
        return List::add;
    }

    @Override
    public Supplier<List<String>> supplier() {
        return ArrayList::new;
    }

    @Override
    public BinaryOperator<List<String>> combiner() {
        return (strings, strings2) -> {
            strings.addAll(strings2);
            return strings;
        };
    }

    @Override
    public Function<List<String>, MyClass> finisher() {
        return strings -> new MyClass(strings.get(0), strings.get(1));
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }
}

class MyClass {
    String s1;
    String s2;

    public MyClass(String s1, String s2) {
        this.s1 = s1;
        this.s2 = s2;
    }

    @Override
    public String toString() {
        return "MyClass{" +
                "s1='" + s1 + '\'' +
                ", s2='" + s2 + '\'' +
                '}';
    }
}
🌐
Baeldung
baeldung.com › home › java › java streams › how to split a stream into multiple streams
How to Split a Stream into Multiple Streams | Baeldung
January 8, 2024 - In this tutorial, we learned how to split streams into groups and process them separately. First, we looked at the older Streams API methods: groupingBy and partitionBy. Next, we used a newer approach utilizing the teeing method introduced in Java 12.
🌐
Oracle
blogs.oracle.com › javamagazine › java-quiz-stream-pattern-splitasstream
Quiz yourself: Splitting Java streams and using escape characters | javamagazine
First, notice that the splitAsStream method splits the string argument "12|11|30" into three text chunks—"12", "11", and "30"—which are then converted to a stream of equivalent primitive int values by the mapToInt operation.
🌐
YouTube
youtube.com › watch
Java Stream: How to Split a String Twice and Get the Result Efficiently - YouTube
In this video, we dive into the powerful capabilities of Java Streams to manipulate strings efficiently. Specifically, we'll explore how to split a string tw...
Published: December 17, 2024
🌐
YouTube
youtube.com › watch
Java Streams Internals: Splitting and Combining - YouTube
This video delves into the internal mechanics of Java sequential streams, categorizing their operations into three main phases: split, apply, and combine. In...
Published: October 4, 2023