Я хотел бы знать масштабируемый и универсальный c способ применения инкрементного filters
к данной коллекции, не теряя причину сбоя, я имею в виду, какой фильтр не соответствует.
Следующий код является упрощением существующего (в нем больше условий и сообщений об ошибках):
public class FailureCause {
public static void main(String[] args) {
validateAtRawWay(asList(201, 300, 450));
validateAtRawWay(asList(20, 30, 40));
validateAtRawWay(asList(400, 1600));
validateAtRawWay(asList(10, 25, 36, 201, 1600));
}
public static void validateAtRawWay(List<Integer> sourceToCheck) {
System.out.println("Initial elements: " + sourceToCheck);
if (!sourceToCheck.stream()
.filter(FailureCause.upTo100())
.findAny()
.isPresent()) {
System.out.println("ERROR: no numbers less or equals than 100 were found");
return;
}
if (!sourceToCheck.stream()
.filter(FailureCause.isPerfectSquare())
.findAny()
.isPresent()) {
System.out.println("ERROR: no perfect square numbers were found");
return;
}
List<Integer> validResults = sourceToCheck.stream()
.filter(FailureCause.upTo100())
.filter(FailureCause.isPerfectSquare())
.collect(toList());
System.out.println("Valid data: " + validResults);
}
public static Predicate<Integer> upTo100() {
return i -> i <= 100;
}
public static Predicate<Integer> isPerfectSquare() {
return i -> {
double sq = Math.sqrt(i);
return (sq - Math.floor(sq)) == 0;
};
}
}
Однако при таком подходе коллекцию необходимо повторить несколько раз, чтобы узнать об ошибке и, наконец, получить подходящие элементы, которые проверяют все условия.
В качестве альтернативы описанному выше подходу я разработал следующий класс для хранения: фильтры, их порядок важности, сообщение об ошибке и наличие элемента это подтвердило.
public class ConditionToMatch<E> implements Comparable<ConditionToMatch> {
// To omit getter/setter
public int order;
public Predicate<E> condition;
public boolean wasFound;
public String errorMessage;
public ConditionToMatch (int order, Predicate<E> condition, boolean wasFound, String errorMessage) {
this.order = order;
this.condition = condition;
this.wasFound = wasFound;
this.errorMessage = errorMessage;
}
@Override
public int compareTo(ConditionToMatch o) {
return ofNullable(o)
.map(ext -> Integer.compare(order, ext.order))
.orElse(-1);
}
}
Добавление этого варианта использования к предыдущему FailureCause
классу:
public class FailureCause {
public static void main(String[] args) {
...
validateWithConditionClass(asList(201, 300, 450));
validateWithConditionClass(asList(20, 30, 40));
validateWithConditionClass(asList(400, 1600));
validateWithConditionClass(asList(10, 25, 36, 201, 1600));
}
...
public static void validateWithConditionClass(List<Integer> sourceToCheck) {
System.out.println("Initial elements: " + sourceToCheck);
ConditionToMatch<Integer> isUpTo100Condition = isUpTo100ConditionToMatch();
ConditionToMatch<Integer> isPerfectSquareCondition = isPerfectSquareConditionToMatch();
// Used to get the "most important" filter has failed
PriorityQueue<ConditionToMatch> priorizeValidations = new PriorityQueue<>(asList(isUpTo100Condition, isPerfectSquareCondition));
List<Integer> validResults = sourceToCheck.stream()
.map(s -> {
if (isUpTo100Condition.condition.test(s)) {
isUpTo100Condition.wasFound = true;
}
if (isPerfectSquareCondition.condition.test(s)) {
isPerfectSquareCondition.wasFound = true;
}
return s;
})
.filter(isUpTo100Condition.condition)
.filter(isPerfectSquareCondition.condition)
.collect(toList());
if (validResults.isEmpty()) {
Iterator<ConditionToMatch> value = priorizeValidations.iterator();
// To know the first "most important" filter that failed
while (value.hasNext()) {
ConditionToMatch current = value.next();
if (!current.wasFound) {
System.out.println(current.errorMessage);
break;
}
}
}
else {
System.out.println("Valid data: " + validResults);
}
}
...
public static ConditionToMatch<Integer> isUpTo100ConditionToMatch() {
return new ConditionToMatch<>(1, FailureCause.upTo100(), false, "ERROR: no numbers less or equals than 100 were found");
}
public static ConditionToMatch<Integer> isPerfectSquareConditionToMatch() {
return new ConditionToMatch<>(2, FailureCause.isPerfectSquare(), false, "ERROR: no perfect square numbers were found");
}
}
Мой вопрос: есть ли лучший и масштабируемый способ сделать это?