如何使用Java 8 Stream将CSV转换为Map

8

我正在尝试创建一个简单的解析工具,将双列CSV文件转换为映射。

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]));
}

正如你所看到的,我正在创建一个字符串流,将每一行以逗号为分隔符转换为一个字符串数组,最后将键映射到索引0,值映射到索引1。

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

    assertEquals(expected, actual);
}

出现这种情况,是因为当我运行这个测试时,实际值为null。我排除了无效的filePath,因为另一个单元测试中它工作得很好,并且在CSV中存在键值。我已经盯着它看了几个小时,觉得也许有人能指出我的错误。
另外,我对Java 8还比较新,如果有人知道更好/更清晰的编写方式,我将感激不尽。

4
这里存在一个文件描述符泄漏问题。应该在 try-with-resources 语句中打开 Files.lines() - fge
1
文件中是否有空格? - rgettman
2
null 可能意味着 map.get(key) 在 map 中找不到 key。尝试打印由 util.getMapFromCSV(filePath) 返回的整个 map。 - Pshemo
@fge不是会自动关闭流吗? - ark234
2
不,它并没有。它会消耗所有元素,但不会调用.close()方法。你必须自己去做。 (顺便说一下,实现AutoCloseable的是BaseStream,而Stream则扩展了BaseStream - fge
在分割之前,您可以尝试过滤掉空行。 - Hank D
3个回答

9

好的,我添加了lines.close()并且从csv中删除了任何空白,现在它可以正常工作了!很奇怪,因为csv在我的其他方法中被解析得很好。这是它的样子:

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;
    }

谢谢分享!你知道有没有一种使用流来去除重复项的方法吗? - Fabio Lopez

2

使用AutoCloseable的try-with-resources

正如fge评论的那样,使用try-with-resources可以使这个过程更加简单。

以下是你的回答的代码,但使用try-with-resources自动关闭一个同时也是AutoCloseableStream。并且添加了一些空格以便阅读。

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

当try-with-resources的{...}块结束时,任何在try中打开的资源都会自动关闭,按照它们打开的相反顺序关闭。无论流程控制是否在完成时优雅地离开该块,或者由于异常或return而突然中断(如您的代码中所见)。请参阅有关此问题的讨论:Java中的Try-with-resources和return语句.

0

以更易读的形式呈现 - 使用映射

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])));
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接