İlk önce genel durum: Bir koleksiyonun bazı öğelerinin belirli bir koşulu karşılayıp karşılamadığını kontrol etmek için bir bayrak kullanmak nadir değildir. Ancak bunu çözmek için en sık gördüğüm örnek, çekimi ekstra bir yöntemle taşımak ve doğrudan geri dönmek ( cevabında açıklanan Kilian Foth gibi ):
private <T> boolean checkCollection(Collection<T> collection)
{
for (T element : collection)
if (checkElement(element))
return true;
return false;
}
Java 8’den bu yana Stream.anyMatch(…)
şunları kullanarak daha özlü bir yol var :
collection.stream().anyMatch(this::checkElement);
Sizin durumunuzda bu muhtemelen şöyle gözükecektir ( list == entry.getValue()
sorunuz varsayarak ):
map.values().stream().anyMatch(list -> list.size() > limit);
Özel örneğinizdeki sorun ek çağrı fillUpList()
. Cevap, bu yöntemin ne yapması gerektiğine çok bağlıdır.
Yan not: Dururken, çağrı fillUpList()
yapmak pek mantıklı değil, çünkü şu anda yinelediğiniz öğeye bağlı değil. Sanırım bu, gerçek kodunuzu soru biçimine uyacak şekilde çıkarmanın bir sonucudur. Fakat tam olarak bu, yorumlanması zor ve dolayısıyla da mantıklı olması zor yapay bir örneğe götürür. Bu nedenle, Minimal, Komple ve Doğrulanabilir bir örnek sunmak çok önemlidir .
Bu yüzden asıl kodun akımı entry
metoda ilettiğini varsayıyorum .
Ancak sorulacak daha çok soru var:
- Bu koda ulaşmadan önce haritadaki listeler boş mu? Öyleyse, neden sadece bir liste veya
BigInteger
anahtarların değil, bir harita var ? Boş değilse, neden listeleri doldurmanız gerekiyor ? Listede zaten öğeler varsa, bu durumda bu bir güncelleme veya başka bir hesaplama değil mi?
- Bir listenin sınırdan daha büyük olmasına neden olan nedir? Bu bir hata durumu mu yoksa sıkça olması bekleniyor mu? Geçersiz girişten mi kaynaklanıyor?
- Limitten daha büyük bir listeye ulaştığınız noktaya kadar hesaplanan listelere ihtiyacınız var mı?
- "Bir şeyler yap " kısmı ne işe yarıyor?
- Bu bölümden sonra dolumu yeniden başlatıyor musunuz?
Bu sadece kod parçasını anlamaya çalıştığımda aklıma gelen bazı sorular. Yani, benim görüşüme göre, bu gerçek kod kokusu : Kodunuz amacı açıkça iletmiyor.
Bu da ("hepsi ya da hiçbiri" anlamına gelebilir ve sınıra ulaşmak bir hataya işaret eder) olabilir:
/**
* 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.
}
Veya bu şu anlama gelebilir ("ilk soruna kadar güncelleme"):
/**
* 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.
}
Veya bu ("tüm listeleri güncelle ama çok büyük olursa orijinal listesini tut"):
/**
* 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
}
Veya aşağıdakileri bile ( computeFoos(…)
ilk örnekte, ancak istisnalar olmadan):
/**
* 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);
}
Ya da tamamen farklı bir şey anlamına gelebilir… ;-)