Logging 使用流API记录排除结果的更好方法
我想知道有没有办法重写这样的代码Logging 使用流API记录排除结果的更好方法,logging,java-8,java-stream,Logging,Java 8,Java Stream,我想知道有没有办法重写这样的代码 public static void main(String[] args) { final List<String> dataCollection = Collections.emptyList(); final Set<String> someValues = new HashSet<>(); final Iterator<String> iterator = dataCollectio
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;
}
}
}
}
我希望有更好的方法。假设跳绳是一种特殊情况,这可能是可行的
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);
}
结果是,
[VALID,123]
,无论是否启用该级别的日志记录。首先,我认为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());
final Predicate loggingFilter=dataItem->{
最后一个字符串calculatedData=dataItem;//想象一些计算
如果(!someValues.contains(calculatedData)){
错误(“跳过数据{},因为…#1”,数据项);
返回false;
}
final optionant元素=dataItem.chars().filter(ch->ch>100.findAny();
if(element.isPresent()){
错误(“由于元素{}…#2”,dataItem,element.getAsInt())跳过了数据{});
返回false;
}
返回true;
};
dataCollection.stream().filter(loggingFilter.collect(Collectors.toList());
我不确定这对你或其他人来说是不是“冗长、笨拙和类似副作用”。对我来说,没有重复的代码或副作用。这几乎是任何语言都能做到的,除了一些语言可能提供链式操作API来删除
if(…);如果(…)
可能是谓词
的扩展?像接口LoggingPredicate扩展谓词…
和静态方法静态LoggingPredicate(Logger log)
一样,它将创建它并覆盖测试方法。只是个主意…是的,但是。。。这是包装此代码的另一种方式。当然,它比Mine具有更好的可重用性。我认为没有其他方法可以做到这一点,因为Stream API除了peek
之外没有任何日志记录功能。跳过项和调用iterator.remove()
之间有根本区别。一般来说,streams不支持这种修改。是的,我知道。对于这个问题,修改现有集合或创建新集合并不重要。请专注于日志记录关于将流拆分为两个的好主意。它是处理数据流的一种被动方式。不幸的是,在(至少在java中)这种拆分是终端操作,它破坏了流延迟评估的潜力。现在还有两个代码块计算结果,实际上是业务算法的重复
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());