在 Java 中创建元组和元组函数的辅助方法?
Helper methods for creating tuples and tupled functions in Java?
我正在使用 Java 8 以及来自 Apache Commons Lang3 的 Pair。
我要做的第一件事是从 List<T>
获取一个流并获取 Function<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>
(类似于 tupled
函数在斯卡拉)。我想它看起来像:
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
是提供语义的。
在 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/) 的产品。
Apache Commons Lang3 中不存在此类方法,因为此库与 Java 6 兼容,但您需要的方法必须 return java.util.function
包的对象,这些对象仅出现在 Java8.
如果您的 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.forEach
already accepts BiConsumer
and Collectors.toMap
第二个参数基本上取代了你的 tupledResult
.
我正在使用 Java 8 以及来自 Apache Commons Lang3 的 Pair。
我要做的第一件事是从 List<T>
获取一个流并获取 Function<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>
(类似于 tupled
函数在斯卡拉)。我想它看起来像:
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
是提供语义的。
在 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/) 的产品。
Apache Commons Lang3 中不存在此类方法,因为此库与 Java 6 兼容,但您需要的方法必须 return java.util.function
包的对象,这些对象仅出现在 Java8.
如果您的 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.forEach
already accepts BiConsumer
and Collectors.toMap
第二个参数基本上取代了你的 tupledResult
.