4 September 2011
The labeled break in Java
Trying to optimize the Android app I'm working on and found this Java feature that I'm sure I knew at one point but ignored as useless. My mistake.
The code I'm working on is in the script parser. The parser has one class method per grammar rule (e.g. parser.processStatement() or parser.processExpression()) following general top-down parsing practice. Within each method/rule, the parser can fail on a token without being certain that the token won't satisfy a subsequent rule. For example: if processStatementLoop() is called before processStatementConditional() and an "if" is the first token encountered in the script, the token stack (and possibly other internal structures) needs to rewind after processStatementLoop() fails on "if". The parser needs to know that the grammar has not yet accepted the "if" as valid. So, a rule may fail on a valid script.
When the grammar was small, I started with various conditionals peppered through each method, unwinding the relevant structures if the rule failed. I changed the conditionals to exceptions because it was easier to manage multiple failures within a single rule. However, the exceptions could be thrown either because of an error in the script or because of simple backtracking in the grammar. The latter isn't a true exception, and so this could be considered misuse of the exception construct.
private boolean processStatementLoop() { transaction.begin(); try { if (!processToken(TOKEN_FOR, true)) { throw new ScriptException(tokenizer); } // ... } catch (ScriptException e) { transaction.rollback(); return false; } transaction.end(); return true; }
And so I pondered and searched on a substitute for the exception in this instance. I'm not sure how I found it, but the Java doc article Branching Statements described the mysterious labeled break. Using this, you can break out of a block a la the "beloved" retro GOTO statement:
private boolean processStatementLoop() { transaction.begin(); Transaction: { if (!processToken(TOKEN_FOR, true)) { break Transaction; } // ... transaction.end(); return true; } transaction.rollback(); return false; }
This (should) avoid the cost of exception construction and stack unwinding, but more importantly it more closely maps the code's intent.
- Techniques after using Swift for a month posted by sstrader on 26 August 2015 at 11:41:51 PM
- Some thoughts on Ruby after finishing a week (minus one day) of training posted by sstrader on 15 December 2011 at 8:59:30 PM
- Links on the singleton pattern posted by sstrader on 9 December 2011 at 9:19:50 AM
- Phonebot posted by sstrader on 29 October 2011 at 6:37:05 PM
- The labeled break in Java posted by sstrader on 4 September 2011 at 11:27:56 AM