Let's say you want to read file from the end. There are a few implementations you can use, org.apache.commons.io.input.ReversedLinesFileReader for example or you cold find alternative one somewhere on the google. There is nice post on Crunchify covering the topic. Both of the examples have readLine method but it is not easy to use them in Java 8 streams since they don't implement method like java.io.BufferedReader.lines. To use them with streams anyway we need to create Spliterator and them simple StreamSupport.stream will create desired stream.
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Test public void reversedLinesReader_canBeUsedWithStreams() throws IOException { File file = temporaryFolder.newFile("testFile.txt"); Files.write(file.toPath(), Arrays.asList("line1", "line2", "line3", "line4")); try (ReversedLinesFileReader reader = new ReversedLinesFileReader(file, defaultCharset())) { Iterable<String> iterable = () -> new IOSupplierIterator<>(reader::readLine); List<String> lines = StreamSupport.stream(iterable.spliterator(), false) .limit(3).collect(Collectors.toList()); assertThat(lines).isEqualTo(Arrays.asList("line4", "line3", "line2")); } }
SupplierIterator from my previous post has to be altered in order to work with the method reference as above(reader::readLine), because method throws checked IOException. To use an existing one, above code would need to be altered to use lambda instead of a method reference and have try-catch block that would handle IOException. That responsibility can be given to an iterator:
public class IOSupplierIterator<T> implements Iterator<T> {
public class IOSupplierIterator<T> implements Iterator<T> {
private T buffer = null; private IOSupplier<T> supplier; public IOSupplierIterator(IOSupplier<T> supplier) { this.supplier = supplier; } @Override public boolean hasNext() { return (buffer != null) || (buffer = supplierGet()) != null; } private T supplierGet() { try { return supplier.get(); } catch (IOException e) { throw new UncheckedIOException(e.getMessage(), e); } } @Override public T next() { if (hasNext()) { T next = buffer; buffer = null; return next; } else { throw new NoSuchElementException(); } } @FunctionalInterface interface IOSupplier<T>{ T get() throws IOException; } }Note: Assert used in the test comes from AssertJ library that I recommend.