Спочатку загальний випадок: використання прапора для перевірки того, чи відповідає якийсь елемент колекції певній умові, не рідкість. Але модель, яку я бачив найчастіше для вирішення цього питання, - це перемістити чек на додатковий метод і безпосередньо повернутися з нього (як Кіліан Фот, описаний у своїй відповіді ):
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()
. Відповідь багато залежить від того, що цей метод повинен зробити.
Побічна примітка: Зазвичай, заклик 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);
}
Або це може означати щось зовсім інше… ;-)