What is the best way to iterate over the lines of a Java String?

JavaStringLoops

Java Problem Overview


Currently I'm using something like :

String[]lines = textContent.split(System.getProperty("line.separator"));
for(String tmpLine : lines){
   //do something
}

I'm not very glad of this method because it create an heavy array (let say textContent can contain a book).

Is there any better solution to iterate over the lines of a String?

Java Solutions


Solution 1 - Java

You could use :

BufferedReader bufReader = new BufferedReader(new StringReader(textContent));

And use the readLine() method :

String line=null;
while( (line=bufReader.readLine()) != null )
{

}

Solution 2 - Java

To add the Java 8 way to this question:

Arrays.stream(content.split("\\r?\\n")).forEach(line -> /*do something */)

Of curse you can also use System.lineSeparator()to split if you are sure that the file is comming from the same plattform as the vm runs on.

Or even better use the stream api even more agressiv with filter, map and collect:

String result = Arrays.stream(content.split(System.lineSeparator()))
                     .filter(/* filter for lines you are interested in*/)
                     .map(/*convert string*/)
                     .collect(Collectors.joining(";"));

Solution 3 - Java

I believe you have a better API available starting with Java-11 where you can do the same using the String.lines() API which returns the stream of strings extracted from this string partitioned by line terminators.

public Stream<String> lines()

Usage of the same could be:-

Stream<String> linesFromString = textContent.lines();
linesFromString.forEach(l -> {  //do sth });

Important API Note :-

@implNote This method provides better performance than
          split("\R") by supplying elements lazily and
          by faster search of new line terminators.

Solution 4 - Java

You could use String.indexOf()/String.substring()

String separator = System.getProperty("line.separator");
int index = textContent.indexOf(separator);

while (index > 0)
{
  int nextIndex = textContent.indexOf(separator, index + separator.length());
  String line = textContent.substring(index + separator.length(), nextIndex);
    
  // do something with line.
}

Solution 5 - Java

Scanner

What about the java.util.Scanner class added in Java 1.5?

In summary:

> A simple text scanner which can parse primitive types and strings > using regular expressions. > > A Scanner breaks its input into tokens using a delimiter pattern, > which by default matches whitespace. The resulting tokens may then be > converted into values of different types using the various next > methods.

and of note for your scenario:

> The scanner can also use delimiters other than whitespace. This > example reads several items in from a string: > > String input = "1 fish 2 fish red fish blue fish"; > Scanner s = new Scanner(input).useDelimiter("\sfish\s"); > System.out.println(s.nextInt()); > System.out.println(s.nextInt()); > System.out.println(s.next()); > System.out.println(s.next()); > s.close();

Solution 6 - Java

Guava's Splitter works well. Especially as you can remove blank lines

Splitter splitter = Splitter.on(System.getProperty("line.separator"))
                            .trimResults()
                            .omitEmptyStrings();
for (String line : splitter.split(input)){
   // do work here
}

Solution 7 - Java

You can actually wrangle Scanner to allow you to use a normal for loop:

import java.util.Scanner;
public class IterateLines {
    public static void main(String[] args) {
        Iterable<String> sc = () ->
            new Scanner("foo bar\nbaz\n").useDelimiter("\n");
        for (String line: sc) {
            System.out.println(line);
        }
    }
}

gives us:

$ javac IterateLines.java && java IterateLines 
foo bar
baz

Solution 8 - Java

Combine java.io.StringReader and java.io.LineNumberReader

Solution 9 - Java

If you are using Java 1.8 (or Android) then try this:

new BufferedReader(new StringReader(str)).lines().forEachOrdered((line) -> {
    // process each line as you like
});

Docs state

> The Stream is lazily populated, i.e., read only occurs during the terminal stream operation.

Which means this runs quicker than other solutions that first generate a massive array of Strings before iteration can begin.

If you are using Java 11 or later then the answer @Naman gave recommending String#lines() method is even cleaner and fast as well, see https://stackoverflow.com/a/50631579/215266

Solution 10 - Java

use BufferedReader with StringReader argument. BufferedReader has a method readLine() so you can read your string line by line.

	StringReader reader = new StringReader(myBigTextString);
	BufferedReader br = new BufferedReader(reader);
	String line;
	while((line=br.readLine())!=null)
	{
		//do what you want
	}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionalain.janinmView Question on Stackoverflow
Solution 1 - JavaGuillaume PoletView Answer on Stackoverflow
Solution 2 - JavaleoView Answer on Stackoverflow
Solution 3 - JavaNamanView Answer on Stackoverflow
Solution 4 - JavaBrendanView Answer on Stackoverflow
Solution 5 - JavaAlexView Answer on Stackoverflow
Solution 6 - JavaJohn BView Answer on Stackoverflow
Solution 7 - JavaAndy BalaamView Answer on Stackoverflow
Solution 8 - Javadavid a.View Answer on Stackoverflow
Solution 9 - Javasatur9nineView Answer on Stackoverflow
Solution 10 - Javashift66View Answer on Stackoverflow