FunDA(17)- 示範:異常處理與事後處理 - Exceptions handling and Finalizers

来源:http://www.cnblogs.com/tiger-xc/archive/2017/04/02/6659185.html
-Advertisement-
Play Games

作為一個能安全運行的工具庫,為了保證占用資源的安全性,對異常處理(exception handling)和事後處理(final clean-up)的支持是不可或缺的。FunDA的數據流FDAPipeLine一般是通過讀取資料庫數據形成數據源開始的。為了保證每個數據源都能被安全的使用,FunDA提供了 ...


    作為一個能安全運行的工具庫,為了保證占用資源的安全性,對異常處理(exception handling)和事後處理(final clean-up)的支持是不可或缺的。FunDA的數據流FDAPipeLine一般是通過讀取資料庫數據形成數據源開始的。為了保證每個數據源都能被安全的使用,FunDA提供了事後處理finalizing程式介面來實現數據流使用完畢後的清理及異常處理(error-handling)程式介面來捕獲和處理使用過程中出現的異常情況。首先,事後處理程式(finalizer)保證了在任何情況下的FunDA數據流終止運算:包括元素耗盡,強制中斷以及異常中斷,finalizer都會被調用。在這篇討論里我們將會測試和示範FunDA Exception-handling和Final-cleanup。下麵的樣板代碼設定了一個靜態集合數據源viewState和一個動態數據流streamState:

  val db = Database.forConfig("h2db")
  implicit def toState(row: StateTable#TableElementType) =
    StateModel(row.id,row.name)
  val viewLoader = FDAViewLoader(slick.jdbc.H2Profile)(toState _)
  val streamLoader = FDAStreamLoader(slick.jdbc.H2Profile)(toState _)

  val stateSeq = viewLoader.fda_typedRows(StateQuery.result)(db).toSeq
  val viewState = fda_staticSource(stateSeq)(println("***Finally*** the end of viewState!!!"))
  val streamState = streamLoader.fda_typedStream(StateQuery.result)(db)(64,64)(println("***Finally*** the end of streamState!!!"))

在上面的代碼例子里我們可以看到fda_staticSource和fad_typedStream都掛接了事後處理程式,我們簡單的用println代表一段完整的程式來證實對事後處理程式的調用。所以說事後處理程式的掛接是在構建view或者stream時進行的。我們先看看它們在正常終止或者強行中斷是是否發生調用:

  viewState.startRun
  viewState.take(2).startRun
  streamState.startRun
  streamState.take(3).startRun
  //  ***Finally*** the end of viewState!!!
  //  ***Finally*** the end of viewState!!!
  //  ***Finally*** the end of streamState!!!
  //  ***Finally*** the end of streamState!!!

那麼如果在出現了異常中斷是是否同樣會被調用呢?我們先設計下麵兩個用戶自定義函數:

  def trackRows: FDAUserTask[FDAROW] = row => {
    row match {
      case m@StateModel(id,name) =>
        println(s"State: $id $name")
        println( "----------------")
        fda_next(m)
      case m@_ => fda_next(m)
    }
  }

  def errorRow: FDAUserTask[FDAROW] = row => {
    row match {
      case StateModel(id,name) =>
        val idx = id / (id - 3)
        fda_next(StateModel(idx,name))
      case m@_ => fda_next(m)
    }
  }

trackRows跟蹤顯示當前數據行,errorRow人為的會在第三行出現異常。我們用streamState來測試一下:

  streamState.appendTask(errorRow).appendTask(trackRows).startRun
//  State: 0 Alabama
//  ----------------
//  State: -2 Alaska
//  ----------------
//  Exception in thread "main" java.lang.ArithmeticException: / by zero
//  at examples.ExceptionsAndFinalizers$$anonfun$errorRow$1.apply(ExceptionsAndFinalizers.scala:46)
//  ...
//  at java.lang.Thread.run(Thread.java:745)
//  ***Finally*** the end of streamState!!!

的確在正常顯示了兩行數據後,第三行出錯中斷,直接調用了finalizer。這就保證了無論發生任何情況,當完成使用數據源後都給予編程人員一個空間去進行事後處理如釋放資源、中斷連接、關閉文件等。

我們可以用onError來掛接異常處理程式,如下:

   val s = streamState.appendTask(errorRow).appendTask(trackRows)
   val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}

註意:onError必須掛接在stream的最尾端以確保所有環節的異常情況都可以正確地得到處理。看看運行結果:

State: 0 Alabama
----------------
State: -2 Alaska
----------------
***Finally*** the end of streamState!!!
Caught Error in streamState!!![/ by zero]

以上例子捕獲了異常情況,同時在異常中斷情況後還是調用了finalizer。

有時我們需要自定義一些特殊情況,我們希望能捕獲這些情況的發生。但我們同時希望這些情況發生時不會中斷運算。首先我們可以先自定義一個異常行類型:

  case class DivideZeroError(msg: String, e: Exception) extends FDAROW

註意:切不可忘記extends FDAROW。我們把上面的errorRow函數修改成一個自捕獲異常的函數:

 def catchError: FDAUserTask[FDAROW] = row => {
    row match {
      case StateModel(id,name) =>
        try {
          val idx = id / (id - 3)
          fda_next(StateModel(idx, name))
        } catch {
          case e: Exception => //pass an error row
            fda_next(DivideZeroError(s"Divide by zero excption at ${id}",e))
        }
      case m@_ => fda_next(m)
    }
  }

必須修改trackRows能分辨DivideZeroError行:

  def trackRows: FDAUserTask[FDAROW] = row => {
    row match {
      case m@StateModel(id,name) =>
        println(s"State: $id $name")
        println( "----------------")
        fda_next(m)
      case DivideZeroError(msg, e) => //error row
        println(s"***Error:$msg***")
        fda_skip
      case m@_ => fda_next(m)
    }
  }

運算下麵的程式:

  val s = streamState.take(5).appendTask(catchError).appendTask(trackRows)
  val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
  s1.startRun

產生下麵的結果:

State: 0 Alabama
----------------
State: -2 Alaska
----------------
***Error:Divide by zero excption at 3***
State: 4 Arkansas
----------------
State: 2 California
----------------
***Finally*** the end of streamState!!!

Process finished with exit code 0

沒有出現異常中斷,捕獲並處理了自定義異常,並且調用了事後處理程式finalizer。

下麵就是這次示範的源代碼:

import slick.jdbc.H2Profile.api._
import com.bayakala.funda.samples.SlickModels._
import com.bayakala.funda._
import api._
import scala.language.implicitConversions

object ExceptionsAndFinalizers extends App {

  val db = Database.forConfig("h2db")
  implicit def toState(row: StateTable#TableElementType) =
    StateModel(row.id,row.name)
  val viewLoader = FDAViewLoader(slick.jdbc.H2Profile)(toState _)
  val streamLoader = FDAStreamLoader(slick.jdbc.H2Profile)(toState _)

  val stateSeq = viewLoader.fda_typedRows(StateQuery.result)(db).toSeq
  val viewState = fda_staticSource(stateSeq)(println("***Finally*** the end of viewState!!!"))
  val streamState = streamLoader.fda_typedStream(StateQuery.result)(db)(64,64)(println("***Finally*** the end of streamState!!!"))

/*
  viewState.startRun
  viewState.take(2).startRun
  streamState.startRun
  streamState.take(3).startRun
  //  ***Finally*** the end of viewState!!!
  //  ***Finally*** the end of viewState!!!
  //  ***Finally*** the end of streamState!!!
  //  ***Finally*** the end of streamState!!!
*/



  def trackRows: FDAUserTask[FDAROW] = row => {
    row match {
      case m@StateModel(id,name) =>
        println(s"State: $id $name")
        println( "----------------")
        fda_next(m)
      case DivideZeroError(msg, e) => //error row
        println(s"***Error:$msg***")
        fda_skip
      case m@_ => fda_next(m)
    }
  }

  def errorRow: FDAUserTask[FDAROW] = row => {
    row match {
      case StateModel(id,name) =>
        val idx = id / (id - 3)
        fda_next(StateModel(idx,name))
      case m@_ => fda_next(m)
    }
  }

  case class DivideZeroError(msg: String, e: Exception) extends FDAROW
  def catchError: FDAUserTask[FDAROW] = row => {
    row match {
      case StateModel(id,name) =>
        try {
          val idx = id / (id - 3)
          fda_next(StateModel(idx, name))
        } catch {
          case e: Exception => //pass an error row
            fda_next(DivideZeroError(s"Divide by zero excption at ${id}",e))
        }
      case m@_ => fda_next(m)
    }
  }



  /*
  streamState.appendTask(errorRow).appendTask(trackRows).startRun
//  State: 0 Alabama
//  ----------------
//  State: -2 Alaska
//  ----------------
//  Exception in thread "main" java.lang.ArithmeticException: / by zero
//  at examples.ExceptionsAndFinalizers$$anonfun$errorRow$1.apply(ExceptionsAndFinalizers.scala:46)
//  ...
//  at java.lang.Thread.run(Thread.java:745)
//  ***Finally*** the end of streamState!!!
*/
  /*
   val v = viewState.appendTask(errorRow).appendTask(trackRows)
   val v1 = v.onError {case e: Exception => println(s"Caught Error in viewState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
   v1.startRun

   val s = streamState.appendTask(errorRow).appendTask(trackRows)
   val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
   s1.startRun
  */

  val s = streamState.take(5).appendTask(catchError).appendTask(trackRows)
  val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
  s1.startRun


}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 12:變幻的矩陣 12:變幻的矩陣 查看 提交 統計 提問 查看 提交 統計 提問 總時間限制: 1000ms 記憶體限制: 65536kB描述 有一個N x N(N為奇數,且1 <= N <= 10)的矩陣,矩陣中的元素都是字元。這個矩陣可能會按照如下的幾種變幻法則之一進行變幻(只會變幻一次)。 現 ...
  • 線性表之順序表 一、頭文件:SeqList.h //順序線性表的頭文件#include<iostream> const int MaxSize = 100;//定義順序表SeqList的模板類template<class DataType>class SeqList{public: //順序表無參構 ...
  • JSR330 DI JSR 330 ,提供了一種可重用的、可維護、可測試的方式來獲取Java對象。也稱為Dependency Injection 。 DI應該都不陌生,因為它就是Spring core之一。在Spring盛行後,Google也提供了一種DI實現:Guice。因為這兩個DI容器的盛行, ...
  • 一、單例模式(Singleton) 1、單例模式應用場景: ①Servlet ②任務管理器 ③鏈接池 ④Spring中每個 bean 預設是單例 ⑤網站計數器 2、單例要求 ①構造器私有 ②私有的靜態變數 ③公共的靜態的可以訪問私有的靜態變數的方法 結論:由結果可以得知單例模式為一個面向對象的應用程 ...
  • 我在mvc配置文件中加上下麵這個配置就好了 <mvc:annotation-driven></mvc:annotation-driven>,需要在開頭引用如下命名空間xmlns:mvc="http://www.springframework.org/schema/mvc 它自動配置DefaultAn ...
  • 聲明 轉載請註明出處! Reprint please indicate the source! http://www.hiknowledge.top/?p=86&preview=true 什麼是JMS JMS即Java消息服務(Java Message Service)應用程式介面,是一個Java平 ...
  • 在牛客網上做到的一道題,挺簡單基礎的,不過也寫一下,哈哈! 統計一個數字在排序數組中出現的次數: 可定義一個用於統計數字個數的變數count,然後從前往後遍曆數組,看是否與所求數字相等,如果相等,則count++; 下麵貼出代碼: public class Solution { public int ...
  • 這段時間在做項目,發現自己忘得好快呀,幸虧有博客園幫我記著呢,整理博客園簡直不要太重要了哦 因為做的是一個內部管理系統,只用了一個主頁面,所有的都不允許整個網頁刷新,所以我們只能用ajax 來做,當然剛開始做也走了很多的彎路,最終還是做出來了 這點還是比較欣慰的 今天要整理一下ajax實現修改功能 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...