很少使用“ ControlFlowException”

控制流是命令式编程的“遗留物”,它已泄漏到其他各种编程范例中,包括Java的面向对象范例 。 除了有用的和无处不在的分支和循环结构外,还包括原语(例如GOTO)和非局部变量(例如异常)。 让我们仔细看看这些有争议的控制流技术。

goto是Java语言中的保留字 。 goto也是JVM字节码中的有效指令。 但是,在Java中,执行goto操作并不容易。 可以从以下堆栈溢出问题中获取一个示例 :

向前跳

label: {// do stuffif (check) break label;// do more stuff
}

在字节码中:

2  iload_1 [check]3  ifeq 6          // Jumping forward6  ..

向后跳

label: do {// do stuffif (check) continue label;// do more stuffbreak label;
} while(true);

在字节码中:

2  iload_1 [check]3  ifeq 96  goto 2          // Jumping backward9  ..

当然,这些技巧仅在非常罕见的情况下才有用,即使那样,您可能仍要重新考虑。 因为我们都知道在代码中使用goto会发生什么:

取自xkcd的图形: http : //xkcd.com/292/

打破控制流与例外

异常是在发生错误或故障时突破控制流结构的好工具。 但是也可以使用异常来定期向下跳转(没有错误或失败):

try {// Do stuffif (check) throw new Exception();// Do more stuff
}
catch (Exception notReallyAnException) {}

这就像前面提到的涉及标签的技巧一样让人感到困惑。

合法使用异常控制流:

但是,在其他一些非常罕见的情况下,异常是摆脱复杂的嵌套控制流(没有错误或失败)的好工具。 当您使用SAXParser解析XML文档时,可能就是这种情况。 也许,您的逻辑将要测试至少三个<check/>元素的出现,在这种情况下,您可能希望跳过对文档其余部分的分析。 这是实现上述内容的方法:

创建一个ControlFlowException

package com.example;public class ControlFlowException 
extends SAXException {}

请注意,通常,您可能更喜欢使用RuntimeException ,但是SAX合同要求处理程序实现抛出SAXException

在SAX处理程序中使用该ControlFlowException

package com.example;import java.io.File;import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;public class Parse {public static void main(String[] args) throws Exception {SAXParser parser = SAXParserFactory.newInstance().newSAXParser();try {parser.parse(new File("test.xml"),new Handler());System.out.println("Less than 3 <check/> elements found.");} catch (ControlFlowException e) {System.out.println("3 or more <check/> elements found.");}}private static class Handler extends DefaultHandler {int count;@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) {if ("check".equals(qName) && ++count >= 3)throw new ControlFlowException();}}
}

何时将异常用于控制流:

对于SAX,上述实践似乎是合理的,因为SAX合同期望发生此类异常,即使在这种情况下,它们不是异常而是常规控制流。 以下是在实际示例中何时使用上述做法的一些提示:

  • 您想突破复杂的算法(而不是简单的块)。
  • 您可以实现“处理程序”以将行为引入复杂的算法中。
  • 这些“处理程序”明确允许在合同中抛出异常。
  • 您的用例不会真正重构复杂算法。

真实示例:使用jOOQ进行批处理查询

在jOOQ中 ,可以“批量存储”记录的集合。 jOOQ不会为每个记录运行单个SQL语句,而是会收集所有SQL语句并执行JDBC批处理操作以一次存储所有这些SQL语句。

由于每条记录都以面向对象的方式封装了给定store()调用的生成的SQL渲染和执行,因此以可重用的方式提取SQL渲染算法而不破坏(或暴露)太多东西将非常棘手。 相反,jOOQ的批处理操作实现了以下简单的伪算法:

// Pseudo-code attaching a "handler" that will
// prevent query execution and throw exceptions
// instead:
context.attachQueryCollector();// Collect the SQL for every store operation
for (int i = 0; i < records.length; i++) {try {records[i].store();}// The attached handler will result in this// exception being thrown rather than actually// storing records to the databasecatch (QueryCollectorException e) {// The exception is thrown after the rendered// SQL statement is availablequeries.add(e.query());                }
}

一个真实的例子:异常变化的行为

jOOQ的另一个示例显示了此技术如何可用于引入仅在极少数情况下适用的异常行为。 如问题#1520中所述 ,某些数据库在每个语句可能的绑定值数量方面存在限制。 这些是:

  • SQLite:999
  • 英格莱斯10.1.0:1024
  • Sybase ASE 15.5:2000
  • SQL Server 2008年:2100

为了规避此限制,一旦达到最大值,jOOQ必须内联所有绑定值。 由于jOOQ的查询模型通过应用复合模式大量封装了SQL呈现和变量绑定行为,因此在遍历查询模型树之前无法知道绑定值的数量。 有关jOOQ的查询模型架构的更多详细信息,请考虑以下先前的博客文章: http ://blog.jooq.org/2012/04/10/the-visitor-pattern-re-visited

因此,解决方案是呈现SQL语句并计算将要呈现的绑定值。 规范的实现将是以下伪代码:

String sql;query.renderWith(countRenderer);
if (countRenderer.bindValueCount() > maxBindValues) {sql = query.renderWithInlinedBindValues();
}
else {sql = query.render();
}

可以看出,规范的实现将需要两次渲染SQL语句。 第一个渲染仅用于计算绑定值的数量,而第二个渲染将生成真实的SQL语句。 这里的问题是,一旦异常事件(绑定值太多)发生,异常行为就应该被放置。 更好的解决方案是引入一个“处理程序”,在常规的“渲染尝试”中对绑定值进行计数,并为绑定值数量超过最大值的少数例外“尝试”抛出ControlFlowException

// Pseudo-code attaching a "handler" that will
// abort query rendering once the maximum number
// of bind values was exceeded:
context.attachBindValueCounter();
String sql;
try {// In most cases, this will succeed:sql = query.render();
}
catch (ReRenderWithInlinedVariables e) {sql = query.renderWithInlinedBindValues();
}

第二种解决方案更好,因为:

  • 我们仅在例外情况下重新呈现查询。
  • 我们还没有完成呈现查询以计算实际计数,而是提早中止以重新呈现。 即我们不在乎是否有2000、5000或100000绑定值。

结论

与所有特殊技术一样,请记住在正确的时机使用它们。 如有疑问,请三思。

参考:在JAVA,SQL和JOOQ博客上, JCG合作伙伴 Lukas Eder 很少使用“ ControlFlowException” 。

翻译自: https://www.javacodegeeks.com/2013/05/rare-uses-of-a-controlflowexception.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java的if里有多个if_代码里写很多if会影响效率吗?

看你怎么写 if.嵌入很多层if的代码叫做“箭头代码”&#xff0c;是一个anti-pattern。 这种代码会增加程序的循环复杂度 (Cyclomatic complexity)具体可以看这里&#xff1a;Flattening Arrow Code这里&#xff1a;总的来说&#xff0c;程序里用if-else是有开销的。每次conditi…

python基础总结(6)

一、模块。 一个模块就是一个python文件&#xff0c;.py文件。 需要注意的是&#xff1a;自己创建模块时要注意命名&#xff0c;不能和Python自带的模块名称冲突。例如&#xff0c;系统自带了sys模块&#xff0c;自己的模块就不可命名为sys.py&#xff0c;否则将无法导入系统自…

[10.10模拟] water

题意&#xff1a; 有一块矩形土地被划分成 n*m 个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。一场大雨后,由于地势高不同,许多地方都积存了不少降水。给定每个小块的高度,求每个…

使用Amazon Web Services(EC2)

正如我上周参加技术动手AWS培训之前所发布的。 这些天的课程当然是我以前使用过的标准EC2和S3服务。 除此之外&#xff0c;我们还使用了RDS &#xff0c; Elastic Load Balancing &#xff0c; SNS和VPC &#xff0c; Elastic Beanstalk并讨论了许多术语和业务案例。 在本文中&…

java整型和浮点型_Java基本的程序结构设计 整形和浮点型

整形&#xff1a;int 4字节short 2字节long 8字节byte 1字节int的大小差不多是20亿。整形计算如果两个int进行加减乘除数学运算的时候&#xff0c;最终的结果仍然是int&#xff0c;有可能出现了溢出&#xff0c;那么结果就不是我们想要的了。如下&#xff1a;System.out.printl…

盒子模型阴影设置,爱奇艺阴影配置

box-shadow的配置阴影 ul li:hover{ border-color: #dfdfdf; border-radius: 10px; -moz-box-shadow: 0 5px 5px rgba(0, 0, 0, 0.1), 0 0 10px 0 rgba(0, 0, 0, 0.2); -webkit-box-shadow: 0 5px 5px rgba(0, 0, 0, 0.1), 0 0 10px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 5px 5…

Linux在线扫描热添加的SCSI/iSCSI设备

SCSI接口具有应用范围广、多任务、带宽大、CPU占用率低&#xff0c;以及热插拔等优点&#xff0c;在服务器中广泛的应用。 当然在虚拟化平台支持下&#xff0c;也能模拟出SCSI设备&#xff0c;方便在虚拟机上热添加SCSI设备&#xff08;一般是硬盘&#xff09; 但是在热添加SCS…

第四周PSP

1.本周PSP 2.本周进度条 3.本周累计进度图 代码积累折线图 博文字数积累折线图 4.本周PSP饼状图 转载于:https://www.cnblogs.com/yuanyue-nenu/p/7648565.html

适用于JDeveloper 11gR2的Glassfish插件

众所周知&#xff0c; ADF Essentials是使用Java构建Web应用程序的绝佳框架&#xff0c;它可以自由开发和部署。 您可以在Glassfish&#xff08;3.1&#xff09;服务器上部署ADF Essentials应用程序。 但是&#xff0c;JDeveloper并不带有嵌入式Glassfish服务器&#xff0c;而是…

java 李刚 pdf_Java数据库技术详解(李刚) PDF_源雷技术空间

资源名称&#xff1a;Java数据库技术详解(李刚) PDF第一篇 数据库基础篇第1章 Java和数据库 21.1 Java概述 21.1.1 跨平台性 21.1.2 面向对象 21.1.3 安全性 31.1.4 简单性 31.1.5 健壮性和自动内存管理 31.2 Java的开发和运行环境 31.2.1 JDK的安装 31.2.2 配置JDK的环境变量 …

html css3模拟心的跳动

<!DOCTYPE html> <html> <head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><title>模拟心的跳动</title> </head> <style type"text/css">* {m…

-------------------前端技术文章收集-------------------

十个最常见的lodash方法 十个必备的js工具函数 (英文原文) You dont need 系列 underscore常用方法 (长期更新) 转载于:https://www.cnblogs.com/skura23/p/7649405.html

bzoj4152: [AMPPZ2014]The Captain

水。。。 这个建边排序一下从一边连向一边 dij在这种稀疏图果然不够优秀啊。只是学了一发。 #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> usin…

使用Hibernate的JPA 2.0标准查询

JPA 2.0中引入了条件查询 。 借助条件查询&#xff0c;您可以以类型安全的方式编写查询。 在进行标准查询之前&#xff0c;开发人员必须通过构建基于对象的查询定义来编写查询。 构建查询时&#xff0c;可能会出现语法错误的情况。 条件查询API提供了创建具有编译时安全性的结构…

response对象的使用

使用response对象提供的sendRedirect()方法可以将网页重定向到另一个页面。重定向操作支持将地址重定向到不同的主机上&#xff0c;这一点与转发是不同的。在客户端浏览器上将会得到跳转地址&#xff0c;并重新发送请求链接。用户可以从浏览器的地址栏中看到跳转后的地址。进行…

java 菜单 分隔符_在Java中使用分隔符连接值列表最优雅的方法是什么?

我从来没有找到一个整洁(呃)的方式来做以下事情.说我有一个列表/数组的字符串.abcdefghijkl我想将它们连接成一个由逗号分隔的单个字符串,如下所示&#xff1a;abc,def,ghi,jkl在Java中,如果我这样写(原谅语法),String[] list new String[] {"abc","def",…

thinkphp3.2----实现伪静态和路由配置

URL模式&#xff1a; 0.普通 http://localhost/qixin/ThinkCMF(test)_backup/index.php?guser&mlogin&aindex    带有&#xff1f;号这种传参路径&#xff0c;对SEO不友好 1.pathinfo http://localhost/qixin/ThinkCMF(test)_backup/index.php/user/login/ind…

Cmder - 在右键菜单添加Cmder Here

使用命令行或终端工具的时候都有一个让我们觉得麻烦的问题&#xff0c;就是需要cd很多目录达到目标位置。在可视化操作系统下面我们一般都是已经处在目标目录了&#xff0c;这时需要执行某些命令如&#xff1a; python test.py   现在只需要右键点击"Cmder Here"即…

标题:a 和 a的区别

以前我也是老搞不懂a 和 a的区别, 后来看了很多资料, 终于总结出来一条规律, 小白专用! 看完这个例子就懂了: 例1:$a 8, 求 a a - --a a-- a得多少? 旧值: 8 9 10 9 8 a a - --a a-- a 新值: 9 …

Java EE CDI处理程序方法示例

这是CDI Disposer方法的教程。 在CDI中&#xff0c;由于Producer方法生成的对象随后可以注入到应用程序中&#xff0c;因此使用Disposer方法&#xff0c;以便在其工作完成时将其删除。 Disposer方法始终与Producer方法匹配。 Disposer方法的使用示例是应用程序使用与数据库的连…