1. Overview
BufferedReader is a class that is used to read text from character input stream which provides efficient reading of characters, arrays and lines. As of Java 8 new method lines() was added to the BufferedReader class. Let’s take a deeper look at this method.
Read more about Files class and its new methods here. There are tons of examples to play with.
2. Content
We will take a look at method lines() and use it in 2 different ways.
3. public Stream<String> lines()
Before Java 8 we were given a method called readLine() which reads one line of the file. If it returns null then the file reading is completed. But this steps are imperative approach.
lines() method is very interesting method as it lets you turn BufferedReader into a java.util.stream.Stream<String>. Once we have Stream we can traverse it in declarative way. One thing to note about the return type Stream is that the file reading will happen during Stream terminal operation that means the reading of file is lazily implemented.
4. Using lines() to get largest length of line
Let’s use lines() method to do some fun things. We have a text file which has more than 450,000 words in it. Let’s see which is the longest word.
Below block of code prints the length of longest word present in words.txt file. In our case the longest word length is 45.
try (BufferedReader reader = Files.newBufferedReader(Paths.get("words.txt"))) { OptionalInt optMaxLength = reader .lines() .mapToInt(String::length) .max(); Assert.assertEquals(OptionalInt.of(45), optMaxLength); } catch (IOException ex) { ex.printStackTrace(); }
So what is that word? The word is pneumonoultramicroscopicsilicovolcanoconiosis which means “lung disease caused by inhaling very fine ash and sand dust”.
Damn, that’s a long word. Tried few times to pronounce it, I give up. 😉
5. Using lines() to get largest word
So how to get longest word from the words.txt file? Well we can use max(Comparator) method of Stream interface. Let’s take a look at that.
try (BufferedReader reader = Files.newBufferedReader(Paths.get("words.txt"))) { Optional<String> optLongestWord = reader .lines() .max((str1, str2) -> str1.length() > str2.length() ? 1 : -1); Assert.assertEquals( Optional.of( "pneumonoultramicroscopicsilicovolcanoconiosis"), optLongestWord); } catch (IOException ex) { ex.printStackTrace(); }
Above method is re-written below using better Comparator alternative as it is better to read and understand.
try (BufferedReader reader = Files.newBufferedReader(Paths.get("words.txt"))) { Optional<String> optLongestWord = reader .lines() .max(Comparator.comparing(String::length)); Assert.assertEquals( Optional.of( "pneumonoultramicroscopicsilicovolcanoconiosis"), optLongestWord); } catch (IOException ex) { ex.printStackTrace(); }
6. Reusing the Stream? No.
Don’t expect to reuse the stream following the terminal operation. As mentioned in JavaDoc, after the use of terminal operation there is no guarantee that reader will be at specific position from which it has to read the next character.
try (BufferedReader reader = Files.newBufferedReader(Paths.get("words.txt"))) { Assert.assertTrue(reader.lines().count() > 0); Assert.assertTrue(reader.lines().count() == 0); } catch (IOException ex) { ex.printStackTrace(); }
7. Conclusion
In this article, we learnt about the new method added to the BufferedReader class called Stream<String> lines which can be used to operate on file data declaratively.