2013-07-06 107 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} 

}