Ответ 1
Основным направлением является использование исключений для чего-то действительно исключительного **. Для "обычного" сбоя гораздо лучше использовать Option
или Either
. Если вы взаимодействуете с Java, где исключаются исключения, когда кто-то чихает неправильно, вы можете использовать Try
, чтобы оставаться в безопасности.
Возьмем несколько примеров.
Предположим, что у вас есть метод, который извлекает что-то с карты. Что может пойти не так? Ну, что-то драматическое и опасное, как переполнение стека segfault *, или что-то ожидаемое, подобное элементу, не найдено. Вы позволили бы переполнению стека segfault вызвать исключение, но если вы просто не найдете элемент, почему бы не вернуть Option[V]
вместо значения или исключения (или null
),
Теперь предположим, что вы пишете программу, в которой пользователь должен ввести имя файла. Теперь, если вы не собираетесь немедленно заручиться программой, когда что-то пойдет не так, Either
- это путь:
def main(args: Array[String]) {
val f = {
if (args.length < 1) Left("No filename given")
else {
val file = new File(args(0))
if (!file.exists) Left("File does not exist: "+args(0))
else Right(file)
}
}
// ...
}
Теперь предположим, что вы хотите проанализировать строку с номерами, разделенными пробелами.
val numbers = "1 2 3 fish 5 6" // Uh-oh
// numbers.split(" ").map(_.toInt) <- will throw exception!
val tried = numbers.split(" ").map(s => Try(s.toInt)) // Caught it!
val good = tried.collect{ case Success(n) => n }
Таким образом, у вас есть три способа (по крайней мере) для решения различных типов сбоев: Option
для того, чтобы он работал/не выполнялся, в тех случаях, когда поведение не ожидается, а не шокирующий и тревожный сбой; Either
, когда все может работать или нет (или, действительно, в любом случае, когда у вас есть два взаимоисключающих параметра), и вы хотите сохранить некоторую информацию о том, что пошло не так; и Try
, когда вы не хотите, чтобы вся головная боль обработки исключений выполнялась самостоятельно, но все же нужно взаимодействовать с кодом, который является исключением-счастливым.
Кстати, исключения приводят к хорошим примерам - так что вы найдете их чаще в учебнике или учебном материале, чем где-либо еще, я думаю: примеры учебников очень часто бывают неполными, а это означает, что серьезные проблемы, которые обычно могут быть предотвращены осторожный дизайн должен быть помечен, выставив исключение.
* Изменить: Segfaults разбивают JVM и никогда не должны происходить независимо от байт-кода; даже исключение вам тогда не поможет. Я имел в виду переполнение стека.
** Изменить: Исключения (без трассировки стека) также используются для потока управления в Scala - они на самом деле довольно эффективный механизм, и они включают такие вещи, как установленные библиотекой выражения break
и return
, который возвращается из вашего метода, даже если элемент управления фактически перешел в одно или несколько закрытий. В основном, вы не должны беспокоиться об этом сами, за исключением того, что поймать все Throwable
не является такой супер-идеей, так как вы можете ошибиться по одному из этих исключений потока управления.