Core Java

Parsing a file with Stream API in Java 8

Streams are everywhere in Java 8. Just look around and for sure you will find them. It also applies to java.io.BufferedReader. Parsing a file in Java 8 with Stream API is extremely easy.

I have a CSV file that I want to be read. An example below:
 
 
 
 
 
 

username;visited
jdoe;10
kolorobot;4

A contract for my reader is to provide a header as list of strings and all records as list of lists of strings. My reader accepts java.io.Reader as a source to read from.

I will start with reading the header. The algorithm for reading the header is as follows:

  • Open a source for reading,
  • Get the first line and parse it,
  • Split line by a separator,
  • Get the first line and parse it,
  • Convert the line to list of strings and return.

And the implementation:

class CsvReader {

    private static final String SEPARATOR = ";";

    private final Reader source;

    CsvReader(Reader source) {
        this(source);
    }
    List<String> readHeader() {
        try (BufferedReader reader = new BufferedReader(source)) {
            return reader.lines()
                    .findFirst()
                    .map(line -> Arrays.asList(line.split(SEPARATOR)))
                    .get();
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }    
}

Fairly simple. Self-explanatory. Similarly, I created a method to read all records. The algorithm for reading the records is as follows:

  • Open a source for reading,
  • Skip the first line,
  • Split line by a separator,
  • Apply a mapper on each line that maps a line to a list of strings.

And the implementation:

class CsvReader {

    List<List<String>> readRecords() {
        try (BufferedReader reader = new BufferedReader(source)) {
            return reader.lines()
                    .substream(1)
                    .map(line -> Arrays.asList(line.split(separator)))
                    .collect(Collectors.toList());
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }  
}

Nothing fancy here. What you could notice is that a mapper in both methods is exactly the same. In fact, it can be easily extracted to a variable:

Function<String, List<String>> mapper 
    = line -> Arrays.asList(line.split(separator));

To finish up, I created a simple test.

public class CsvReaderTest {

    @Test
    public void readsHeader() {
        CsvReader csvReader = createCsvReader();
        List<String> header = csvReader.readHeader();
        assertThat(header)
                .contains("username")
                .contains("visited")
                .hasSize(2);
    }

    @Test
    public void readsRecords() {
        CsvReader csvReader = createCsvReader();
        List<List<String>> records = csvReader.readRecords();
        assertThat(records)
                .contains(Arrays.asList("jdoe", "10"))
                .contains(Arrays.asList("kolorobot", "4"))
                .hasSize(2);
    }

    private CsvReader createCsvReader() {
        try {
            Path path = Paths.get("src/test/resources", "sample.csv");
            Reader reader = Files.newBufferedReader(
                path, Charset.forName("UTF-8"));
            return new CsvReader(reader);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }
}
Reference: Parsing a file with Stream API in Java 8 from our JCG partner Rafal Borowiec at the Codeleak.pl blog.

Rafal Borowiec

Software developer, Team Leader, Agile practitioner, occasional blogger, lecturer. Open Source enthusiast, quality oriented and open-minded.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button