我需要驗證幾個字串并確保每個字串都已填充或沒有。
我正在接收資料,所以我無法控制它,未填充的可能是 null 或空字串(只有空格的字串被視為已填充)。
我顯然可以寫出類似的東西:
String s1 = "A";
String s2 = "B";
String s3 = "C";
boolean valid = (
(s1 == null || s1.isEmpty()) &&
(s2 == null || s2.isEmpty()) &&
(s3 == null || s3.isEmpty())
) || (
(s1 != null && !s1.isEmpty()) &&
(s2 != null && !s2.isEmpty()) &&
(s3 != null && !s3.isEmpty())
);
但這越來越難以閱讀,我認為最終我需要檢查七個字串。
所以我開始看流,我可以做到
boolean anyPopulated = Stream.of(s1, s2, s3).anyMatch(s -> s != null && !s.isEmpty());
boolean allPopulated = Stream.of(s1, s2, s3).allMatch(s -> s != null && !s.isEmpty());
boolean valid = (anyPopulated == allPopulated);
這更容易閱讀,但我不禁想到必須有一種更容易閱讀的方法來做到這一點。
我需要為此使用標準 Java,所以沒有庫。
uj5u.com熱心網友回復:
至少只涉及一個流
public static boolean validate(String... strings) {
long populated = Stream.of(strings).filter(s -> s != null && !s.isEmpty()).count();
return populated == 0 || populated == strings.length;
}
uj5u.com熱心網友回復:
allMatch() noneMatch()
關于基于流的解決方案,您建議使用組合allMatch() noneMatch()和allPopulated || nonePopulated.
條件allPopulated || nonePopulated比anyPopulated == allPopulated閱讀更直觀,并且需要更少的努力。
看起來可能有兩次迭代,但請記住,操作allMatch()和noneMatch()是短路的,因此兩個流都不會迭代整個資料集。
boolean nonePopulated = Stream.of(s1, s2, s3)
.noneMatch(s -> s != null && !s.isEmpty());
boolean allPopulated = Stream.of(s1, s2, s3)
.allMatch(s -> s != null && !s.isEmpty());
boolean valid = allPopulated || nonePopulated;
請注意,也可以保持解決方案短路并僅使用單個流。為了理解邏輯,讓我們首先看一下使用普通for回圈的實作。
短路解決方案 - For-loop
要使用回圈實作短路邏輯,我們可以評估第一個元素的謂詞,并根據基本結果檢查所有后續結果。在第一個結果與基數不匹配之后,我們可以打破回圈。
boolean isValid = validateAll(s -> s != null && !s.isEmpty(), s1, s2, s3);
public static <T> boolean validateAll(Predicate<T> pred, T... args) {
if (args.length == 0) return true; // or throw
boolean base = pred.test(args[0]);
for (int i = 1; i < args.length; i ) {
if (base != pred.test(args[i])) {
return false;
}
}
return true;
}
短路解決方案 - 單流
與前面的解決方案類似,我們可以從評估第一個元素的謂詞開始。但是,我們可以調整謂詞本身并進一步應用否定謂詞或初始謂詞,而不是存盤結果。
此流可以從第二個元素開始終止(如果資料無效)。
public static <T> boolean validateAll(Predicate<T> pred, T... args) {
if (args.length == 0) return true; // or throw
Predicate<T> adjustedPredicate = pred.test(args[0]) ? pred : pred.negate();
return Arrays.stream(args).skip(1).allMatch(adjustedPredicate);
}
有關于如何使用單個流甚至一個陳述句執行此驗證的選項。下面列出了其中一些,但它們不是短路的,空間效率較低并且需要更多的努力閱讀。
單一陳述句 - 內置收集器
這是一個基于收集器組合的解決方案collectingAndThen(),partitioningBy()它允許isValid在單個陳述句中獲取值:
boolean isValid = Stream.of(s1, s2, s3)
.collect(Collectors.collectingAndThen(
Collectors.partitioningBy(s -> s != null && !s.isEmpty(),
Collectors.counting()),
map -> map.get(true) == 0 || map.get(false) == 0
));
一個流 - 自定義收集器
如果我們概括該任務,則可以使用自定義收集器來解決它,該收集器使用布爾陣列作為累積型別(您可以在類的內置收集器的實作中使用類似的方法Collectors)。
要創建自定義收集器,我們可以使用靜態方法Collector.of()。
boolean isValid = validateAll(s -> s != null && !s.isEmpty(), s1, s2, s3);
通用方法,它需要一個varargs和Ta Predicate<T>:
public static <T> boolean validateAll(Predicate<T> pred, T... args) {
return Arrays.stream(args).collect(allMatchOrNoneMatch(pred));
}
一個自定義收集器,它產生一個boolean值:
public static <T> Collector<T, ?, Boolean> allMatchOrNoneMatch(Predicate<T> pred) {
return Collector.of(
() -> new Boolean[]{null, true},
(Boolean[] arr, T next) -> {
if (arr[0] == null) arr[0] = pred.test(next);
else if (arr[1] && (pred.test(next) != arr[0])) arr[1] = false;
},
(left, right) -> {
left[1] = left[1] && right[1];
return left;
},
arr -> arr[1]
);
}
uj5u.com熱心網友回復:
從 Alexander Ivanchenko 的出色回答中汲取靈感,我想通過反轉條件來稍微縮短它,以便檢查所有空或空(給出相同的結果)并將其放入一個方法中:
private static boolean allOrNonePopulated(String... strings) {
return Stream.of(strings).allMatch(s -> s == null || s.isEmpty())
|| Stream.of(strings).noneMatch(s -> s == null || s.isEmpty());
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/513400.html
標籤:爪哇验证布尔值java流
