2016-11-28 14 views
5

Поиск в Интернете ответ дает две видные посты (Codacy's и Daniel Westheide's), и оба дают один и тот же ответ, как Scala's official documentation for Try:Какие преимущества дает scala.util.Try иметь try..catch?

Важное свойство Постарайся показано в приведенном выше примере является его способность трубопровода, или цепь , операции, улавливающие исключения на этом пути.

Пример ссылки выше:

import scala.io.StdIn 
import scala.util.{Try, Success, Failure} 

def divide: Try[Int] = { 
    val dividend = Try(StdIn.readLine("Enter an Int that you'd like to divide:\n").toInt) 
    val divisor = Try(StdIn.readLine("Enter an Int that you'd like to divide by:\n").toInt) 
    val problem = dividend.flatMap(x => divisor.map(y => x/y)) 
    problem match { 
    case Success(v) => 
     println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v) 
     Success(v) 
    case Failure(e) => 
     println("You must've divided by zero or entered something that's not an Int. Try again!") 
     println("Info from the exception: " + e.getMessage) 
     divide 
    } 
} 

Но можно так же легко операции трубопроводов с использованием обычного try блок:

def divideConventional: Int = try { 
    val dividend = StdIn.readLine("Enter an Int that you'd like to divide:\n").toInt 
    val divisor = StdIn.readLine("Enter an Int that you'd like to divide by:\n").toInt 
    val problem = dividend/divisor 
    println("Result of " + dividend + "/"+ divisor +" is: " + problem) 
    problem 
} catch { 
    case (e: Throwable) => 
    println("You must've divided by zero or entered something that's not an Int. Try again!") 
    println("Info from the exception: " + e.getMessage) 
    divideConventional 
} 

(Примечание: divide и divideConventional незначительно отличаются в поведении в том, что последний ошибается при первых признаках неприятностей, но вот об этом. Попробуйте ввести «10a» в качестве входа в dividend, чтобы увидеть wh я имею в виду.)

Я пытаюсь найти преимущество конвейеризации scala.util.Try, но мне кажется, что эти два метода равны. Что мне не хватает?

+1

Обратите внимание, что 'Try (...)' только улавливает нефатальные исключения, поэтому он эквивалентен 'try {...} catch {case NonFatal (e) => ...} –

+0

Обратите внимание, что' Try' является частью системы типов. Любой код, который обрабатывает значение типа 'Try',« знает », что он может быть тем или иным. Подпрограмма, которая может бросить, может обернуть ее в «Try» и передать ее как чужую проблему. Без «Try» нет простого способа общения: «Эй, кому-то еще нужно справиться с этим». – jwvh

+1

Daniel Westheide говорит в своем посте, что «если вам нужно иметь дело с исключением, брошенным актером, который выполняется в каком-то другом потоке, вы, очевидно, не можете этого сделать, поймав это исключение». Я думаю, что проблема параллелизма также важна. – NaHeon

ответ

4

Я думаю, что вам трудно увидеть составные способности Try[T], потому что вы обрабатываете исключения локально в обоих случаях. Что делать, если вы хотите создать divideConventional с дополнительной операцией?

Мы бы имея некоторые, как:

def weNeedAnInt(i: Int) = i + 42 

Тогда мы имеем что-то вроде:

weNeedAnInt(divideConventional()) 

Но предположим, что вы хотите максимум из числа повторений вы позволяют пользователю (обычно это то, что у вас есть в реальных сценариях жизни, когда вы не можете повторно вводить метод навсегда? Нам придется дополнительно обернуть вызов weNeedAnInt с помощью try-catch:

try { 
    weNeedAnInt(divideConventional()) 
} catch { 
    case NonFatal(e) => // Handle? 
} 

Но если бы мы использовали divide, и скажем, это не обрабатывать исключения локально и propogated внутреннее исключение наружу:

def yetMoreIntsNeeded(i: Int) = i + 64 

val result = divide.map(weNeedAnInt).map(yetMoreIntsNeeded) match { 
    case Failure(e) => -1 
    case Success(myInt) => myInt 
} 

println(s"Final output was: $result") 

Разве это не проще? Возможно, я думаю, что это имеет некоторую субъективность ответа, я считаю его более чистым. Представьте, что у нас был длинный трубопровод таких операций, мы можем составить каждый Try[T] к следующему, и только беспокоиться о проблемах, когда по завершении конвейера.