首先是一般情况:使用标志来检查集合中的某些元素是否满足特定条件并不罕见。但是,我最常看到的解决此问题的模式是将支票移到其他方法中,然后直接从中返回(例如Kilian Foth在他的回答中所述):
private <T> boolean checkCollection(Collection<T> collection)
{
for (T element : collection)
if (checkElement(element))
return true;
return false;
}
从Java 8开始,有一种更简洁的使用方式 Stream.anyMatch(…)
:
collection.stream().anyMatch(this::checkElement);
在您的情况下,这可能看起来像这样(假设 list == entry.getValue()
您的问题):
map.values().stream().anyMatch(list -> list.size() > limit);
您特定示例中的问题是对的附加调用fillUpList()
。答案在很大程度上取决于此方法应该执行的操作。
旁注:就目前而言,对to的调用fillUpList()
没有多大意义,因为它并不取决于您当前正在迭代的元素。我想这是剥离实际代码以适合问题格式的结果。但这恰恰导致了一个难以解释的人工例子,因此也难以推理。因此,提供Minimal,Complete和可验证的示例。
因此,我假设实际的代码将电流传递entry
给该方法。
但是还有更多问题要问:
- 在到达此代码之前,地图中的列表是否为空?如果是这样,为什么为什么已经有一个地图,而不仅仅是
BigInteger
键的列表或键集?如果它们不为空,那么为什么需要填写列表?如果列表中已经有元素,在这种情况下是更新还是其他计算?
- 是什么导致列表变得超出限制?这是错误状态还是经常发生?是输入无效引起的吗?
- 您是否需要计算列表,直至达到大于限制的列表?
- “ 做什么 ”部分是做什么的?
- 在这部分之后您是否重新开始填充?
当我尝试理解代码片段时,这只是我想到的一些问题。因此,在我看来,这才是真正的代码味道:您的代码并未明确传达意图。
它可能意味着这个(“全有或全无”,并且达到限制表示错误):
/**
* Computes the list of all foo strings for each passed number.
*
* @param numbers the numbers to process. Must not be {@code null}.
* @return all foo strings for each passed number. Never {@code null}.
* @throws InvalidArgumentException if any number produces a list that is too long.
*/
public Map<BigInteger, List<String>> computeFoos(Set<BigInteger> numbers)
throws InvalidArgumentException
{
if (numbers.isEmpty())
{
// Do you actually need to log this here?
// The caller might know better what to do in this case...
logger.info("Nothing to compute");
}
return numbers.stream().collect(Collectors.toMap(
number -> number,
number -> computeListForNumber(number)));
}
private List<String> computeListForNumber(BigInteger number)
throws InvalidArgumentException
{
// compute the list and throw an exception if the limit is exceeded.
}
或可能意味着此(“更新到第一个问题”):
/**
* Refreshes all foo lists after they have become invalid because of bar.
*
* @param map the numbers with all their current values.
* The values in this map will be modified.
* Must not be {@code null}.
* @throws InvalidArgumentException if any new foo list would become too long.
* Some other lists may have already been updated.
*/
public void updateFoos(Map<BigInteger, List<String>> map)
throws InvalidArgumentException
{
map.replaceAll(this::computeUpdatedList);
}
private List<String> computeUpdatedList(
BigInteger number, List<String> currentValues)
throws InvalidArgumentException
{
// compute the new list and throw an exception if the limit is exceeded.
}
或这样(“更新所有列表,但如果列表太大,则保留原始列表”):
/**
* Refreshes all foo lists after they have become invalid because of bar.
* Lists that would become too large will not be updated.
*
* @param map the numbers with all their current values.
* The values in this map will be modified.
* Must not be {@code null}.
* @return {@code true} if all updates have been successful,
* {@code false} if one or more elements have been skipped
* because the foo list size limit has been reached.
*/
public boolean updateFoos(Map<BigInteger, List<String>> map)
{
boolean allUpdatesSuccessful = true;
for (Entry<BigInteger, List<String>> entry : map.entrySet())
{
List<String> newList = computeListForNumber(entry.getKey());
if (newList.size() > limit)
allUpdatesSuccessful = false;
else
entry.setValue(newList);
}
return allUpdatesSuccessful;
}
private List<String> computeListForNumber(BigInteger number)
{
// compute the new list
}
甚至以下内容(使用computeFoos(…)
第一个示例,但无例外):
/**
* Processes the passed numbers. An optimized algorithm will be used if any number
* produces a foo list of a size that justifies the additional overhead.
*
* @param numbers the numbers to process. Must not be {@code null}.
*/
public void process(Collection<BigInteger> numbers)
{
Map<BigInteger, List<String>> map = computeFoos(numbers);
if (isLimitReached(map))
processLarge(map);
else
processSmall(map);
}
private boolean isLimitReached(Map<BigInteger, List<String>> map)
{
return map.values().stream().anyMatch(list -> list.size() > limit);
}
否则可能意味着完全不同的…;-)