Java 使用流api在字段上而不是对象上循环

Java 使用流api在字段上而不是对象上循环,java,collections,java-stream,Java,Collections,Java Stream,我想将Java 8的流api用于以下练习: 给定人员列表 Person是一个简单的POJO,具有名称(字符串)和年龄(int)属性 构造以下字符串Names=[joe,diana,thomas]&Ages=[34,52,19] 使用streams,我可以轻松做到以下几点: String result = persons.stream() .map(p -> "(" + p.getName() + "," + p.getAge() + ")") .collectors(C

我想将Java 8的流api用于以下练习:

  • 给定
    人员列表
  • Person
    是一个简单的POJO,具有名称(字符串)和年龄(int)属性
  • 构造以下字符串
    Names=[joe,diana,thomas]&Ages=[34,52,19]
使用streams,我可以轻松做到以下几点:

String result = persons.stream()
    .map(p -> "(" + p.getName() + "," + p.getAge() + ")")
    .collectors(Collectors.joining("&","persons=[","]");
这将给出
persons=[(joe,34)&(diana,52)&(thomas,19)]
,但我不知道如何在多个person对象的字段上连接,而不是在每个person对象的属性上连接。这就像我需要将人员平面映射到一个属性,然后将人员列表第二次平面映射到下一个属性,然后合并这些输出。这个的语法是什么


Person类非常简单。如果可能的话,我想要一个解决方案,它的编写方式是使用反射在类的所有字段上循环,而不是只检查硬编码的“name”和“age”字段。假设所有字段都是简单的属性,如String或int(没有嵌套的类或集合)。

我想如果有一个class
Person
(如您所述),您需要一个自定义收集器来完成以下任务:

 String result = List.of(new Person(1, "david"), new Person(33, "eugene"))
            .stream()
            .parallel()
            .collect(Collector.of(
                    () -> new StringJoiner[]{new StringJoiner(",", "[", "]"), new StringJoiner(",", "[", "]")},
                    (sj, per) -> {
                        sj[0] = sj[0].add("" + per.getAge());
                        sj[1] = sj[1].add(per.getName());
                    },
                    (left, right) -> {
                        left[0] = left[0].merge(right[0]);
                        left[1] = left[1].merge(right[1]);
                        return left;
                    },

                    x -> "Names = " + x[1].toString() + "&Ages = " + x[0].toString()
            ));
你可以用

String result = persons.stream()
    .flatMap(p -> Stream.of(new AbstractMap.SimpleEntry<>(true, p.getName()),
                            new AbstractMap.SimpleEntry<>(false, ""+p.getAge())))
    .collect(Collectors.collectingAndThen(
        Collectors.partitioningBy(Map.Entry::getKey,
            Collectors.mapping(Map.Entry::getValue, Collectors.joining(",", "[", "]"))),
        m -> "Names="+m.get(true)+"&Ages="+m.get(false)));

您可能需要编写自己的
收集器
。如果流的对象不都是同一类型的,您还需要决定结果应该是什么。对于两个字段(如名称和年龄),您可以使用“Collectors.toMap”和“Collectors.CollectingAnd”编写一个简单的解决方案,但在更一般的情况下,它会变得更复杂,您可能需要像@Andreas所说的那样编写自定义收集器。@只有在绝对确定名称是唯一的情况下,才能使用alainlompo映射。因为世界上不止一个(或多个),你不能保证这一点,所以地图不是一个好的选择。
String result = persons.stream()
    .flatMap(p -> Stream.of(new AbstractMap.SimpleEntry<>("Names", p.getName()),
                            new AbstractMap.SimpleEntry<>("Ages", ""+p.getAge())))
    .collect(Collectors.collectingAndThen(
        Collectors.groupingBy(Map.Entry::getKey,
            Collectors.mapping(Map.Entry::getValue, Collectors.joining(",", "[", "]"))),
        m -> m.entrySet().stream()
              .map(e -> e.getKey()+"="+e.getValue()).collect(Collectors.joining("&"))));