Exploring the new features of Java 8, I stumbled the wish to create a Consumer<X>
by chaining a Consumer<Y>
to Function<X,Y>
.
Does this make sense? And if so, how would a good (general) solution look like?
What I've tried (rather a special case by example):
Given
@FunctionalInterface
public interface PartialFunction<X, Y> {
Y apply(X x) throws Exception;
}
and
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
public class PartialFunctions {
public static <X, Y> Function<X, Optional<Y>> withOptionalResults(final PartialFunction<X, Y> funcThatThrows) {
return z -> {
try {
return Optional.of(funcThatThrows.apply(z));
} catch (final Exception e) {
return Optional.empty();
}
};
}
public static <X, Y> Consumer<X> acceptOnSuccess(final PartialFunction<X, Y> g, final Consumer<Y> c) {
return x -> withOptionalResults(x).apply(t).ifPresent(c);
}
}
I end up with a possible usage like:
files.forEach(PartialFunctions.<File, BufferedImage>acceptOnSuccess(
ImageIO::read, images::add));
However, the need for the explicit generic specification is not optimal. Hopefully there is something better?
interface IgnoreThrowing<F,V> extends Function<F,V> {
public default V apply(F from) {
try {
return ignore(from);
} catch(Exception e) {
return null;
}
}
public V ignore(F from) throws Exception;
}
class Throwables {
public static <F,V> Function<F,V> ignore(IgnoreThrowing<F,V> f) {
return f;
}
}
static {
files.map(Throwables.ignore(ImageIO::read)).collect(...)
}
It will get better if you add a Collector that ignores nulls as input.
edit: i wrote this without syntax checking or compiling, so not totally sure about the placement of the default, and whether the compiler can successfully infer the chained function type parameters.
You could extend the Function
interface like so:
public interface ComposableFunction<T, R> extends Function<T, R> {
default Consumer<T> andThen(Consumer<R> after) {
Objects.requireNonNull(after);
return (T t) -> {after.accept(apply(t));};
}
}
And then use it regularly like so:
ComposableFunction<Throwable, String> getMessage = Throwable::getMessage;
Consumer<String> log = System.out::println;
Consumer<Throwable> logMessage = getMessage.andThen(log);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With