Writing grep with Java 8 streams
22 Jul 2015Intro
We’re going to write our very own grep
command using Java 8 streams. By the end, we will be able to run it on the command line, just like the normal UNIX grep program.
Pre-reqs
This post assumes you have some familiarity with Java 8 streams and a basic understanding of regular expressions. We’re actually going to review grep
, so it’s ok if you do not yet know it.
What is grep?
According to wikipedia, “grep is a command-line utility for searching plain-text data sets for lines matching a regular expression.” And if you were wondering, grep stands for globally search a regular expression and print.
For example,
grep .*public.* MyJavaClass.java
might yield
public class MyJavaClass {
public static void main(String[] args) {
public static final int MY_INT_CONST = 3;
As input, grep
takes a pattern and some text to search (maybe a file, maybe the output of another program). As output, it then prints out all lines of the input text that match the pattern.
Our grep
implementation will only take files as input, and will only use Regular Expressions as patterns.
Not so bad, right?
Grep implementation
The grep
method
This is where we will write the bulk of the logic of our program. With streams, the method body is just one line, styled across two. (note: I omitted the throws
clause to keep the code clean).
public static Stream<String> grep (String pattern, String fileName) {
return Files.lines(Paths.get(fileName))
.filter(line -> line.matches(pattern));
}
Fortunately, Java 8 streams shipped with some pretty sweet I/O functions, like java.nio.Files::lines()
. This function takes a file name and returns a stream of the lines of that file.
All we need to do after that is filter those lines by matching on our pattern (built into Java.lang.String), and we’re done!
The main
method
Now, we can give our Grep class a main method so that we can call it from the command line.
public static void main(String[] args) throws IOException {
grep(args[0], args[1]).forEach(System.out::println);
}
All we’re doing here is calling our grep function, then printing out each line in the stream that gets returned.
The whole program
Putting it all back together, our grep program in its entirety looks like:
public class Grep {
public static void main(String[] args) throws IOException {
grep(args[0], args[1]).forEach(System.out::println);
}
public static Stream<String> grep(String pattern, String fileName)
throws IOException {
return Files.lines(Paths.get(fileName))
.filter(line -> line.matches(pattern));
}
}
Running our grep program
Now, we can find all the lines that have the word ‘public’ in Grep.java, using Grep.java.
java Grep ".*public.*" Grep.java
and see as output:
public class Grep {
public static void main(String[] args) throws IOException {
public static Path getPath(String fileName) throws IOException {
public static Stream<String> grep(String pattern, String fileName)