2013-07-06 43 views
10

这里的值是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() 
     } 
} 

如果我增加了一个附加价值,使其抱怨上

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

+1

您可以通过重新抛出异常来得到此类型,即'e.printStackTrace();抛出e'或退出,即'e.printStackTrace(); sys.exit',这取决于你想要发生什么 - 因为抛出的异常和sys.exit的类型是'Nothing',它将所有的东西都分为 –

回答

23

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

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只是为了这个目的,它给了这些概念有意义的名称并增加了许多hel有趣的方法。 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)。

+0

这是一个很好的答案! –

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 
     } 
} 

常见类型的东西,单位为所有。因此,在这两种情况下(带有或不带结果变量)你需要做的是在两个分支中返回值(可能是一些虚拟值,如catch catch中的空List)。

编辑

的错误是不同的,因为没有VAL编译器可以跟踪流下来到分支,请注意函数的返回类型和catch结果是不同的。随着VAL没有就没有VAL类型约束,因此它可以愉快地推断val result有什么类型,然后,当你回来时导致其与功能的结果类型面对。如果您明确指定结果类型为val result: List[String] = ...,则错误消息将相同。

+0

这很有道理。但是我的方法(使用和不使用val结果)有什么区别?他们必须返回相同的类型,但出于某种原因,错误是不同的。 –

+0

@MariusKavansky请参阅更新 –

4

在Scala中这样的事情应该单子风格可以更好地完成:

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

更新

如果你看一下尝试执行的申请,你会看到和有趣的代码:

/** 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/catch语句的包装为一元链接

+1

您可以用'.map {一些(_)}替换'toOption'。无} .get'来获得类似问题的行为。 – senia

+0

@senia toOption更短,我不会这样做,因为没有用处的副作用 – 4lex1v

+0

如何使用运算符“try”而不是“Try”方法来做到这一点? –

0

对于大多数对象和字符串类型(它们是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} 

}