以下是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()
}
}
它在上抱怨
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)
} catch {
case e: Exception => { e.printStackTrace(); Nil; }
}
Scala的一种标准方法是返回一个Option
,这让调用者清楚地知道发生了什么:
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
专门用于此目的,它为这些概念提供了有意义的名称,并添加了许多有用的方法。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)) }
(略有不同,Try { ... }
也捕获了一些Error
)。
它抱怨,因为不是所有分支都返回结果:
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
}
}
Something和Unit的常见类型是Any。因此,在这两种情况下(有或没有结果变量),都需要在两个分支中返回值(可能是一些伪值,比如catch情况下的空List)。
编辑
错误是不同的,因为如果没有val,编译器可以跟踪流到分支,并注意到函数返回类型和catch结果是不同的。有了val,val上没有类型约束,因此它可以很高兴地推断val result
具有Any类型,然后,当您返回结果时,它将面对函数结果类型。如果将结果类型显式指定为val result: List[String] = ...
,则错误消息将相同。
在Scala中,这样的事情应该用单元风格来做得更好:
def fun(arg: Strign*): Option[List[String]] = Try {
new MyClass(new URL(arg(0))).map(_.getRawString.toString)
}.toOption
更新
如果你看看Try's应用程序的实现,你会看到有趣的代码:
/** 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的包装器
您可以将"null"作为大多数对象和字符串类型(它们是AnyRef的子类型)的返回类型。例如,请参阅下面的
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}
}