Zunächst zum allgemeinen Fall: Es ist nicht ungewöhnlich, dass ein Flag verwendet wird, um zu überprüfen, ob ein Element einer Sammlung eine bestimmte Bedingung erfüllt. Aber das Muster, das ich am häufigsten gesehen habe, um dies zu lösen, besteht darin, den Scheck in eine zusätzliche Methode zu verschieben und direkt daraus zurückzukehren (wie Kilian Foth in seiner Antwort beschrieben hat ):
private <T> boolean checkCollection(Collection<T> collection)
{
for (T element : collection)
if (checkElement(element))
return true;
return false;
}
Seit Java 8 gibt es eine präzisere Möglichkeit, Folgendes zu verwenden Stream.anyMatch(…)
:
collection.stream().anyMatch(this::checkElement);
In Ihrem Fall würde dies wahrscheinlich so aussehen (vorausgesetzt, list == entry.getValue()
in Ihrer Frage):
map.values().stream().anyMatch(list -> list.size() > limit);
Das Problem in Ihrem konkreten Beispiel ist der zusätzliche Anruf an fillUpList()
. Die Antwort hängt stark davon ab, was diese Methode bewirken soll.
Randnotiz: Der Aufruf von fillUpList()
macht derzeit wenig Sinn, da er nicht von dem Element abhängt, das Sie gerade iterieren. Ich vermute, dies ist eine Folge davon, dass Sie Ihren eigentlichen Code auf das Frageformat reduziert haben. Aber genau das führt zu einem künstlichen Beispiel, das schwer zu interpretieren und daher schwer zu überlegen ist. Daher ist es so wichtig, ein minimales, vollständiges und überprüfbares Beispiel bereitzustellen .
Ich gehe also davon aus, dass der tatsächliche Code den aktuellen übergibt entry
an die Methode weitergibt.
Es gibt jedoch noch weitere Fragen zu stellen:
- Sind die Listen in der Karte leer, bevor dieser Code erreicht wird? Wenn ja, warum gibt es bereits eine Karte und nicht nur die Liste oder den Satz der
BigInteger
Schlüssel? Wenn sie nicht leer sind, warum müssen Sie die Listen ausfüllen ? Wenn die Liste bereits Elemente enthält, handelt es sich in diesem Fall nicht um ein Update oder eine andere Berechnung?
- Wodurch wird eine Liste größer als das Limit? Ist dies ein Fehlerzustand oder wird ein häufiges Auftreten erwartet? Wird es durch ungültige Eingabe verursacht?
- Benötigen Sie die Listen, die bis zu dem Punkt berechnet wurden, an dem Sie eine Liste erreichen, die das Limit überschreitet?
- Was macht der Teil " Etwas tun"?
- Starten Sie die Befüllung nach diesem Teil neu?
Dies sind nur einige Fragen, die mir einfielen, als ich versuchte, das Codefragment zu verstehen. Meiner Meinung nach ist das also der wahre Codegeruch : Ihr Code kommuniziert die Absicht nicht klar.
Dies kann entweder bedeuten ("alles oder nichts" und das Erreichen des Grenzwerts weist auf einen Fehler hin):
/**
* 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.
}
Oder es könnte dies bedeuten ("Update bis zum ersten Problem"):
/**
* 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.
}
Oder dies ("Aktualisiere alle Listen, aber behalte die Originalliste, wenn sie zu groß wird"):
/**
* 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
}
Oder sogar das Folgende (mit computeFoos(…)
dem ersten Beispiel, aber ohne Ausnahmen):
/**
* 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);
}
Oder es könnte etwas ganz anderes bedeuten… ;-)