作为一个能安全运行的工具库,为了保证占用资源的安全性,对异常处理(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)(,)(println("***Finally*** the end of streamState!!!"))

在上面的代码例子里我们可以看到fda_staticSource和fad_typedStream都挂接了事后处理程序,我们简单的用println代表一段完整的程序来证实对事后处理程序的调用。所以说事后处理程序的挂接是在构建view或者stream时进行的。我们先看看它们在正常终止或者强行中断是是否发生调用:

  viewState.startRun
viewState.take().startRun
streamState.startRun
streamState.take().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 - )
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:  Alabama
----------------
State: - 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 - )
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().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:  Alabama
----------------
State: - Alaska
----------------
***Error:Divide by zero excption at ***
State: Arkansas
----------------
State: California
----------------
***Finally*** the end of streamState!!! Process finished with exit code

没有出现异常中断,捕获并处理了自定义异常,并且调用了事后处理程序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)(,)(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 - )
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 - )
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().appendTask(catchError).appendTask(trackRows)
val s1 = s.onError {case e: Exception => println(s"Caught Error in streamState!!![${e.getMessage}]"); fda_appendRow(FDANullRow)}
s1.startRun }

FunDA(17)- 示范:异常处理与事后处理 - Exceptions handling and Finalizers的更多相关文章

  1. Python学习(17)异常处理

    目录 Python 异常处理 Python 标准异常 异常处理 使用except而不带任何异常类型 使用except而带多种异常类型 try-finally 语句 异常参数 异常的参数 用户自定义参数 ...

  2. DRF之权限认证,过滤分页,异常处理

    1. 认证Authentication 在配置文件中配置全局默认的认证方案 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_f ...

  3. DRF的异常处理

    默认情况下,DRF框架通过内置的 exception_handler 方法,处理了如下异常: django内置异常 Http404 PermissionDenied DRF框架异常 APIExcept ...

  4. drf07 过滤 排序 分页 异常处理 自动生成接口文档

    4. 过滤Filtering 对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持. pip install django-filter 在配置文件sett ...

  5. Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the connection string near ';characterEncoding=UTF

    今天在使用springboot整合SSM的时候,配置好以后启动项目,报了一个这样的异常 java.sql.SQLNonTransientConnectionException: Cannot load ...

  6. django-rest-framework-源码解析002-序列化/请求模块/响应模块/异常处理模块/渲染模块/十大接口

    简介 当我们使用django-rest-framework框架时, 项目必定是前后端分离的, 那么前后端进行数据交互时, 常见的数据类型就是xml和json(现在主流的是json), 这里就需要我们d ...

  7. MasaFramework -- 异常处理

    前言 在程序设计中,我们会遇到各种各样的异常问题,一个异常处理不仅仅可以帮助开发者快速的定位问题,也可以给用户更好的使用体验,那么我们在AspNetCore项目中如何捕获以及处理异常呢? 而对应Asp ...

  8. (05)odoo数据库和业务操作

    以一个例子开头* To-do 向导   # 配置文件       __openerp_.py:         { 'name': 'To-do Tasks Management Assistant' ...

  9. linux中断源码分析 - 初始化(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 本篇文章主要讲述源码中是如何对中断进行一系列的初始化的. 回顾 在上一篇概述中,介绍了几个对于中断来说非常重要的 ...

随机推荐

  1. Windows-universal-samples学习笔记系列二:Controls, layout, and text

    Controls, layout, and text AutoSuggestBox migration Clipboard Commanding Context menu Context menu ( ...

  2. Java第1章笔记

    第一章 计算机程序:计算机为完成某些功能产生的一系列有序指令集合. Java技术包括:JavaSE(标准版)  JavaEE(企业版) ---JavaME(移动版) 开发Java程序步骤:1.编写 2 ...

  3. oracle 中删除表 drop delete truncate

    oracle 中删除表 drop delete truncate   相同点,使用drop delete truncate 都会删除表中的内容 drop table 表名 delete from 表名 ...

  4. 整合SPRING CLOUD云服务架构 - 企业分布式微服务云架构构建

    整合SPRING CLOUD云服务架构 - 企业分布式微服务云架构构建 1.   介绍 Commonservice-system是一个大型分布式.微服务.面向企业的JavaEE体系快速研发平台,基于模 ...

  5. 【转】MongoDB导入导出以及数据库备份

    -------------------MongoDB数据导入与导出------------------- 1.导出工具:mongoexport     1.概念:         mongoDB中的m ...

  6. php mongodb driver

    yum install -y PHP-devel php-pear httpd-devel pecl install mongo 执行以上命令后,你需要修改php.ini文件,在php.ini文件中添 ...

  7. JSON转JS对象,JS对象转JSON

    一.从服务端发来的json字符串,怎么才能作为JavaScript对象(JSON对象)在web端调用呢? 1.如果使用jQuery,就很方便了,可以在ajax一系列函数中,把参数Datatype传js ...

  8. pytorch总结

    PyTorch 深度学习:60分钟快速入门 用例子学习 PyTorch 手把手教你用PyTorch从零搭建图像分类模型

  9. AI学习经验总结

    我的人工智能学习之路-从无到有精进之路 https://blog.csdn.net/sinox2010p1/article/details/80467475 如何自学人工智能路径规划(附资源,百分百亲 ...

  10. IntelliJ IDEA 2017版 spring-boot 2.0.3 邮件发送搭建,概念梳理 (一)

    邮件发送功能总结        第一部分 背景   一.使用场景 (1)注册验证    注册各大网站,通常需要输入邮件地址,在注册成功后,会发送一封邮箱验证的邮件,点击确认,证明这个邮箱是用户自己的 ...