我有很多这些:
Validation<String, Foo> a;
Validation<String, Foo> b;
Validation<String, Foo> c;
以下是他们的一些方法:
boolean isValid();
boolean isInvalid(); // === !isValid()
String getError();
现在,我试图这样做:
Stream.of(a, b, c).reduce(
Validation.valid(foo),
(a, b) -> a.isValid() && b.isValid()
? Validation.valid(foo)
: String.join("; ", a.getError(), b.getError())
);
明显的问题是,如果只有a
或b
中的一个出错,那么就会出现一个不必要的;
。但是有一个更严重的问题:如果验证有效,getError()
会抛出异常。
有没有办法可以编写这个lambda(或使用io.vavr.control.Validation library中的其他内容)而不会全部4个案例(a && b
,a && !b
,!a && b
,{ {1}})明确吗?
修改
为了更清楚,我最终想要!a && !b
的结果。我认为它的行为就像一个“monad”,但我不确定。
答案 0 :(得分:1)
我认为您尝试实现的目标在Validation
域中更容易解决。
首先,将您的Either
流转换为Stream<Either<String, Foo>> eithers = Stream.of(a, b, c)
.map(Validation::toEither);
s的流:
Either<String, Foo> result = Either.sequence(eithers)
.mapLeft(seq -> seq.collect(Collectors.joining("; ")))
.map(combinator); // fill in with combinator function that converts
// a Seq<Foo> into a single Foo
然后合并它们:
Foo
由于您没有指定如何将多个有效Either.Left
个对象合并为一个,我将其打开以供您填写上述示例中的组合函数。
Either.sequence(...)
如果任何提供的eithers为左侧,则返回包含左侧值序列的Either.Right
,或者{Validation.sequence(...)
会将多个eithers减少为一个{1}}包含一个(可能是空的)所有正确值的序列,如果提供的eithers的 none 是左侧。
有一个{{3}}方法可以在不转换为Either域的情况下执行此操作(我在创建原始答案时不知何故错过了 - 感谢指出):
Validation<Seq<String>, Seq<Foo>> validations = Validation.sequence(
Stream.of(a, b, c)
.map(v -> v.mapError(List::of))
);
Validation<String, Foo> result = validations
.mapError(errors -> errors.collect(Collectors.joining("; ")))
.map(combinator); // fill in with combinator function that converts
// a Seq<Foo> into a single Foo
您说Foo
个实例是相同的,这意味着您可以使用Seq::head
代替组合函数。但是你需要注意不要使用空的验证序列作为输入,因为在这种情况下Seq::head
会抛出NoSuchElementException
。
答案 1 :(得分:0)
如您所见,import re
text = 'Version: 10.2.4.110\r\nPkg name: XXXX-10.2.4-Agent-Linux-x86_64\r\nRevision: 110\r\nPatch version: 23'
replaced = re.sub(r'(?:Version:\s?((?:\d+\.){3})(?:[^\r\n]+\r?\n){3}Patch version:\s?(\d+))', '\g<1>\g<2>', text)
print(replaced) //10.2.4.23
的输出为字符串,错误列表以reduce
分隔。
您正在混合累加器参数:
;
是当前减少的部分结果a
是您正在迭代的对象本身我会做这样的事情:
b
答案 2 :(得分:0)
Collectors.groupingBy()怎么样?我认为你仍然可以改进字符串的错误部分并加入它们,下面代码的输出是:
{false=[SomeException, ReallyBadProblem], true=[3, 5]}
代码示例:
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toSet;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Validation<String,Integer> a = new Validation<>(true, null, 3);
Validation<String,Integer> b = new Validation<>(true, null, 5);
Validation<String,Integer> c = new Validation<>(false, "SomeException", null);
Validation<String,Integer> d = new Validation<>(false, "ReallyBadProblem", null);
//Stream.of(a,b,c).collect(Collectors.groupingBy(v->v.isValid(), v->v.));
TreeMap<Boolean, Set<Object>> map = Stream.of(a,b,c,d).collect((groupingBy(v->v.isValid(), TreeMap::new,
mapping(v-> { return v.isValid() ? v.valid() : v.getError();}, toSet()))));
System.out.println(map);
}
public static class Validation<E, T>{
boolean valid;
T validVal;
String error;
public Validation(boolean valid, String error, T validVal) {
super();
this.valid = valid;
this.error = error;
this.validVal = validVal;
}
/**
* @return the valid
*/
public boolean isValid() {
return valid;
}
/**
* @param valid the valid to set
*/
public void setValid(boolean valid) {
this.valid = valid;
}
/**
* @return the error
*/
public String getError() {
return error;
}
/**
* @param error the error to set
*/
public void setError(String error) {
this.error = error;
}
public T valid() {
return validVal;
}
}
}
答案 3 :(得分:0)
这是我结束的方式,虽然我认为@Nandor(接受的答案)说得对。 (他的解决方案基于io.vavr.control.Validation
的更新版本而不是我可以使用的版本(仍为javaslang.control.Validation
)。我发现mapLeft
已重命名为mapErrors
但是,有一些与Seq
操作相关的缺失位。由于缺乏对Java的熟悉,我无法解决我在这条路线上的错误。)
Validation<String, AdRequest> validation =
Stream.of(
validateTargetingRequest(adRequest),
validateFlightRequest(adRequest, ad),
validateCreativeRequest(adRequest)
).reduce(
Validation.valid(adRequest),
(a, b) -> {
if (a.isValid() && b.isValid()) {
return Validation.valid(adRequest);
}
if (a.isInvalid() && b.isInvalid()) {
return Validation.invalid(String.join("; ", a.getError(), b.getError()));
}
// This seemingly overcomplicated structure was necessitated by the fact that getError
// throws an exception when called on an Valid form of Validation.
return a.isInvalid() ? a : b;
}
);