It’s a fairly common programming maxim that you should not let your methods grow too large. If that happens, the maxim generally suggests you split up your behemoth method by spinning off parts of it into their own ‘helper’ methods.
I agree to the maxim, but I never really liked the solution. Helper methods are awkward; where do you put them in the source file? They should obviously ‘go with’ the method they are a helper for, but in many code houses (including for example google), you’re supposed to sort your methods in a specific order, so you’d have to prefix all your helper names with the original method name. Thus, something like:
public void enormousMethod() {
enormousMethod_doStep1();
enormousMethod_doStep2();
}
private void enormousMethod_doStep1() {
...
}
private void enormousMethod_doStep2() {
...
}
Doable, but annoying. The more serious problem is that you have to pass in variables for all state from the main method that you need, and you have to return everything that you mutate or produce in the helper method. If you mutate/produce more than 1 result, then you need to return a tuple of some sort, which is unwieldy. You also have to refactor, which IDEs can help you with, but only to an extent.
I’ve found a solution which I think is superior. We’re going to use a little known java feature: Scope blocks – you can just start a block in java, anywhere. All variables declared inside the block are no longer valid when the scope ends, just like when you use them as the block associated with a while, if, or for construct. Thus, we can have ‘methods in methods’ so to speak:
public void enormousMethod() {
/* Explanation of what step 1 is for */ {
...
}
/* Explanation of what step 2 is for */ {
...
}
}
It’s not a panacea; sometimes a helper method is the better choice. For example, you cannot just break out of a scope block, whereas with a helper method, you can (You return from the method). However, you nicely separate your behemoth method into mostly self-contained blocks that can have their own local variable names, and you have absolutely no problem sharing state in between them where that makes sense. Thus, they can all increase a counter for example.
Another more drastic trick you can do in java is to create a method local class, with state stored in that method local’s fields. If in another language you would have used an actual method-in-a-method, then that’s the nearest simile java has to offer. It’s a bit unwieldy in syntax, but in rare cases it ends up being the cleanest solution.
{ 3 } Comments
I am using blocks quite often, especially to scope initialization sequences of a just defined variable. To me, this makes code much more readable.
Regarding break out, well, one can label blocks and thus use labeled breaks. Labels may not be a very liked feature in Java, but would additionally name the blocks.
I use “naked” blocks all the time. Got into that habit in C++, where going out of scope actually called destructors which could have real effects, but now I use them if I have several code blocks that are similar enough that I want to re-use a temp var name, but don’t want to re-use the var itself, and the code blocks are not close enough to be able to refactor them into a method.
Stefan: You can break out of a lone block? Whoooooa.
I just tested it and, you’re right. Colour me surprised. Second time in a month I learn something new in java. I thought I was beyond learning new things in regards to java syntax.
This is very very cool. Thanks!