Прежде всего, общий случай: использование флага для проверки соответствия некоторого элемента коллекции определенному условию не является редкостью. Но шаблон, который я видел чаще всего для решения этой проблемы, заключается в перемещении чека в дополнительном методе и непосредственном возвращении из него (как Килиан Фот описал в своем ответе ):
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()
не имеет особого смысла, поскольку он не зависит от элемента, который вы в настоящее время повторяете. Я предполагаю, что это является следствием сокращения вашего фактического кода, чтобы соответствовать формату вопроса. Но именно это приводит к искусственному примеру, который трудно интерпретировать и, следовательно, трудно рассуждать. Поэтому так важно привести минимальный, полный и проверяемый пример .
Поэтому я предполагаю, что фактический код передает текущий 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);
}
Или это может означать что-то совершенно другое… ;-)