Java 8: Chain consumer <Y> for function <X, Y>
While exploring the new features of Java 8, I came across a desire to create a Consumer<X> by binding Consumer<Y> to Function<X,Y> .
What I tried (rather, a special case with an example):
Considering
@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 get a possible use, for example:
files.forEach(PartialFunctions.<File, BufferedImage>acceptOnSuccess( ImageIO::read, images::add)); However, the need for an explicit general specification is not optimal. Hope something better?
+6
4 answers
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(...) } This will be better if you add a Collector that ignores NULL values as input.
edit: I wrote this without syntax checking or compilation, so I’m not completely sure about the default layout and whether the compiler can successfully determine the parameters of the function chain.
+8
You can extend the Function interface like this:
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 like this:
ComposableFunction<Throwable, String> getMessage = Throwable::getMessage; Consumer<String> log = System.out::println; Consumer<Throwable> logMessage = getMessage.andThen(log); +2
Can you try something like this?
public void lambdaChaining() { System.out.println("\nlambda chaining:"); List<String> l = Arrays.asList("1", "22", "333", "4444", "55555", "666666", "7777777", "88888888", "999999999"); Function<String, ?> f = s -> s.length(); Consumer<String> c = s -> System.out.println(f.apply(s));; l.forEach(c); } +1