Java 8:链消费者<y>到函数<x,y> </x,y> </y>

时间:2013-12-13 16:03:58

标签: java lambda java-8

探索Java 8的新功能,我偶然希望通过将Consumer<X>链接到Consumer<Y>来创建Function<X,Y>

这有意义吗?如果是这样,一个好的(一般)解决方案会是什么样的?


我尝试了什么(而不是一个例子的特例):

鉴于

@FunctionalInterface
public interface PartialFunction<X, Y> {
    Y apply(X x) throws Exception;
}

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);
    }
}

我的最终用法如下:

files.forEach(PartialFunctions.<File, BufferedImage>acceptOnSuccess(
        ImageIO::read, images::add));

然而,对显式通用规范的需求并不是最佳的。 希望有更好的东西吗?

4 个答案:

答案 0 :(得分:9)

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(...)
}

如果添加一个忽略空值作为输入的收集器,它会更好。

编辑:我在没有语法检查或编译的情况下写了这个,所以不完全确定默认位置,以及编译器是否可以成功推断出链式函数类型参数。

答案 1 :(得分:4)

您可以扩展Function界面,如下所示:

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));};
    }

}

然后经常使用它:

ComposableFunction<Throwable, String> getMessage = Throwable::getMessage;
Consumer<String> log = System.out::println;
Consumer<Throwable> logMessage = getMessage.andThen(log);

答案 2 :(得分:1)

你可以试试这样的东西吗?

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);
}

答案 3 :(得分:0)

另一个选项(更一般的情况)是使用new Function<X,Y>(...).andThen(new Function<Y,Z>(...))。我不会将消费者和功能混合在一起,而是将链接功能混合到消费者身上(他们也可以选择链接)。