Add IOFunction and {Byte,Char}Source.read(IOFunction)
See original GitHub issuetl;dr This fixes part of Java 8’s functional mapping combined with IOException, which is currently a pain.
In this Java 8 world, I found useful to have an interface called IOFunction
that is basically Function
that can throw IOException
.
Typical form:
import java.io.IOException;
@FunctionalInterface
public interface IOFunction<F, T> {
T apply(F input) throws IOException;
}
Until here, there’s nothing really interesting with this interface.
What makes it interesting is coupling it with ByteSource
and CharSource
to have a very quick access to a parsed object from those ByteSource
and CharSource
.
The typical implementation is rather obvious:
// In ByteSource
public <T> T read(IOFunction<InputStream, T> function) {
try (InputStream in = openStream()) {
return function.apply(in);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
“Hey, but that’s what ByteProcessor
and LineProcessor
do!”
Well, yes and no.
ByteProcessor
takes control of things I don’t want it to take control, such as the size of the chunks that need to be processed. Often ByteProcessor
requires me to internally buffer bytes that overlap between chunks. Same thing for LineProcessor
: not every text file is line-based. For instance, huge one-line JSON files, which happen every so often.
Also, both ByteProcessor
and CharProcessor
are 2-methods interfaces, meaning that they can’t be @FunctionalInterface
, so I can’t simply pass a lambda or a method reference to the read
methods.
Finally the IOException
isn’t manageable in stream-like API without much burden. This is why UncheckedIOException
was introduced (see java.nio.file.Files.lines
, for instance).
See how IOFunction
makes it easy:
Optional<CharSource> source = ... ;
Optional<Properties> properties = source.map(s -> s.read(this::loadProperties));
Properties loadProperties(Reader reader) throws IOException {
Properties properties = new Properties();
properties.load(reader);
return properties;
}
Look! No resource management, clean *Source
usage. Clean mapping (as in no inner try
), I didn’t use any complex structure: just a simple method making something obvious. Try making the same with CharProcessor
. Yup, it’s a pain 😦 Outside of CharSource
? Well, what’s the point to have the resource managed for you then if you don’t use it? 😛
So to ease the use of ByteSource
and CharSource
with Java 8, please think about making such IOFunction
. Of course It’s also OK to have a FromBytesFunction
for ByteSource
and FromCharsFunction
for CharSource
(this naming is similar to the ToIntFunction
style, but it seems weak, anything else is welcome, ofc.).
Note that I’ve edited to make the intent of the method clearer: mapping inside stream-like API. It seems this wasn’t clear at first: I thought the whole “Java 8 context” was clear enough, I was wrong.
Issue Analytics
- State:
- Created 6 years ago
- Comments:6 (4 by maintainers)
Top GitHub Comments
With the presence of try-with-resources, I’m not sure I understand what’s painful anymore about resource management that requires the intervention of lambdas at all. I’m not sure why you wouldn’t just write
The addition of the lambdas doesn’t seem to buy much; the only thing you’re doing is eliminating the try-with-resources block, which is not really adding that much complexity here. Am I missing something?
Closing due to @lowasser’s alternatives/concerns