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