question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add IOFunction and {Byte,Char}Source.read(IOFunction)

See original GitHub issue

tl;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:closed
  • Created 6 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
lowassercommented, Jun 17, 2017

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

CharSource source = ... ;
Properties props = loadProperties(source);

Properties loadProperties(CharSource source) throws IOException {
  try (Reader reader = source.openReader()) {
    Properties properties = new Properties();
    properties.load(reader);
    return properties;
  }
}

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?

0reactions
ronshapirocommented, Aug 8, 2019

Closing due to @lowasser’s alternatives/concerns

Read more comments on GitHub >

github_iconTop Results From Across the Web

read
The read() function shall attempt to read nbyte bytes from the file associated with the open file descriptor, fildes, into the buffer pointed...
Read more >
Reading from file using read() function - Stack Overflow
Read Byte by Byte and check that each byte against '\n' if it is not, then store it into buffer if it is...
Read more >
read()--Read from Descriptor - IBM
From the file or socket indicated by file_descriptor, the read() function reads nbyte bytes of input into the memory area indicated by buf....
Read more >
How to Reuse Functions That You Create In Scripts - Earth Lab
How to Source Functions in R · Open your .Rmd file or R script. · At the top of your file, add the...
Read more >
READ Function (Query) - Dynamics NAV - Microsoft Learn
This article describes how the READ function (Query) reads data from a row in the resulting dataset of a query.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found