Scala 从try-catch返回值
下面是Scala中的一个方法:Scala 从try-catch返回值,scala,Scala,下面是Scala中的一个方法: def method1(arg: String*): List[String] = { try { new MyClass(new URL(arg(0))) .map(x => x.getRawString.toString) } catch { case e: Exception => e.printStackTrace()
def method1(arg: String*): List[String] = {
try {
new MyClass(new URL(arg(0)))
.map(x => x.getRawString.toString)
}
catch {
case e: Exception => e.printStackTrace()
}
}
它抱怨
found : Unit
[error] required: List[String]
如果我添加了一个附加值,以便:
def method1(arg: String*): List[String] = {
val result = try {
new MyClass(new URL(arg(0)))
.map(x => x.getRawString.toString)
}
catch {
case e: Exception => e.printStackTrace()
}
result
}
它会说
found : Any
[error] required: List[String]
奇怪的是,这和第一种方法不一样吗
不管怎样,Scala处理这种情况的标准方法是什么——从
try{..}catch{..}
返回值?它抱怨,因为不是所有分支都返回结果:
def method1(arg: String*): List[String] = {
try {
new MyClass(new URL(arg(0)))
.map(x => x.getRawString.toString) // ok, here I know what to do
}
catch {
case e: Exception => e.printStackTrace() // ???? What to return here???
// ok, will return Unit
}
}
事物和单位的常见类型是Any。所以,在这两种情况下(使用或不使用结果变量)都需要返回两个分支中的值(可能是一些伪值,如catch case中的空列表)
编辑
错误是不同的,因为没有val编译器可以跟踪流到分支的错误,并注意函数返回类型和捕获结果是不同的。使用val时,val没有类型约束,因此它可以愉快地推断
val result
具有任何类型,然后,当您返回结果时,它与函数result type对抗。如果将结果类型显式指定为val-result:List[String]=…
错误消息将是相同的。在Scala中,这样的事情最好使用一元样式:
def fun(arg: Strign*): Option[List[String]] = Try {
new MyClass(new URL(arg(0))).map(_.getRawString.toString)
}.toOption
更新
如果您查看Try的apply的实现,您将看到一些有趣的代码:
/** Constructs a `Try` using the by-name parameter. This
* method will ensure any non-fatal exception is caught and a
* `Failure` object is returned.
*/
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
因此,Try只是一元链的Try/catch的包装器,问题是在出现异常的情况下,没有要返回的值。因此,您必须决定在这种情况下返回什么值。它可以是一个空列表(如果您真的不关心如何处理错误-不推荐!): 标准的Scala方法是返回一个
选项
,它向调用者说明发生了什么:
def method1(arg: String*): Option[List[String]] =
try {
Some(new MyClass(new URL(arg(0)))
.map(x => x.getRawString.toString))
} catch {
case e: Exception => { e.printStackTrace(); None; }
}
或者返回异常本身:
def method1(arg: String*): Either[Exception,List[String]] =
try {
Right(new MyClass(new URL(arg(0)))
.map(x => x.getRawString.toString))
} catch {
case e: Exception => Left(e)
}
由于这种模式比较常见,因此有一个专门用于此目的的Scala类,它为这些概念提供了有意义的名称,并添加了许多有用的方法Try[A]
封装返回A
的计算结果,或者在计算失败时封装异常:
sealed abstract class Try[+T]
final case class Success[+T](value: T) extends Try[T]
final case class Failure[+T](exception: Throwable) extends Try[T]
所以你的方法的文字重写应该是
def method1(arg: String*): Try[List[String]] =
try {
Success(new MyClass(new URL(arg(0)))
.map(x => x.getRawString.toString))
} catch {
case e: Exception => Failure(e)
}
但是Scala当然有这种模式的方法(毕竟这就是Try
的目的),所以您可以只编写
def method1(arg: String*): Try[List[String]] =
Try { new MyClass(new URL(arg(0)))
.map(x => x.getRawString.toString)) }
(也有一点不同,尝试{…}
。对于大多数对象和字符串类型(都是AnyRef的子类型),可以将“null”作为返回类型传递。例如,请参见下文
def execute_rs(sql:String): ResultSet = {
try {
println("SQL IS " + sql)
val con = DriverManager.getConnection(url, username, password)
// println("statemetn created1")
val stmt = con.createStatement()
//println("statemetn created")
//str.foreach( i =>statement.addBatch(i))
val rs = stmt.executeQuery(sql)
return rs
}
catch {
case e: SQLException=> {println("exception occured in oracle sql insertion"+e); null}
case e: Exception=> {println("Common exception occured:"+e);null}
case _:Throwable => {println("some other exception occured");null}
}
您可以用
.map{Some()}.recover{case e:Exception=>e.printStackTrace();None}.get
替换选项
,以获得类似问题的行为。@senia toOption较短,我不会这样做,因为它会产生无用的副作用。我使用操作符“try”而不是方法“try”来做吗?我不会说日志记录是无用的。@senia完全同意你的观点,但可以使用monadIt进行日志记录是有意义的。但是我的两种方法(使用和不使用val结果)之间有什么区别?它们必须返回相同的类型,但由于某些原因,错误是不同的。您可以通过重新引用异常,即e.printStackTrace(),将其用于typecheck;抛出e
或退出,即e.printStackTrace();sys.exit
,这取决于您希望发生什么-因为抛出的异常和sys.exit属于类型Nothing
,它将所有内容都子类化我们不应该使用Try companion对象来构造成功/失败吗?
def execute_rs(sql:String): ResultSet = {
try {
println("SQL IS " + sql)
val con = DriverManager.getConnection(url, username, password)
// println("statemetn created1")
val stmt = con.createStatement()
//println("statemetn created")
//str.foreach( i =>statement.addBatch(i))
val rs = stmt.executeQuery(sql)
return rs
}
catch {
case e: SQLException=> {println("exception occured in oracle sql insertion"+e); null}
case e: Exception=> {println("Common exception occured:"+e);null}
case _:Throwable => {println("some other exception occured");null}
}