Prima di tutto il caso generale: l'uso di un flag per verificare se alcuni elementi di una raccolta soddisfano una determinata condizione non è raro. Ma lo schema che ho visto più spesso per risolvere questo problema è spostare il controllo in un metodo aggiuntivo e tornare direttamente da esso (come descritto da Kilian Foth nella sua risposta ):
private <T> boolean checkCollection(Collection<T> collection)
{
for (T element : collection)
if (checkElement(element))
return true;
return false;
}
Da Java 8 esiste un modo più conciso di utilizzare Stream.anyMatch(…)
:
collection.stream().anyMatch(this::checkElement);
Nel tuo caso questo probabilmente assomiglierebbe a questo (supponendo list == entry.getValue()
nella tua domanda):
map.values().stream().anyMatch(list -> list.size() > limit);
Il problema nel tuo esempio specifico è la chiamata aggiuntiva a fillUpList()
. La risposta dipende molto da cosa dovrebbe fare questo metodo.
Nota a margine: così com'è, la chiamata a fillUpList()
non ha molto senso, perché non dipende dall'elemento che stai ripetendo. Immagino che questa sia una conseguenza della riduzione del codice effettivo per adattarlo al formato della domanda. Ma esattamente ciò porta a un esempio artificiale che è difficile da interpretare e quindi difficile da ragionare. Perciò è importante fornire un minimo, completa e verificabile esempio .
Quindi presumo che il codice effettivo passi la corrente entry
al metodo.
Ma ci sono altre domande da porre:
- Gli elenchi nella mappa sono vuoti prima di raggiungere questo codice? In tal caso, perché esiste già una mappa e non solo l'elenco o il set di
BigInteger
chiavi? Se non sono vuoti, perché è necessario compilare gli elenchi? Quando ci sono già elementi nell'elenco, non è un aggiornamento o qualche altro calcolo in questo caso?
- Cosa fa sì che un elenco diventi più grande del limite? Si tratta di una condizione di errore o si prevede che accada spesso? È causato da un input non valido?
- Hai bisogno degli elenchi calcolati fino al punto in cui raggiungi un elenco più grande del limite?
- Cosa fa la parte " Fai qualcosa "?
- Riavvia il riempimento dopo questa parte?
Queste sono solo alcune domande che mi sono venute in mente quando ho cercato di capire il frammento di codice. Quindi, secondo me, questo è il vero odore del codice : il tuo codice non comunica chiaramente l'intento.
Potrebbe significare questo ("tutto o niente" e raggiungere il limite indica un errore):
/**
* 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.
}
Oppure potrebbe significare questo ("aggiornamento fino al primo 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.
}
O questo ("aggiorna tutti gli elenchi ma mantieni l'elenco originale se diventa troppo 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
}
O anche il seguente (usando computeFoos(…)
dal primo esempio ma senza eccezioni):
/**
* 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);
}
Oppure potrebbe significare qualcosa di completamente diverso ... ;-)