【问题标题】:How can one rewrite Java 8 stream() using Java 7 patterns?如何使用 Java 7 模式重写 Java 8 stream()?
【发布时间】:2017-10-04 08:13:17
【问题描述】:

我想重写以下 Java 8 代码以符合 Java 7:

System.out.println("items: " + stringList.stream().collect(Collectors.joining(", ")));

一种天真的方式是:

System.out.print("items: ");
String joiner = "";
for (String item : stringList) {
  System.out.print(joiner + item);
  joiner = ", ";
}
System.out.println();

有哪些替代模式可以完成这项任务?例如,是否可以使用命令模式以某种方式传递封装为对象的 print()?

【问题讨论】:

  • StringBuilder ....
  • 或者干脆看一下JDK 8 StringJoiner类的源码,写一个JDK 7版本的吧
  • 您的代码几乎没问题。我要做的唯一更改是分别更改System.out.print joineritem,以避免不必要的字符串创建。 StringBuilder 在这里效率较低,因为您只需缓冲字符、创建字符串、写入另一个字符缓冲区;相反,只需直接写入最终缓冲区(就像您已经在做的那样)。

标签: java java-8 java-7 command-pattern


【解决方案1】:
StringBuilder sb = new StringBuilder("items: ");
for (String item : stringList) {
  sb.append(item).append(", ");
}
if (!stringList.isEmpty()) {
    sb.setLength(sb.length() - 2);
}
System.out.println(sb.toString());

评论:

  1. StringBuilder 使用构造函数参数进行初始化
  2. append 返回一个 StringBuilder,这样你就可以将它们链接起来
  3. 需要删除最后两个字符以避免尾随“,”
  4. stringList 可能为空,因此请仅删除尾随逗号(如果不是)
  5. 这可能会更有效,因为您可以避免大量临时的 String 创建和复制。

【讨论】:

  • 或者,如果!sb.isEmpty(),则可以先附加冒号分隔符,然后始终附加下一项。
  • 谢谢。我编辑了我的原始帖子以删除循环字符串创建,因为它不是我要引起注意的部分。我的问题实际上是如何使用替代设计模式来完成给定的任务。例如,将封装函数作为变量传递的命令模式。
【解决方案2】:

如果你在类路径上有番石榴(你真的应该是 IMO),那么它有同样流畅的加入方式,但与 jdk-7 兼容(显然你需要一个版本的番石榴是否兼容 jdk-7):

 String joined = Joiner.on(",").join(stringList);

【讨论】:

    【解决方案3】:

    几乎相同,只是避免串联:

    System.out.print("items: ");
    boolean first = true;
    for (String item : stringList) {
        if (! first)
            System.out.print(", ");
        System.out.print(item);
        first = false;
    }
    System.out.println();
    

    注意:布尔值的含义可以颠倒,所以我们不需要使用否定,但为了便于阅读,我更喜欢这种方式。

    【讨论】:

      【解决方案4】:

      请注意,您的原始 Java 8 代码

      System.out.println("items: " + stringList.stream().collect(Collectors.joining(", ")));
      

      可以简化为

      System.out.println("items: " + String.join(", ", stringList));
      

      在 Java 7 中,您必须使用 StringBuilder 才能有效地执行相同的操作,但您可以将其封装在实用程序类中,类似于 Java 8 的 StringJoiner。使用具有相同 API 的类可以创建与 Java 7 兼容的代码,这些代码仍然很容易适应使用 Java 8 对应物。

      但是,这不太可能是应用程序中对性能最关键的部分,因此,您可以使用务实的方法:

      String s = stringList.toString();
      System.out.append("items: ").append(s, 1, s.length()-1).println();
      

      这根本不会打印字符串表示的[],从而生成所需的逗号分隔列表。虽然这种字符串表示不是强制性的,但很难找到一个不遵守此约定的有用集合实现示例(如果您使用了这样的类,您会知道)。

      关于您更新的问题,指的是“命令模式”之类的东西,嗯,这与您问题的 Stream 代码没有任何关系,但已经有抽象,如上面代码中使用的抽象。

      你可以创建一个类似的方法

      static <A extends Appendable> A join(A target, CharSequence sep, List<?> data) {
          try {
              CharSequence currSep = "";
              for(Object item: data) {
                  target.append(currSep).append(item.toString());
                  currSep = sep;
              }
              return target;
          } catch(IOException ex) {
              throw new IllegalStateException(ex);
          }
      }
      

      它提供了一些灵活性,例如你可以用它来获取String:

      String s = join(new StringBuilder(), ", ", stringList).toString();
      System.out.println("items: " + s);
      

      或者只是打印:

      join(System.out.append("items: "), ", ", stringList).println();
      

      【讨论】:

        猜你喜欢
        • 2019-06-14
        • 1970-01-01
        • 2018-05-17
        • 2017-01-31
        • 1970-01-01
        • 2018-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多