很少使用“ 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) {}這就像前面提到的涉及標簽的技巧一樣讓人感到困惑。
合法使用異??刂屏?#xff1a;
但是,在其他一些非常罕見的情況下,異常是擺脫復雜的嵌套控制流(沒有錯誤或失敗)的好工具。 當您使用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綁定值。
結論
與所有特殊技術一樣,請記住在正確的時機使用它們。 如有疑問,請三思。
翻譯自: https://www.javacodegeeks.com/2013/05/rare-uses-of-a-controlflowexception.html
總結
以上是生活随笔為你收集整理的很少使用“ ControlFlowException”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ddos攻击手段教程(ddos攻击攻击步
- 下一篇: 使用Amazon Web Service