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