8

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.

6
  • 4
    You are leaking a file descriptor here. Files.lines() should be opened in a try-with-resources statement. Commented Apr 7, 2016 at 17:13
  • 1
    Is there whitespace in the file? Commented Apr 7, 2016 at 17:14
  • 2
    null may suggests that map.get(key) couldn't find key in map. Try printing entire map returned by util.getMapFromCSV(filePath). Commented Apr 7, 2016 at 17:15
  • @fge doesn't collect() close the stream? Commented Apr 7, 2016 at 17:18
  • 2
    No it doesn't. It consumes all the elements but doesn't call .close(). You have to do it yourself. (by the way, it is BaseStream which implements AutoCloseable, and Stream extends BaseStream) Commented Apr 7, 2016 at 17:34

3 Answers 3

9

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;
    }
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for sharing! Do you know of a way to do it with streams while removing duplicates?
2

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.

Comments

0

in a form that might be easier to read – with mapping

public static Map<String, String> getMapFromCSV(final String filePath) throws IOException {
  try(Stream<String> lines = Files.lines(Paths.get(filePath))) {
      return lines.collect(
        mapping(s -> s.split(","), toMap(k -> k[0], v -> v[1])));
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.