从try-catch返回一个值

时间:2013-07-06 07:56:45

标签: 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()
        }
}

抱怨

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 { .. }返回一个值?

4 个答案:

答案 0 :(得分:28)

问题是,在异常的情况下,没有值返回。所以你必须决定在这种情况下返回什么值。它可以是一个空列表(如果你真的不关心处理错误 - 不推荐!):

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 { ... }catches some Errors)。

答案 1 :(得分:5)

它抱怨,因为并非所有分支都返回结果:

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 and Unit的常见类型是Any。因此,在两种情况下(使用或不使用结果变量),您需要做的是在两个分支中返回值(可能是一些虚拟值,如catch case中的空List)。

修改

错误是不同的,因为没有val编译器可以跟踪该流向下到分支并注意函数返回类型和捕获结果是不同的。对于val,val没有类型约束,因此它可以很高兴地推断 val result具有任何类型,然后,当您返回结果时,它会遇到函数结果类型。如果您明确指定结果类型为val result: List[String] = ...,则错误消息将相同。

答案 2 :(得分:4)

在Scala中,使用monadic风格应该更好地完成这些事情:

def fun(arg: Strign*): Option[List[String]] = Try {
    new MyClass(new URL(arg(0))).map(_.getRawString.toString)
}.toOption

<强>更新

如果你看一下Try的应用实现,你会看到并感兴趣的代码:

/** 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 for monadic chaining的包装器

答案 3 :(得分:0)

你可以传递&#34; null&#34;作为大多数对象和字符串类型(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}

}