Primeiro do caso geral: não é incomum usar um sinalizador para verificar se algum elemento de uma coleção atende a uma determinada condição. Mas o padrão que vi com mais freqüência para resolver isso é mover a verificação em um método extra e retornar diretamente a partir dela (como Kilian Foth descrito em sua resposta ):
private <T> boolean checkCollection(Collection<T> collection)
{
for (T element : collection)
if (checkElement(element))
return true;
return false;
}
Desde o Java 8, existe uma maneira mais concisa de usar Stream.anyMatch(…)
:
collection.stream().anyMatch(this::checkElement);
No seu caso, isso provavelmente seria assim (supondo list == entry.getValue()
na sua pergunta):
map.values().stream().anyMatch(list -> list.size() > limit);
O problema no seu exemplo específico é a chamada adicional para fillUpList()
. A resposta depende muito do que esse método deve fazer.
Nota lateral: do jeito que está, a chamada para fillUpList()
não faz muito sentido, porque não depende do elemento que você está iterando no momento. Eu acho que isso é uma consequência de remover o código real para se ajustar ao formato da pergunta. Mas exatamente isso leva a um exemplo artificial difícil de interpretar e, portanto, difícil de raciocinar. Por isso, é tão importante para fornecer um mínimo, completa e verificável exemplo .
Então, eu assumo que o código real passa a corrente entry
para o método
Mas há mais perguntas a serem feitas:
- As listas no mapa estão vazias antes de alcançar este código? Se sim, por que já existe um mapa e não apenas a lista ou o conjunto de
BigInteger
chaves? Se eles não estiverem vazios, por que você precisa preencher as listas? Quando já existem elementos na lista, não é uma atualização ou alguma outra computação nesse caso?
- O que faz com que uma lista fique maior que o limite? Esta é uma condição de erro ou espera-se que ocorra com frequência? É causado por entrada inválida?
- Você precisa das listas calculadas até o ponto em que atinge uma lista maior que o limite?
- O que a parte " Faça alguma coisa " faz?
- Você reinicia o preenchimento após esta parte?
Estas são apenas algumas perguntas que me vieram à mente quando tentei entender o fragmento de código. Então, na minha opinião, esse é o verdadeiro cheiro do código : seu código não comunica claramente a intenção.
Isso pode significar isso ("tudo ou nada" e atingir o limite indica um erro):
/**
* 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.
}
Ou pode significar isso ("atualização até o primeiro problema"):
/**
* 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.
}
Ou isto ("atualize todas as listas, mas mantenha a lista original se ela ficar muito grande"):
/**
* 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
}
Ou até o seguinte (usando computeFoos(…)
o primeiro exemplo, mas sem exceções):
/**
* 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);
}
Ou pode significar algo completamente diferente… ;-)