Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert csv to a map using Java 8 Stream

I'm trying to create a simple parsing util that converts a two-column CSV file and put it into a map.

public Map<String, String> getMapFromCSV(final String filePath) throws IOException {
    return Files.lines(Paths.get(filePath))
                .map(line -> line.split(","))
                .collect(Collectors.toMap(line -> line[0], line -> line[1]));
}

As you can see, I'm creating a stream of strings, delimiting each line on a comma and transforming it into a string array, and finally mapping key to index 0 and value to index 1.

@Test
public void testGetMapFromCSV() throws IOException{
    actual = util.getMapFromCSV(filePath).get("AL");
    expected = "ALABAMA";

    assertEquals(expected, actual);
}

For some reason, when I run this test, the actual value is null. I ruled out invalid filePath because it's working fine in another unit test, and the key value is present in the CSV. I've been staring at it for a few hours now, figured maybe someone here could point out my error.

Also, I'm fairly new to Java 8, so if anyone knows a better/cleaner way of writing this, I'd appreciate the feedback.

like image 981
ark234 Avatar asked Apr 07 '16 17:04

ark234


2 Answers

Ok, I added lines.close() and removed any whitespace from the csv and it works! Strange, considering the csv got parsed fine in my other method. Here's what it looks like:

public static Map<String, String> getMapFromCSV(final String filePath) throws IOException{

        Stream<String> lines = Files.lines(Paths.get(filePath));
        Map<String, String> resultMap = 
                lines.map(line -> line.split(","))
                     .collect(Collectors.toMap(line -> line[0], line -> line[1]));

        lines.close();

        return resultMap;
    }
like image 125
ark234 Avatar answered Nov 16 '22 12:11

ark234


Try-with-resources with AutoCloseable

As commented by fge, using try-with-resources makes this easier.

Here is the code from your Answer but using try-with-resources to automatically close a Stream that is also AutoCloseable. And some added SPACE characters for breathing room.

public static Map<String, String> getMapFromCSV(final String filePath) throws IOException{

    try (
        Stream < String > lines = Files.lines( Paths.get( filePath ) );
    )
    {
        Map < String , String > resultMap = 
                lines.map( 
                         line -> line.split( "," ) 
                     )
                     .collect(
                         Collectors.toMap( line -> line[0] , line -> line[1] )
                     );
        return resultMap;
    }
    // The `Stream` named `lines` is automatically closed at this point by the try-with-resources.
}

When the {…} block of the try-with-resources ends, any resources opened in the try are automatically closed, in reverse order of their opening. This is true whether flow-of-control leaves the block gracefully upon completion, or abruptly due to an exception or a return (as seen in your code). See discussion on this Question, Try-with-resources and return statements in java.

like image 2
Basil Bourque Avatar answered Nov 16 '22 12:11

Basil Bourque