Yet Another Java Trick

Recently I ran into a bit of trouble when coding a particular method. It had a number of exit points, something like this:
[java]
boolean method() {
if (conditionA)
return resultA;

if (conditionB)
return resultB;

if (conditionC)
return resultC;
}
[/java]

The problem was that I also needed to log the result before exiting. Since there was a lot of exit points I had a choice of two usual options:

  1. Log the result at each exit point
  2. Introduce a result variable and convert exit points to if blocks

I didn’t like either of them. The first introduces copy-paste, while the second makes method more complex (blocks are harder to follow than test-and-exit idiom).

Therefore I did something different:
[java]
boolean method() {
boolean result = false;

try {
if (conditionA)
return (result = resultA);

if (conditionB)
return (result = resultB);

if (conditionC)
return (result = resultC);
}
finally {
log(result)
}
}
[/java]

The idiom basically makes the return value available in the finally clause. It’s quite concise and the only gotcha is that on an exception the value will be initialized to the default one. Happy coding!

Tags: ,

  • http://robbyoconnor.blogspot.com Robert O’Connor

    Nice!

  • Jevgeni Kabanov

    Thanks!

  • Taylor Gautier

    Great!! I agree, if statements would have been a poor choice. This idiom makes you wish there was an implicit “try” at the method level, so you could skip the try and write just “finally { }” at the bottom of the method.

  • contrapunctus

    really “chic” trick, thx:)

  • Jevgeni Kabanov

    It’s not that bad. If you add a language idiom for every case you end up with perl :) try-finally has explicit scoping and it’s a good thing.

  • Dhanaraj

    Nice trick.

    AOP would be other choice; have an after-method advice implementation

  • Jevgeni Kabanov

    Dhanaraj: AOP is an overkill for such a small case. I would already rather wrap the method in another method that’d do the logging. But this was better :)

  • anonymous

    hmm.. my guess is that the given code doesn’t compile..

  • http://cime.net/~ricky/ Ricky Clarkson

    boolean method() {
    return log(conditionA ? resultA : conditionB ? resultB : conditionC ? resultC : false); }

    Make log return whatever you pass it and that is possible. The great failure is that ‘if’ isn’t an expression form. Please, if anybody reading this makes a new language, ignore C and related syntax!

  • Jevgeni Kabanov

    Ricky: I simplified for the example, conditions are not exclusive and some of them had for loops and etc. Blocks are not expressions in Java so it won’t work in any complex case.

    anonymous: it’s pseudocode, of course it won’t compile.

  • http://cime.net/~ricky/ Ricky Clarkson

    Jevgeni, yes, for loops are a problem. I try to replace them with map/filter etc. where possible.

  • Lorne Malec

    It is a trick alright, but you really think this is really more complex than what you wrote????

    1. boolean method() {
    2. boolean result = false;
    3.
    4. if (conditionA)
    5. result = resultA;
    6.
    7. else if (conditionB)
    8. result = resultB;
    9.
    10. else if (conditionC)
    11. result = resultC;
    12.
    13. log(result)
    14. return result;
    15. }

  • Jevgeni Kabanov

    Lorne: this works only if conditions are simple, whereas in my original example one of the returns was inside a for loop

    In real code the conditions will almost never be such one-liners, I only written them like that to simplify the example pseudocode. For the particular example I brought your code is simpler.

    EDIT: Wait, in this case exclusivity is not that important :) else if is already exclusive, my fault.

  • Jevgeni Kabanov

    Lorne: thanks for putting me to think some more :) This idiom does make more sense when it doesn’t fit easily into if-then-else branching. Though I still think that multiple exit points are more comfortable, e.g. you can have common logics for several branches easily.

    In the end it’s not like it’s the way to do all of your conditional logic from now on, just a small trick I came up with for my own code and wondered what will others think about it.

  • http://my.opera.com/karmazilla/blog/ Christian Vest Hansen

    I knew before I saw the code that you were going to do the try-fianlly trick, although, deep inside, something was teling me “As… spect… Jay…” – if only it was accepted as part of Java itself and the compiler wasn’t so buggy.

    You might think AOP is overkill, but can you be sure you won’t need the same kind of logging somewhere else? Plus, if the method is already complex, then wrapping the whole thing in a try-finally would be an aesthetic downgrade I really don’t want to do. You could refactor the method and make it less complex, but that won’t make try-finally prettier in my view. :-)

  • http://jroller.com/eu Eugene Kuleshov

    Yuck! try/finally really isn’t really meant for something like that, nor using statements in returns making code readable. If AOP is not acceptable, I would rewrite it like:

    boolean method() {
    boolean result = calculateResult();
    log(result);
    return result;
    }

  • Jevgeni Kabanov

    Christian: I’m pretty sure I won’t need such logging somewhere, the log string is specific to the method. It is definitely in no way a reusable aspect.

    Eugene: Try/finally has a very clear semantics. Do you have troubles understanding the code?

    Yes a wrapper method would be an alternative, as I already mentioned in comments. But I don’t see how is it better than this. I don’t think AOP is a good idea unless it helps you to abstract something.

    I like that this created such a discussion, with some people clearly liking it and some clearly disliking it. It just goes to prove that programming is just as much art as science.

  • http://www.freshvanilla.org:8080 peter lawrey

    That could make for alot of code to change, and you might miss a return point. If you have more than one developer she might not know that this method has to be returned that way.
    Another approach is to rename the method to a private method and call that.

    boolean method() {
    boolean result = method0();
    log(“method() = “+result);
    return result;
    }

    private boolean method0() {

    This is a good use case for aspect orientated programming as you can log the return value without changing the method itself.

  • http://tmorris.net/ Tony Morris

    Sure does suck not having monads or any high-level constructs in such a broken language, doesn’t it?

  • Jevgeni Kabanov

    Tony: I programmed in Haskell for some time, and I prefer Java (here comes the flame of a thousand Haskellers). I might prefer Scala to Java, but even that has a lot of quirks and is getting overly complicated.

    Funnily enough Monads are one of the reasons I dislike Haskell, esp. the IO Monad. Clean had a much better solution for IO with uniqueness typing (which you could easily build a number of monads on, if you were so willing).

    Anyway, it’s a discussion for a different thread, but I don’t think that Java is specially broken way beyond fixing. It just needs closures and a bit more sugar to achieve most that you want (e.g. painless DSLs).

  • http://my.opera.com/behrangsa Behrang

    @Tony

    Sure does suck being dogmatic and living in a pure-functional world that I/O is such an alien that needs a whole distinct approach to handle! And it even sucks more that one’s beloved language has no place in the real world and is being used only as an academic language. LOL. Hahaha.

  • Jevgeni Kabanov

    @Behrang No need to be offensive, both Java and Haskell have their merits.

  • kretes

    Well – actually -> the real Aspect approach would be to seperate the logging from the rest of logic in the application. Then You wouldn’t have to write any wrapper for your method nor introduce not easy readable and straight solution with try-finally. You would just have to specify in the aspect, that You have to log something , while finishign executing of this method. In my opinion – AOP is a thing that should be another step into beatufil software architecture.

    Anyway – nice trick ;-)

  • http://rauschma.blogspot.com/ Axel Rauschmayer

    How about the following?

    public static X log(X arg) {
    logItSomehow(arg);
    return arg;
    }

    Then you can write the following (which is more conventional than your code, but also smaller and almost AOP):

    boolean method() {
    if (conditionA) return log(resultA);
    if (conditionB) return log(resultB);
    if (conditionC) return log(resultC);
    }

  • Jevgeni Kabanov

    Axel: It’s a matter of taste. But I think that if you are already creating extra methods then delegating the actual functionality is better than delegating the logging (that is you should rename the method() to doMethod() and create a method() that does the logging).

  • Adrian Kuhn

    Cool.
    Reminds me of this trick (encountered first in the sources of javac itself!)

    // sets value and returns old value
    public void setter(Object value) {
    try {
    return this.value;
    }
    finally {
    this.value = value;
    }
    }

  • CyberMandrake

    Kuhn: Sure this looks creepy !!!
    All: I’ve read somewhere that using try-catch blocks may impair the performance, because of the way bytecode should be generated, or smth else. So I would take care with this trick and use only in really complicated if nests and lairs. The simple example would not be the case, as is the real example above mentioned.

  • Jevgeni Kabanov

    CyberMandrake: “I’ve read somewhere” is not the best argument. Try-finally in such a case should not anyhow significantly impair performance. It is in fact pretty same as just copying the finally block before every return (try-finally is implemented by doing a JSR jump before return an the RET jump when the block is finished, both are very cheap). If try-catch-finally would cost much the whole Java model would be broken, because checked exceptions mean you catch them a LOT.

  • http://my.opera.com/behrangsa Behrang

    @Kuhn: setter is void, it cant return value.

  • Tao Wang

    There is a problem when an exception threw with in the condtions like conditionA.
    such exception will cause the method with no return value, but logged with result False.

  • Jevgeni Kabanov

    It’s not a problem, you just have to have a sensible default result. If there isn’t any just don’t use this idiom :) In my case false was the acceptable default.

  • Pingback: dow.ngra.de » Blog Archive » Yet Another Java Trick, Revisited