Java 8流和& Formatter或String :: format

时间:2016-10-09 00:35:16

标签: java-8 java-stream formatter

如何使用流格式化字符串,而不使用lambda?我一直在关注Formatter,但无法找到任何只需要一根字符串的方法......所以我可以这样做:

Set<String> imported = new HashSet<>();
extendedModels.stream().filter((x)->imported.add(x))
    .map(new Formatter("import {%1$s} from './%1$s';\n")::format);

我刚开始使用Java 8,所以不确定上面是否是正确的语法(引用对象的方法)。

具体来说,我寻找一种在没有lambda表达式的情况下格式化字符串的方法。原因很简单 - 因为,Java 8之前的表单只是:

for (String m : extendedModels)
    if (imported.add(m))
        tsWriter.write(String.format("import {%1$s} from './%1$s';\n", m));

与问题无关的细节:

我试图查看字符串列表,将它们缩减为唯一的*),然后在格式化的字符串中使用它们,最终写入Writer。这就是我现在所拥有的:

这样可行,但我必须处理IOException中的forEach

extendedModels.stream().filter(imported::add)
.map((x)->{return String.format("import {%1$s} from './%1$s';\n", x);})
.forEach(tsWriter::write);

所以现在我用这个:

tsWriter.write(
    extendedModels.stream()
        .filter(imported::add)
        .map((x)->{return String.format("import {%1$s} from './%1$s';\n", x);})
        .collect(Collectors.joining())
);

*)唯一性是跨多个集合,而不仅仅是extendedModels所以我不想使用某种unique流工具。

2 个答案:

答案 0 :(得分:3)

至于避免使用lambda表达式并仅使用方法引用,您需要将格式化部分提取为静态或实例方法,并使用方法引用表达式引用它:

static String formatImportStatement(String imp) {
    return String.format("import {%1$s} from './%1$s';\n", imp);
}

然后.map(YourClass::formatImportStatement)。或者您也可以将labmda本身提取为如下变量:

Function<String, String> importFormatter = 
    (s) ->  String.format("import {%1$s} from './%1$s';\n", s);

然后直接使用它:.map(importFormatter)

关于例外情况:

您可以使用委托Writer包装器来软化(转换检查到未检查)异常并取消选中已检查的IOException - s方法签名,然后将其与{{1一起使用}}

您还可以使用lambda包装器工厂来包装lambda,以使用.forEach(softeningWriter::write)模式软化此answer中的LambdaExceptionUtil类之类的异常。

如果您不介意首先使用.forEach(rethrowConsumer(tsWriter::write))将导入语句收集到String,那么您的第三个解决方案也可以正常运行。

不幸的是,您需要解决已检查的异常(至少在今天的Java8中)。也许未来的Java版本会对这些遗产做些什么,但据我所知,这并不能保证会发生。

答案 1 :(得分:0)

请注意,虽然.filter(imported::add)看起来像一个聪明的技巧,但它是一种沮丧的技术,因为它创建了一个有状态谓词。如果您想要的是唯一性,请使用.distinct()代替。如果您稍后需要imported,请使用直接的收集操作创建它,即imported = new HashSet<>(extendedModels)并在Set上流式传输。

因此,如果您的Writer要写入文件或任何路径,那么有一个FileSystem实现,一个简单的解决方案就是

Set<String> imported = new HashSet<>(extendedModels);
Files.write(path, () -> imported.stream()
    .<CharSequence>map(x->String.format("import {%1$s} from './%1$s';\n", x)).iterator());

或者,如果您不需要稍后设置imported

Files.write(path, () -> extendedModels.stream().distinct()
    .<CharSequence>map(x->String.format("import {%1$s} from './%1$s';\n", x)).iterator());

如果没有Path,即您无法避免使用预定义的Writer,则可以使用Formatter,但必须注意不要错过异常:

Formatter f=new Formatter(tsWriter);
extendedModels.stream().distinct().forEachOrdered(
    x -> f.format("import {%1$s} from './%1$s';\n", x));
f.flush();
if(f.ioException()!=null) throw f.ioException();

无法为方法引用提供绑定参数,但由于标记Stringformat和字符串文字是不可避免的,因此无论如何都没有太大的潜在保存。