使用流时如何格式化Java属性对象的内容?

使用流时如何格式化Java属性对象的内容?,java,properties,java-stream,Java,Properties,Java Stream,静态方法System.getProperties()返回一个Properties对象,其中包含作为键值对的系统属性 在SO post中,Radiodef提供了一种工作正常的解决方案,可以对其进行增强,以对输出进行排序: System.getProperties() .entrySet() .stream() .map(e -> e.getKey() + ": " + e.getV

静态方法System.getProperties()返回一个Properties对象,其中包含作为键值对的系统属性

在SO post中,Radiodef提供了一种工作正常的解决方案,可以对其进行增强,以对输出进行排序:

        System.getProperties()
                .entrySet()
                .stream()
                .map(e -> e.getKey() + ": " + e.getValue())
                .sorted()
                .forEach(System.out::println);
下面是该语句生成的排序输出的一小部分:

我试图修改上面的语句,使输出中的属性值左对齐,但没有成功。由于java.vm.specification.version恰好是最长的系统属性键,因此上面显示的输出的格式化表示应该如下所示:

显然,棘手的部分是在格式化输出之前,以某种方式知道最长键的长度。关于如何使用流在单个语句中实现这一点的任何建议,或者是不可能的

更新:


我忘了在最初的帖子中声明,另一个约束是,解决方案也应该使用并行流。我为疏忽表示歉意。

如果您想尝试一个声明,您可以尝试:

    AtomicInteger len = new AtomicInteger();
    System.getProperties()
          .entrySet()
          .stream()
          .sorted((e1, e2) -> Integer.compare(e2.getKey().toString().length(), e1.getKey().toString().length()))
          .peek(e -> len.set(Math.max(len.get(), e.getKey().toString().length())))
          .map(e -> String.format("%-" + len.get() + "s: %s", e.getKey(), e.getValue()))
          .sorted()
          .forEach(System.out::println);
它涉及两种排序,因此元素将首先通过查看来找到最大长度

这样做并非不可能,但我确实不建议这样做,因为引入了一种不必要的排序。

这样做:

    AtomicInteger len = new AtomicInteger();
    ((Map<String, String>)(Map)System.getProperties())
    .entrySet()
    .parallelStream()
    .peek(e -> len.set(Integer.max(e.getKey().length(), len.get())))
    .sorted((e1, e2) -> (e1.getKey()).compareTo(e2.getKey()))
    .forEachOrdered(e -> System.out.printf("%-" + len + "s %s%n", e.getKey() + ":", e.getValue()));
AtomicInteger len=新的AtomicInteger();
((Map)(Map)System.getProperties())
.entrySet()
.parallelStream()
.peek(e->len.set(Integer.max(e.getKey().length(),len.get()))
.sorted((e1,e2)->(e1.getKey()).compareTo(e2.getKey())
.forEachOrdered(e->System.out.printf(“%-”+len+“s%s%n”,e.getKey()+“:”,e.getValue());

只需将步骤分开即可

  • 确定最大密钥长度
  • 使用长度设置所有条目的格式
  • 例如

    int maxLen = System.getProperties().keySet()
        .stream().mapToInt(k -> ((String)k).length()).max().orElse(0);
    String format = "%-"+maxLen+"s %s%n";
    System.getProperties().forEach((k,v)->System.out.printf(format, k+":", v));
    
    请注意,这也会打印左对齐的冒号,如示例输出中所示。当您想要对该映射进行排序和/或确保这两个操作之间没有修改时,您可以使用

    @SuppressWarnings("unchecked") Map<String,String> map
                                       = new HashMap<>((Map)System.getProperties());
    int maxLen = map.keySet().stream().mapToInt(String::length).max().orElse(0);
    String format = "%-"+maxLen+"s %s%n";
    map.entrySet().stream()
       .sorted(Map.Entry.comparingByKey())
       .forEach(e -> System.out.printf(format, e.getKey()+":", e.getValue()));
    

    没有简单的方法可以做到这一点。您必须提前知道最长钥匙的长度。差不多就这样了,为什么在一个声明中?首先找到最大长度,然后,在第二遍中,填充所有字符串…@Federicoperaltachaffner是的,我意识到,如果在处理流之前已经知道最长键的长度,这很简单,但我想知道是否也可以通过处理流来实现。虽然这是一个有趣的挑战,这也是一个很好的例子,说明了两条流或两个循环比试图将其强制放入一个方法链要好得多。@VGR问题不是寻求解决问题的其他方法的建议;它只是简单地询问如何在一次传递中使用流来完成,几个用户提供了解决方案。当然,我怀疑在现实世界中是否有人会使用流来解决这个特定问题,但是下面的解决方案仍然很有趣,并且具有普遍的适用性。除了使用parallelStream()之外,您的解决方案工作得很好,我已经更新了OP,以澄清这一点。对此我深表歉意。您的方法也可以调整为使用parallelStream()吗?Evgeniy Dorofev的解决方案更好,因为它只涉及一种排序。对于并行流,我认为并行的功能对您没有好处,因为您需要按顺序打印输出
    forEachOrdered()
    将保证并行排序,并在
    线程之间进行锁定和同步。这使得它相当于一个单线程流,但也有开销。明白了,我意识到在现实世界中,使用parallelStream()处理系统属性可能比stream()慢。我这篇文章的核心目标是找出如何根据流处理过程中确定的信息格式化流的输出,而使用System.getProperties()正是实现这一点的工具。我明白了。您可以使用
    forEachOrdered()
    作为终端操作符,以便为并行流输出内容。我更新了OP,以澄清在使用parallelStream()而不是stream()时,解决方案也应该有效。但是,您的解决方案似乎也可以与parallelStream()一起使用。这种行为是有保证的,还是我只是幸运地测试了你的代码?forEachOrdered保证了排序中心的正确顺序这是不并行兼容的,因为
    len.set(Integer.max(e.getKey().length(),len.get())
    包含
    get
    set
    ,所以它不是原子更新。但是使用正确的原子更新并不难:
    len.acgregateAndget(e.getKey().length(),Integer::max)
    …OP声明“关于如何使用流在单个语句中实现这一点的任何建议,或者这是不可能的?”,因此“只需分离步骤”不是解决方案。但最终,在单个语句中就有了解决方案(虽然非常复杂),仍然需要两次通过。一次通过是不可能的,尽管我不知道如何证明它。@skomisa:“……或者它不可能吗?”这个问题得到了准确的回答:“一步完成是不可能的……”
    ((Map<String,String>)(Map)System.getProperties()).entrySet().stream()
       .collect(collectingAndThen(toMap(Map.Entry::getKey,Map.Entry::getValue), map -> {
            int maxLen = map.keySet().stream().mapToInt(String::length).max().orElse(0);
            String format = "%-"+maxLen+"s %s%n";
            map.entrySet().stream()
               .sorted(Map.Entry.comparingByKey())
               .forEach(e -> System.out.printf(format, e.getKey()+":", e.getValue()));
            return null;
       }));