Final variable assignment with try/catch

30,987

One way to do this is by introducing a (non-final) temporary variable, but you said you didn't want to do that.

Another way is to move both branches of the code into a function:

final int x = getValue();

private int getValue() {
  try {
    return Integer.parseInt("someinput");
  }
  catch(NumberFormatException e) {
    return 42;
  }
}

Whether or not this is practical depends on the exact use case.

All in all, as long as x is a an appropriately-scoped local variable, the most practical general approach might be to leave it non-final.

If, on the other hand, x is a member variable, my advice would be to use a non-final temporary during initialization:

public class C {
  private final int x;
  public C() {
    int x_val;
    try {
      x_val = Integer.parseInt("someinput");
    }
    catch(NumberFormatException e) {
      x_val = 42;
    }
    this.x = x_val;
  }
}
Share:
30,987

Related videos on Youtube

dtech
Author by

dtech

CS student

Updated on August 29, 2020

Comments

  • dtech
    dtech almost 4 years

    Because I believe it is a good programming practice, I make all my (local or instance) variables final if they are intended to be written only once.

    However, I notice that when a variable assignment can throw an exception you cannot make said variable final:

    final int x;
    try {
        x = Integer.parseInt("someinput");
    }
    catch(NumberFormatException e) {
        x = 42;  // Compiler error: The final local variable x may already have been assigned
    }
    

    Is there a way to do this without resorting to a temporary variable? (or is this not the right place for a final modifier?)

    • NPE
      NPE over 11 years
      I doubt you can do this without a temporary variable.
    • Joop Eggen
      Joop Eggen over 11 years
      final int x = makeX(); definitely. (try-catch in function)
    • T.J. Crowder
      T.J. Crowder over 11 years
      Shocking that the JDK still doesn't have a tryParse.
    • dtech
      dtech over 11 years
      @T.J.Crowder definitly, but it is irrelevant in this case since I just used the integer as an example
    • jaco0646
      jaco0646 over 9 years
      To be perfectly clear, the compiler error is incorrect, is it not? There is no circumstance under which x could be assigned twice in the given example.
    • Joshua Goldberg
      Joshua Goldberg about 8 years
      @jaco0646, it's asking a lot for the compiler to get that in general when there are multiple lines in the try block where the exception might happen. It would be nice to have an exceptional case for this purpose, though, detecting when the assignment is the last statement in the try.
    • augurar
      augurar over 7 years
      I guess the real problem is that Java's try-catch statement does not support an else case like Python.
    • Frans
      Frans over 3 years
      Kotlin has try expressions for this (kotlinlang.org/docs/reference/…). Hopefully they'll be added to Java some day.
  • gks
    gks over 11 years
    I guess it could reflect an error cannot make a static reference to the non-static method getValue(), so we are suppose to use the static function ,, i may be wrong private static int getValue() ..@NPE
  • dtech
    dtech over 11 years
    For a local scope I agree with you, however this most often occurs with instance variables.
  • Stefan
    Stefan over 10 years
    The compiler is smart enough to know which statements throw which exceptions. It may not be possible in all cases but just like the compiler can tell you in some cases about dead code etc. it should be able to figure out if final would work.
  • Franklin Yu
    Franklin Yu about 8 years
    To support what @Stefan said, Clang is able to figure this out when compiling Swift.
  • Joshua Goldberg
    Joshua Goldberg about 8 years
    If this.x is an object-type like Integer, then you need a little more (sadly). If you leave x_val undeclared, the compiler will complain that it may not have been initialized. If the fall-back for the catch block is null, you need to pre-initialize to null and either redundantly assign null in the catch for clarity (that's my preference) or have an empty catch.
  • Ti Strga
    Ti Strga over 5 years
    What @JoshuaGoldberg says is true even for primitive types. We have exactly the same pattern of code, where the member in the role of this.x is a primitive boolean, as is the local variable. Even with Java 9, we get "<thing_in_the_role_of_x_val> may not have been initialized". The lack of control-flow analysis for this situation is frustrating, but easily worked around.