Try[A]
представляет вычисление, которое, если оно выполнено, является значением типа A
, в противном случае что-то пошло не так и будет Throwable
. Он поставляется в двух вариантах: при успешном вычислении это значение типа A
, заключенное в экземпляр Success[A]
. В случае сбоя это экземпляр Failure[A]
, который включает исключение Throwable
.
Одной из характеристик Try
является то, что он позволяет очень умно использовать функции высокого порядка (например, Option
, Either
и другие монады) и цепные операции.
Допустим, у вас есть эта маленькая программа:
scala> def divide(x: Int, y: Int): Try[Int] =
if (y == 0) Try(throw new Exception("Error: division by zero!"))
else Try(x / y)
divide: (x: Int, y: Int)scala.util.Try[Int]
Вы получаете
scala> divide(3,2)
res30: scala.util.Try[Int] = Success(1)
и
scala> divide(3,0)
res31: scala.util.Try[Int] = Failure(java.lang.Exception: Error: division by zero!)
Таким образом, вы можете использовать возможность функций высокого порядка для элегантного распознавания сбоев:
scala> divide(3,0).getOrElse(0)
res32: Int = 0
Это всего лишь пример, но подумайте о том, пытались ли вы выполнить более сложное вычисление, которое могло бы потерпеть неудачу, и вам пришлось зафиксировать этот результат и действовать в результате.
Почему бы вам не использовать try catchs
в Scala? Это не потому, что вы не сможете этого сделать, а потому, что это не очень функционально. Если вам нужно обработать исключение, которое возникает в другом потоке (скажем, актером), вы не можете перехватить это исключение, возможно, вы захотите передать сообщение вашему текущему основному потоку о том, что вычисление не удалось, и вы выясним, как справиться с этим.
Кроме того, почему мы возвращаем разделение в случае отказа? Иначе у нас будет несоответствие типов? Это единственная причина?
Возвращает divide
в Failure
, потому что позволяет перезапустить программу, если она не удалась, но это просто решение, принятое программистом. Вы могли бы просто возвратить Failure
обертывание какого-то сообщения об ошибке.