使用 Stream lambda 将 CSV 字符串值转换为 Hashmap

Convert CSV string value to Hashmap using Stream lambda

我正在尝试使用 Java 8 条流 API 从 CSV 字符串值中获取 HashMap<String,String>。我能够获取值等,但是如何将 List 的索引添加为 HashMap.

中的键
(HashMap<String, String>) Arrays.asList(sContent.split(",")).stream()
        .collect(Collectors.toMap(??????,i->i );

所以我的地图将包含如下所示的 Key 和 Value。

0->Value1
1->Value2
2->Value3
...

使用普通 Java 我可以轻松做到,但我想使用 JAVA 8 流 API.

您可以使用以下方法获得所需的输出

  private Map<Integer, String> getMapFromCSVString(String csvString) {
        AtomicInteger integer = new AtomicInteger();
        return Arrays.stream(csvString.split(","))
                .collect(Collectors.toMap(splittedStr -> integer.getAndAdd(1), splittedStr -> splittedStr));
    }

我写了下面的测试来验证输出。

 @Test
    public void getCsvValuesIntoMap(){
        String csvString ="shirish,vilas,Nikhil";
        Map<Integer,String> expected = new HashMap<Integer,String>(){{
            put(0,"shirish");
            put(1,"vilas");
            put(2,"Nikhil");

        }};
        Map<Integer,String> result = getMapFromCSVString(csvString);
        System.out.println(result);
        assertEquals(expected,result);

    }

您可以像这样创建一系列索引:

String[] values = sContent.split(",");
Map<Integer, String> result = IntStream.range(0, values.length)
                                       .boxed()
                                       .collect(toMap(Function.identity(), i -> values[i]));

这是一个奇怪的要求。当您调用 Arrays.asList(sContent.split(",")) 时,您已经拥有一个将 int 数字映射到它们的 String 的数据结构。结果是 List<String>,您可以调用 .get(intNumber) 来获得所需的值,就像您可以使用 Map<Integer,String>...

但是,如果它确实必须是 Map 并且您想使用流 API,您可以使用

Map<Integer,String> map=new HashMap<>();
Pattern.compile(",").splitAsStream(sContent).forEachOrdered(s->map.put(map.size(), s));

解释一下,Pattern.compile(separator).splitAsStream(string)Arrays.stream(string.split(separator)) 的作用相同,但不创建中间数组,因此更可取。而且您不需要单独的计数器,因为地图本质上维护这样一个计数器,它的大小。

上面的代码是创建此类临时地图的最简单代码,而干净的解决方案将避免流操作本身之外的可变状态,并 return 完成时创建新地图。但是干净的解决方案并不总是最简洁的:

Map<Integer,String> map=Pattern.compile(",").splitAsStream(sContent)
    .collect(HashMap::new, (m,s)->m.put(m.size(), s),
        (m1,m2)->{ int off=m1.size(); m2.forEach((k,v)->m1.put(k+off, v)); }
    );

虽然 collect 的前两个参数定义了与之前解决方案类似的操作,但最大的障碍是第三个参数,该函数仅在通过单个 csv 行请求并行处理时使用,不太可能受益于并行处理。但不支持省略它。如果使用,它将合并两个映射,这是两个并行操作的结果。由于两者都使用自己的计数器,因此必须通过添加第一张地图的大小来调整第二张地图的索引。