Reputation: 46876
How can I format a string with streams, without using lambda? I've been looking at Formatter
but can't find any method that would only take a single string... so I could do:
Set<String> imported = new HashSet<>();
extendedModels.stream().filter((x)->imported.add(x))
.map(new Formatter("import {%1$s} from './%1$s';\n")::format);
I'm just starting with Java 8 so not sure if the above is a right syntax (referencing a method of an object).
Specifically I look for a way to format the strings without the lambda expression. The reason is brevity - because, the pre-Java 8 form is just:
for (String m : extendedModels)
if (imported.add(m))
tsWriter.write(String.format("import {%1$s} from './%1$s';\n", m));
I'm trying to go through a list of strings, reduce them to unique*) ones, and then use them in an formatted string, which will ultimately written to a Writer
. Here's what I have now:
This would work but I'd have to handle an IOException
in forEach
:
extendedModels.stream().filter(imported::add)
.map((x)->{return String.format("import {%1$s} from './%1$s';\n", x);})
.forEach(tsWriter::write);
So for now I use this:
tsWriter.write(
extendedModels.stream()
.filter(imported::add)
.map((x)->{return String.format("import {%1$s} from './%1$s';\n", x);})
.collect(Collectors.joining())
);
*) The uniqueness is across multiple sets, not just the extendedModels
so I don't want to use some sort of unique
stream util.
Upvotes: 1
Views: 9991
Reputation: 298439
Note that while .filter(imported::add)
looks like a clever trick, it’s a discouraged technique, as it creates a stateful predicate. If all you want, is uniqueness, just use .distinct()
instead. If you need imported
later-on, create it with a straight-forward Collection operation, i.e. imported = new HashSet<>(extendedModels)
and stream over the Set
.
So if your Writer
is going to write into a file or any path, there is a FileSystem
implementation for, a simple solution is
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());
or, if you don’t need the imported
Set later-on:
Files.write(path, () -> extendedModels.stream().distinct()
.<CharSequence>map(x->String.format("import {%1$s} from './%1$s';\n", x)).iterator());
If there is no Path
, i.e. you can’t avoid using a predefined Writer
, you can use a Formatter
, but have to care about not missing an exception:
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();
There is no way to provide a bound parameter to a method reference, but since the tokens String
, format
and the string literal are unavoidable, there is not much potential saving anyway.
Upvotes: 0
Reputation: 7108
As for avoiding using a lambda expression and using only method references, you need to extract the formatting part to a static or an instance method and reference it using a method reference expression:
static String formatImportStatement(String imp) {
return String.format("import {%1$s} from './%1$s';\n", imp);
}
then .map(YourClass::formatImportStatement)
. Or you could also extract the labmda itself to a variable like this:
Function<String, String> importFormatter =
(s) -> String.format("import {%1$s} from './%1$s';\n", s);
then use it directly: .map(importFormatter)
.
Regarding exceptions:
You can use a delegating Writer
wrapper which softens (converts checked to unchecked) exceptions and undeclares the checked IOException
-s from it's method signatures, then use that with .forEach(softeningWriter::write)
.
You can also use a lambda wrapper factory to wrap your lambda to soften the exceptions like the LambdaExceptionUtil
class in this answer, with the .forEach(rethrowConsumer(tsWriter::write))
pattern.
And your third solution could also work if you don't mind collecting the import statements to a String
using Collectors.joining()
first.
Unfortunately, you need to work around the checked exceptions (at least in Java8 as of today). Maybe a future version of Java will do something about this legacy, but this is not guaranteed to happen as far as I know.
Upvotes: 3