Reading file in reverse order using commons.io and streams

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> {
    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.

Iterator from Supplier

Creating an Iterator can be one step towards creating a stream from some resource. SupplierIterator takes only a Supplier and uses buffer for the next value. Example is inspired by java.io.BufferedReader.lines() method.

public class SupplierIterator<T> implements Iterator<T> {
   private T buffer = null;
   private Supplier<T> supplier;

   public SupplierIterator(Supplier<T> supplier) {
      this.supplier = supplier;
   }

   @Override
   public boolean hasNext() {
      return (buffer != null) ||
         (buffer = supplier.get()) != null;
   }

   @Override
   public T next() {
      if (hasNext()) {
         T next = buffer;
         buffer = null;
         return next;
      } else {
         throw new NoSuchElementException();
      }
   }
}