Home > Enterprise >  Is there a way to pass an object to a catch block in order to call a clean0up function on it before
Is there a way to pass an object to a catch block in order to call a clean0up function on it before

Time:08-11

I'm working with a database that has entries with one of three status codes included with them (not used, provisioning, provisioned). I'm trying to implement code to reset the entry's value to "not used" if there's an exception caught during the program's execution. My issue is that the necessary information and objects needed to do this are initialized in the try block and go out of scope once the code in the catch block starts running.

Is there a functional way to achieve this effect or should I refactor?

CodePudding user response:

The problem is, java doesn't know how far the try block 'goes' before the catch block is invoked. In other words, imagine this:

void example() {
  try {
    foo();
    long x = System.currentTimeMillis();
    bar();
  } catch (SomeException e) {
    System.out.println(x);
  }
}

The above won't compile because, imagine that foo() threw the exception. Then x doesn't even exist yet. What value does x have? That's why java won't let you. The problem is fundamental, so I can't tell you what the solution is. I can merely show you a solution, show how to apply that solution, and then you know how to come up with your own and use the same patterns.

One easy way out is to state that you want x to take some default value, let's say 0, until it is properly initialized. Your catch block could perhaps detect that x still has the sentinel value that indicates 'not initialized yet' and act accordingly. It would look like this:

void example() {
  {
    long x = 0L;
    try {
      foo();
      x = System.currentTimeMillis();
      bar();
    } catch (SomeException e) {
      System.out.println(x);
    }
  }
}

Here we create x before the try block even starts, thus allowing java to reason that x will definitely have been initialized to something (0, at least!) and this the above is perfectly fine. if foo() throws and gets us to the catch, x will be 0. (or, somehow, System.currentTimeMillis() does - how can javac know for certain it would not? It's just a method invocation, javac doesn't know what it does) - but if bar() throws it, then x will be the time as it was fater finishing foo().

I intentionally used a rarely used java 'trick' in this example: There's an extra, seemingly useless pair of braces in there. This is legal. It has one use: To isolate variables. In java, a local variable's scope is strictly limited to the nearest set of braces. In other words, this:

try {
  int x = 5;
} catch (Exception e) {
  return;
}

System.out.println(x);

is illegal java code even though code flow wise it's perfectly fine - if we get to the sysout statement, x = 5 has definitely executed. The problem is, int x;, not x = 5. The x variable is defined within the scope of the braces of the try{} statement. Meaning, outside of those {} it does not exist. javac will not compile this and will complain that it has no idea what x might be. A different error than what you're getting (which is "I know what it is, but I cannot be sure that it has been initialized so I will not allow you to read it here").

The same applies when you use 'lone' {}. In other words, this last snippet still isolates the long x; variable to exist solely there. If your method is quite large this is a good idea - it means you are having to juggle fewer variables in your head as you parse the code. It matches the 'scope' of x in your question. If you don't need this kind of scope limitations, then you don't need the extra braces.

  • Related