Ответ 1
Я не уверен, что есть один самый идиоматический способ справиться с исключениями Java, потому что есть по крайней мере четыре разных случая, которые они будут брошены:
- Что-то, что ни вы, ни разработчик библиотеки не ожидали пойти не так, пошли не так.
- То, что надеялся дизайнер библиотеки, не помогло, и вам нужно знать подробности.
- То, что вы надеялись, не помогло бы, и вам не нужно знать подробности.
- Иногда метод создает значение, а иногда нет, и он сообщает об этом, вызывая исключение.
Лучшие практики, возможно, различаются для каждого из этих случаев
1. Действительно исключительные исключения
Scala имеет полнофункциональную обработку исключений. Нет ничего плохого в том, чтобы позволить непредвиденному исключению распространяться невостребованным, пока вы не достигнете уровня, где вы можете что-то сделать. Упаковка любого возможного исключения в Either
может тратить много времени. Просто документируйте то, что, как вы знаете, не обрабатываете, и используйте try/catch на соответствующем высоком уровне (например, метод saveEverything
должен, вероятно, перейти в блок try/catch (или обернуть его содержимое в одном), потому что независимо от того, что было неправильно, если сэкономить все не удалось, вы, вероятно, захотите попытаться спасти ситуацию, а не просто умереть).
В частности, вы, вероятно, захотите обработать Error
таким образом и только пакет Exception
, а не все Throwable
s, в Either
.
2. Исключения, которые вам нужно знать о
Это тот случай, о котором вы говорите, и вы уже дали несколько хороших предложений о том, как с ними бороться. Как вы уже заметили, вы можете использовать catching
для упаковки исключений в Either
. Затем вы можете
а. Используйте сопоставление шаблонов, что позволит вам более подробно разделить ваш Either
:
doesNotThrowExceptions("par").right.map(transformData) match {
case Left(ioe: IOException) => /* ... */
case Left(nsae: NoSuchAlgorithmException) => /* ... */
case Right(x) => /* ... */
case Left(e) => throw e // Didn't expect this one...
}
б. Сконвертировать в Option
после регистрации ошибки:
doesNotThrowExceptions("par").left.map{ e =>
println("You're not going to like this, but something bad happened:")
println(e)
println("Let see if we can still make this work....")
}.right.toOption
с. Если исключения являются действительно важной частью вашего контроля потока, Either
может быть недостаточно. Вместо этого вы можете определить свой собственный класс Either
с более чем Left
и Right
. Или вы можете вложить левую часть Either
:
try { Right(/* java code */) }
catch {
case ioe: IOException => Left(Left(ioe))
case nsae: NoSuchAlgorithmException => Left(Right(nsae))
}
д. Используйте Scalaz Validation
, который очень похож на Either
, но немного приспособлен к обработке исключений.
3. Исключения, когда вам нужно только знать, что что-то пошло не так, и
4. Исключения, сброшенные, чтобы указать no-return-value
Даже если это концептуально две разные категории, вы обрабатываете их одинаково:
catching(classOf[IOException], classOf[NoSuchAlgorithmException]) opt { ... }
чтобы получить Option
назад. Тогда map
, flatMap
и т.д.