2013-12-20 28 views
1

我想開發一個控制結構,重試一些聲明的異常但拋出其他異常。控制結構很好地工作,但我有問題檢查,如果捕獲的異常屬於聲明的異常的類型。用更通用的話來說,我該如何檢查參數是否是聲明的類型參數列表之一?檢查斯卡拉重試控制結構中的多個異常

定義的重試控制結構:

def retry[T, R](times:Int=3, delay:Int=1000)(ex:Class[_<:Exception]*)(t:T)(block:T=>R):R = { 
try { 
    block(t) 
} 
catch { 
    case e:Exception if (isOneOf(e, ex:_*) && times>0) => { 
    println(s"Exception $e happened, sleep $delay milliseconds") 
    Thread.sleep(delay) 
    println(s"$times times remain for retry before give up") 
    retry(times-1, delay)(ex:_*)(t)(block) 
    } 
    case e:Throwable => { 
    println(s"Exception $e is not handled") 
    throw e 
    } 
} 

}

限定isOneOf函數來檢查聲明和運行時異常類型

def isOneOf[T:scala.reflect.ClassTag](obj:T, cs:Class[_]*) = { 
    val dc = obj.getClass 
    val rc = scala.reflect.classTag[T].runtimeClass 
    cs.exists(c=>c.isAssignableFrom(dc) || c.isAssignableFrom(rc)) 
} 

定義拋出多個異常的功能

def d(str:String) = { 
    val r = Math.random() 
    println(r) 

    if (r>0.6) throw new IllegalArgumentException 
    else if (r>0.4) throw new java.io.IOException 
    else if (r>0.2) throw new UnsupportedOperationException 
    else println(str) 
} 

而且我可以重試調用該函數爲:

retry(3, 1000)(classOf[IllegalArgumentException], classOf[java.io.IOException])("abc"){ 
    x=> d(x) 
} 

我想重試拋出:IllegalArgumentException和IOException異常,但會拋出UnsupportedOperationException異常。

我的目標是要調用的函數是這樣的:

retry(3, 1000)[IllegalArgumentException, java.io.IOException]("abc"){ 
    x=> d(x) 
} 

重試結構,宣告例外列表中在運行時動態傳遞。所以多個異常情況聲明不適用於我。當捕獲異常時,我將它與泛型異常匹配,使用isOneOf函數檢查異常類型。理想情況下,該函數將採用一系列類型,而不是一系列類。我如何傳遞一系列異常類型,而不是一系列的類,並根據類型序列檢查捕獲到的異常?

+1

實際上有很多延遲重試的實現。其中之一 - https://gist.github.com/Mortimerp9/5430595 –

+1

您不能在'retry'方法中使用可變數量的類型標識符。這不僅僅意味着它們的使用方式。您可能堅持傳遞受支持的可重試異常列表。 – cmbaxter

回答

2

你怎麼看待與知道哪些異常是可恢復的(並且可以動態建立)的功能替代的例外列表:

def retry[T, R](times: Int = 3, delay: Int = 1000)(t: T)(block: T => R)(recoverable: Throwable => Boolean): R = { 

    Try(block(t)) match { 
    case Success(value) => value 
    case Failure(throwable) => if (recoverable(throwable)) retry(times - 1, delay)(t)(block)(recoverable) else throw throwable 
    } 

} 

recoverable功能看起來是這樣的:

def recoverable(throwable: Throwable): Boolean = throwable match { 
    case exc @ (_: IllegalArgumentException | _: IOException) => true 
    case _ => false 
} 
+0

'if(可恢復(可拋出)&&次> = 0)...'在if語句中。 – aepurniet

+0

因此,必須定義一個可恢復的函數和模式聯編程序才能使用重試結構。 情況EXC @(_:拋出:IllegalArgumentException | _:IOException的)=>真 相當於 情況EXC:拋出:IllegalArgumentException =>真 情況EXC:IOException異常=>真 和兩個例外都在可恢復功能被靜態編碼。這並不能真正簡化代碼。 使用類可變參數定義,我可以構建在運行時重試的例外列表: val可恢復:Seq [Class [_ <:Exception]] =計算 並呼叫重試 重試()(可恢復)(「abc」 ){x => d(x)} – sabz

+0

你是對的,你應該對它們進行硬編碼,但是你不會像'List'那樣做嗎?我的意思是你將在'retry'函數外部創建一個帶有預定義異常的列表,同樣你也將用這些異常集動態構建一個函數。所以這個想法是讓這個列表在'重試'之外是可配置的,你可以用兩者來完成。你怎麼看? – iuriisusuk