Niclas Hedhman a écrit :
> Most (all?) Iterables in Core was replaced before.

There still are some leftovers here and there.
I started with TypeLookup where I removed some of the Stream
multi-iterations and added more caching, optimising frequently invoked
code paths. There's still room for improvement.

> For exceptions,
> first of all, I think almost all exceptions in Zest are RuntimeExceptions
> and should not cause much problem. For IOException and such, I typically
> wrap in UndeclaredThrowableException if the cause/use is unclear and catch
> that in the caller.

We use core/io in EntityStore and BackupRestore interfaces.

These APIs are meant to transfer large datasets where each party has
exceptions to catch and resources to cleanup.

[1] If we forget that for a moment we could write something like:

interface EntityStore {
  Stream<EntityState> entityStates();
}
interface BackupRestore {
  Stream<String> backup();
  void restore(Stream<String> states);
}

Streams are AutoCloseables, so they can be used with try-with-resources
or simple try/catch. Implementations could register a callback with
Stream::onClose() to clean up resources.

Both EntityStore and BackupRestore implementations could also wrap
checked exceptions in unchecked ones.
BTW, for IOExceptions we should prefer Java 8 UncheckedIOException.

Javadoc for EntityStore and BackupRestore should then advertise that
consuming the stream may throw UncheckedIOExceptions and that the
Streams must be closed properly. Like the ones created by java.nio.Files
for example.

That way the only thing we miss compared to core/io is explicit handling
of both producer and consumer exceptions around each item in the stream
on the consumer side.

[2] We could go one step further and write something like:

interface EntityStore {
  Stream<Supplier<EntityState>> entityStates();
}
interface BackupRestore {
  Stream<Supplier<String>> backup();
  void restore(Stream<Supplier<String>> states);
}

so that exceptions and resource cleanup can be handled around fetching
each item in the stream.

[3] If we want to mimic core/io and use checked exceptions we could go
even further and write:

interface EntityStore {
  Stream<ThrowingSupplier<EntityState, IOException>> entityStates();
}
interface BackupRestore {
  Stream<ThrowingSupplier<String, IOException>> backup();
  void restore(Stream<ThrowingSupplier<String, IOException>> states);
}
ThrowingSupplier<T, ThrowableType extends Throwable> extends Supplier<T> {
    T get() throws ThrowableType;
}

In both [2] & [3] cases we could use some EntityStateSupplier and
StringStateSupplier types to reduce API clutter a bit.

My gut feel is that [2] is acceptable for EntityStore and BackupRestore
use cases. We could also drop the ability to handle producer exceptions
around each item when consuming and go for [1].

I'll experiment with [1] and see what comes up out of it.

Cheers

/Paul



Reply via email to