What is the best way to iterate over the lines of a Java String?
JavaStringLoopsJava 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
});
> 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
}