Java 8 函数式编程避免有条件



如何使用纯函数式编程(没有if-conditional)来执行以下transform()方法的等效项。

Meta:我希望标题编辑,我不确定如何用"功能"来表达这个问题

public class Playground {
private static Optional<Map<String,Integer>> transform(List<Tuple<String,Optional<Integer>>> input) {
if (input.stream().anyMatch(t->t.second.isEmpty())) return Optional.empty();
Map<String, Integer> theMap = input.stream()
.map(t -> new Tuple<>(t.first, t.second.get()))
.collect(Collectors.groupingBy(
t1 -> t1.first,
Collectors.mapping(t2 -> t2.second, toSingle())));
return Optional.of(theMap);
}
@Test
public void collect()  {
List<Tuple<String,Optional<Integer>>> input1 = new ArrayList<>();
input1.add(new Tuple<>("foo", Optional.of(1)));
input1.add(new Tuple<>("bar", Optional.empty()));
Optional<Map<String,Integer>> result1 = transform(input1);
assertTrue(result1.isEmpty());
List<Tuple<String,Optional<Integer>>> input2 = new ArrayList<>();
input2.add(new Tuple<>("foo", Optional.of(1)));
input2.add(new Tuple<>("bar", Optional.of(2)));
Optional<Map<String,Integer>> result2 = transform(input2);
assertTrue(result2.isPresent());
assertEquals((int)1, (int)result2.get().get("foo"));
assertEquals((int)2, (int)result2.get().get("bar"));
}
private static class Tuple<T1,T2> {
public T1 first;
public T2 second;
public Tuple(T1 first, T2 second) {
this.first = first;
this.second = second;
}
}
public static <T> Collector<T, ?, T> toSingle() {
return Collectors.collectingAndThen(
Collectors.toList(),
list ->  list.get(0)
);
}
}

这可能对你有用:

private static Optional<Map<String, Integer>> transform(
List<Tuple<String, Optional<Integer>>> input) {
return Optional.of(input)
.filter(t -> t.stream().allMatch(a -> a.second.isPresent()))
.map(
in ->
in.stream()
.filter(t -> t.second.isPresent())
.map(t -> new Tuple<>(t.first, t.second.get()))
.collect(
Collectors.groupingBy(
t1 -> t1.first, Collectors.mapping(t2 -> t2.second, toSingle()))));
}

虽然我的解决方案不能满足您的结果,但我可以使用三元运算符提供解决方案

private static Map<String, Integer> transform(List<Tuple<String, Optional<Integer>>> input) {
return input.stream().anyMatch(t -> t.second.isEmpty()) ? Collections.emptyMap() :
input.stream()
.map(t -> new Tuple<>(t.first, t.second.get()))
.collect(Collectors.groupingBy(
t1 -> t1.first,
Collectors.mapping(t2 -> t2.second, toSingle())));
}
">

纯函数式编程"不一定是质量的标志,本身也不是目的。

如果你想使代码更简单、更高效,其中可能包括摆脱 if 条件,特别是当它对源数据进行第二次迭代时,你可以通过各种方式做到这一点。 例如

private static <K,V> Optional<Map<K,V>> transform(List<Tuple<K,Optional<V>>> input) {
final class AbsentValue extends RuntimeException {
AbsentValue() { super(null, null, false, false); }
}
try {
return Optional.of(input.stream().collect(Collectors.toMap(
t1 -> t1.first,
t2 -> t2.second.orElseThrow(AbsentValue::new),
(first,next) -> first)));
} catch(AbsentValue av) {
return Optional.empty();
}
}

当空可选确实是例外情况时,您可以将通过异常标记作为方法协定的一部分,例如

public static class AbsentValueException extends RuntimeException {
}
private static <K,V> Map<K,V> transform(List<Tuple<K,Optional<V>>> input)
throws AbsentValueException {
return input.stream().collect(Collectors.toMap(
t1 -> t1.first,
t2 -> t2.second.orElseThrow(AbsentValueException::new),
(first,next)->first));
}
@Test(expected = AbsentValueException.class)
public void collect1() {
List<Tuple<String,Optional<Integer>>> input1 = new ArrayList<>();
input1.add(new Tuple<>("foo", Optional.of(1)));
input1.add(new Tuple<>("bar", Optional.empty()));
Map<String,Integer> result1 = transform(input1);
}
@Test
public void collect2() {
List<Tuple<String,Optional<Integer>>> input2 = new ArrayList<>();
input2.add(new Tuple<>("foo", Optional.of(1)));
input2.add(new Tuple<>("bar", Optional.of(2)));
Map<String,Integer> result2 = transform(input2);
assertEquals((int)1, (int)result2.get("foo"));
assertEquals((int)2, (int)result2.get("bar"));
}

更好的是首先不要将可选项放入元组列表中。

最新更新