2

我正在使用 Java 8 以及来自 Apache Commons Lang3 的 Pair。

我要做的第一件事是从 a 获取流List<T>并获取 aFunction<T,U>并最终创建一个List<Pair<T,U>>. 目前我正在创建一个Function<T,Pair<T,U>>我想要的特定类型并使用它来映射流。我想要的是这样的:

public static <T, U> Function<T, Pair<T, U>> tupledResult(final Function<T, U> generator) {
    Objects.requireNonNull(generator);
    return (T t) -> new ImmutablePair<>(t, generator.apply(t));
}

下一个问题是,现在我有了一个List<Pair<T, U>>我想能够用来foreach应用一个BiConsumer<T,U>(类似于tupledScala 中的函数)。我想它看起来像:

public static <T, U> Consumer<Pair<T, U>> tupled(final BiConsumer<T, U> consumer) {
    Objects.requireNonNull(consumer);
    return (final Pair<T, U> p) -> consumer.accept(p.getLeft(), p.getRight());
}

Apache Commons Lang3 中有什么可以做到这一点还是我应该自己动手?如果是后者,这是对贡献有用的东西还是一个不好的解决方案?

例子

这是我想要实现的目标:

private void doStuff(final List<Thing> things) {
    final List<Pair<Thing, Other>> otherThings = things.stream()
        .map(tupledResult(ThingHelper::generateOther))
        .collect(Collectors.toList());
    otherThings.stream().forEach(tupled((final Thing thing, final Other other) -> {
        doSomething(thing, other);
    }));
    otherThings.stream().forEach(tupled((final Thing thing, final Other other) -> {
        doSomethingElse(thing, other);
    }));
}

这里的要点ThingHelper.generateOther是相对昂贵,我只想做一次。也doSomething必须先应用到所有东西,然后再应用doSomethingElse

这些对永远不会离开此方法的范围,我也不想重载方法来获取一对。在这种情况下,我真的不在乎这对缺乏语义,重要的是顺序。doSomething并且doSomethingElse是提供语义的人。

4

2 回答 2

3

Apache Commons Lang3 中不存在此类方法,因为该库与 Java 6 兼容,但您想要的方法必须返回java.util.function仅在 Java 8 中出现的包对象。

如果您的Thing对象没有重复,那么在您的情况下使用它是很自然的Map

private void doStuff(final List<Thing> things) {
    final Map<Thing, Other> otherThings = things.stream()
        .collect(Collectors.toMap(Function.identity(), ThingHelper::generateOther));
    otherThings.forEach((final Thing thing, final Other other) -> {
        doSomething(thing, other);
    });
    otherThings.forEach((final Thing thing, final Other other) -> {
        doSomethingElse(thing, other);
    });
}

甚至更短:

private void doStuff(List<Thing> things) {
    Map<Thing, Other> otherThings = things.stream()
        .collect(toMap(x -> x, ThingHelper::generateOther));
    otherThings.forEach(this::doSomething);
    otherThings.forEach(this::doSomethingElse);
}

这样你就不需要包装器Map.forEachBiConsumer,因为Collectors.toMap第二个参数基本上取代了你的tupledResult.

于 2015-11-11T02:55:05.590 回答
0

在 FunctionalJava (https://github.com/functionaljava/functionaljava)中,我会这样做:



    private void doStuff(final List<Thing> things) {
        fj.data.List<P2<Thing, Other>> otherThings = fj.data.List.list(things)
            .map(t -> P.p(t, ThingHelper.generateOther.apply(t)));
        otherThings.forEachDoEffect(p -> doSomething(p._1(), p._2()));
        otherThings.forEachDoEffect(p -> doSomethingElse(p._1(), p._2()));
    }

元组被支持为具有 P、P1、P2 等类的产品 ( https://functionaljava.ci.cloudbees.com/job/master/javadoc/ )。

于 2015-11-11T02:46:44.893 回答