从try-catch返回值



以下是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}
}

最新更新