Повторне вилучення виключення лише тому, що ви вирішили зареєструвати його за допомогою блоку ловлі (тобто виняток взагалі не змінився) - погана ідея.
Однією з причин, коли ми використовуємо повідомлення про винятки, винятки та їх обробку, є те, що ми знаємо, що пішло не так, і вміло написані винятки можуть пришвидшити пошук помилки з великою запасом.
Також пам’ятайте, що обробка винятків коштує набагато більше ресурсів, ніж, скажімо, є if
, тому не слід часто обробляти їх лише тому, що вам здається. Це впливає на ефективність вашої програми.
Однак хороший підхід використовувати виключення як засіб для позначення рівня програми, в якому з’явилася помилка.
Розглянемо наступний напівпсевдо-код:
interface ICache<T, U>
{
T GetValueByKey(U key); // may throw an CacheException
}
class FileCache<T, U> : ICache<T, U>
{
T GetValueByKey(U key)
{
throw new CacheException("Could not retrieve object from FileCache::getvalueByKey. The File could not be opened. Key: " + key);
}
}
class RedisCache<T, U> : ICache<T, U>
{
T GetValueByKey(U key)
{
throw new CacheException("Could not retrieve object from RedisCache::getvalueByKey. Failed connecting to Redis server. Redis server timed out. Key: " + key);
}
}
class CacheableInt
{
ICache<int, int> cache;
ILogger logger;
public CacheableInt(ICache<int, int> cache, ILogger logger)
{
this.cache = cache;
this.logger = logger;
}
public int GetNumber(int key) // may throw service exception
{
int result;
try {
result = this.cache.GetValueByKey(key);
} catch (Exception e) {
this.logger.Error(e);
throw new ServiceException("CacheableInt::GetNumber failed, because the cache layer could not respond to request. Key: " + key);
}
return result;
}
}
class CacheableIntService
{
CacheableInt cacheableInt;
ILogger logger;
CacheableInt(CacheableInt cacheableInt, ILogger logger)
{
this.cacheableInt = cacheableInt;
this.logger = logger;
}
int GetNumberAndReturnCode(int key)
{
int number;
try {
number = this.cacheableInt.GetNumber(key);
} catch (Exception e) {
this.logger.Error(e);
return 500; // error code
}
return 200; // ok code
}
}
Припустимо, хтось подзвонив GetNumberAndReturnCode
і отримав 500
код, сигналізуючи про помилку. Він зателефонує в службу підтримки, яка відкриє файл журналу і побачить це:
ERROR: 12:23:27 - Could not retrieve object from RedisCache::getvalueByKey. Failed connecting to Redis server. Redis server timed out. Key: 28
ERROR: 12:23:27 - CacheableInt::GetNumber failed, because the cache layer could not respond to request. Key: 28
Потім розробник одразу знає, який рівень програмного забезпечення викликав процес переривання, і він має простий спосіб виявити проблему. У цьому випадку це критично важливо, тому що тайм-аут Redis ніколи не повинен відбуватися.
Можливо, інший користувач закликає той самий метод, також отримує 500
код, але журнал відображатиме таке:
INFO: 11:11:11- Could not retrieve object from RedisCache::getvalueByKey. Value does not exist for the key 28.
INFO: 11:11:11- CacheableInt::GetNumber failed, because the cache layer could not find any data for the key 28.
У такому випадку підтримка може просто відповісти користувачеві, що запит недійсний, оскільки він вимагає значення для неіснуючого ідентифікатора.
Підсумок
Якщо ви обробляєте винятки, переконайтеся, що з ними правильно поводитися. Також переконайтеся, що ваші винятки включають в першу чергу правильні дані / повідомлення відповідно до ваших шарів архітектури, тому повідомлення допоможуть вам визначити проблему, яка може виникнути.