我想知道有没有办法像这样重写代码
public static void main(String[] args) {
final List<String> dataCollection = Collections.emptyList();
final Set<String> someValues = new HashSet<>();
final Iterator<String> iterator = dataCollection.iterator();
while (iterator.hasNext()) {
final String dataItem = iterator.next();
// imagine some calculations
String calculatedData = dataItem;
if (!someValues.contains(calculatedData)) {
logger.error("Skipped data {} because of ...#1", dataItem);
iterator.remove();
continue;
}
for (char element : dataItem.toCharArray()) {
// imagine some other calculations
if (element > 100) {
logger.error("Skipped data {} because of ...#2", dataItem);
iterator.remove();
break;
}
}
}
}
使用Stream
API,以便记录过滤后的元素。
peek()在这种情况下不起作用,因为它要么在过滤前对每个元素执行操作,要么在剩余项目后执行。
到目前为止,我设法通过在lambda中记录来设计它,但它似乎冗长,笨拙并且像副作用一样。我们可以将它包装在某个方法中,但它只会隐藏该代码
public static void main(String[] args) {
final List<String> dataCollection = Collections.emptyList();
final Set<String> someValues = new HashSet<>();
final Iterator<String> iterator = dataCollection.iterator();
dataCollection.stream()
.filter(byCondition1(someValues))
.filter(byCondition2())
.collect(Collectors.toList());
}
private static Predicate<String> byCondition1(Set<String> someValues) {
return dataItem -> {
final boolean remain = someValues.contains(dataItem);
if (!remain) {
logger.error("Skipped data {} because of ...#1", dataItem);
}
return remain;
};
}
private static Predicate<String> byCondition2() {
return dataItem -> {
for (char element : dataItem.toCharArray()) {
// imagine some other calculations
if (element > 100) {
logger.error("Skipped data {} because of element {}...#2", dataItem, element);
return false;
}
}
return true;
};
}
我希望有更好的方法。
答案 0 :(得分:3)
假设跳过是一种特殊情况,这可能是可行的
List<String> dataCollection = Arrays.asList("FOO", "hello", "VALID", "123", "BAR", "bla");
Set<String> someValues = new HashSet<>(Arrays.asList("FOO", "BAR"));
Predicate<String> firstPredicate = string -> !someValues.contains(string);
Predicate<String> secondPredicate = string -> string.chars().noneMatch(c -> c>100);
List<String> result;
if(!logger.isLoggable(Level.WARNING)) {
result = dataCollection.stream()
.filter(firstPredicate)
.filter(secondPredicate)
.collect(Collectors.toList());
}
else {
Map<Boolean, List<String>> map = dataCollection.stream()
.collect(Collectors.partitioningBy(firstPredicate));
if(!map.get(false).isEmpty())
logger.log(Level.WARNING, "Skipped data {0} because of ...#1", map.get(false));
map = map.get(true).stream()
.collect(Collectors.partitioningBy(secondPredicate));
if(!map.get(false).isEmpty())
logger.log(Level.WARNING, "Skipped data {0} because of ...#2", map.get(false));
result = map.get(true);
}
此代码使用标准java.util.logging
API,如果禁用了指定级别的日志记录,则不会执行任何与日志记录相关的操作。另一方面,如果启用并遇到要跳过的项目,它将在每个条件下一次报告所有这些项目,而不是使用每个元素的条目充斥日志。使用上面显示的示例数据和默认日志处理程序,打印
Sep 26, 2017 11:00:46 AM LoggingExample main
WARNUNG: Skipped data [FOO, BAR] because of ...#1
Sep 26, 2017 11:00:46 AM LoggingExample main
WARNUNG: Skipped data [hello, bla] because of ...#2
结果为[VALID, 123]
,是否启用了该级别的日志记录。
答案 1 :(得分:2)
首先,我认为OP中的代码并不算太糟糕。其次,我们可以通过原始代码进行一些改进:
final Predicate<String> loggingFilter = dataItem -> {
final String calculatedData = dataItem; // imagine some calculations
if (!someValues.contains(calculatedData)) {
logger.error("Skipped data {} because of ...#1", dataItem);
return false;
}
final OptionalInt element = dataItem.chars().filter(ch -> ch > 100).findAny();
if (element.isPresent()) {
logger.error("Skipped data {} because of element {}...#2", dataItem, element.getAsInt());
return false;
}
return true;
};
dataCollection.stream().filter(loggingFilter).collect(Collectors.toList());
我不确定它是否是:“啰嗦,尴尬和副作用”给你或其他任何人。对我来说,没有重复的代码或副作用。除了某些语言可能会提供链式操作API以删除if(...); if(...)
之外,我们几乎可以使用任何语言。