Scala 从try-catch返回值

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()

下面是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) // 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}

}