2

Is there a way in Java 8 to simultaneously declare and initialize a final variable with the result of a complex expression?

In other words, is something like the following possible?

final int x = [capturedVariable] {
    switch (capturedVariable) {
    case 1: return 42;
    case 2: return 84;
    default: return 66;
    }
};

While the syntax is obviously "creative", I hope the intent is clear.

Edit 1: While this particular example can be written using ternary operators, it's merely an example of a complex expression and I'm looking for a general solution.

Edit 2: Maybe a less controversial way to look at this question is the following: What is the syntax to simultaneously declare and invoke a lambda/closure in Java 8?

François Beaune
  • 4,270
  • 7
  • 41
  • 65
  • 5
    Write a method? `final int x = someMethod(capturedVariable);` – bradimus May 18 '17 at 15:01
  • 1
    That's of course a valid solution but I'm looking for a way to do it without introducing a one-off function (which also breaks the top-to-bottom reading order). – François Beaune May 18 '17 at 15:03
  • You can easily write `final int x; { switch (capturedVariable) { case 1: x=42; break; case 2: x=84; break; default: x=66; } }`. It’s shorter than your proposed syntax… – Holger May 18 '17 at 17:28

3 Answers3

3

I don't see how Java 8 is relevant here, you can assign a final variable in multiple places so long as you always assign it and only ever assign it once, for example this is legal Java code (assuming blah is a valid boolean):

final int test;
if (blah) {
  test = 1;
} else {
  test = 2;
}

The expressions can be as complicated as you like so long as the compiler is able to deterministically prove that you always initialize the variable once and only once. (For example loops would make it fail).

Tim B
  • 40,716
  • 16
  • 83
  • 128
  • Thanks! I'm tasked to write Java at work but I haven't used the language in decades. Coming from a C++ background, I was expecting that `final` *local* variables had to be initialized at the point of declaration, like `const` variables in C++, but I guess not :) Thanks for your answer. – François Beaune May 18 '17 at 15:28
  • I don't know why I read into the question that this option was off the table (I think it was me, not the question). If it isn't (off the table), this is the obvious, best way to go. – T.J. Crowder May 18 '17 at 15:29
  • 1
    @T.J.Crowder The question could be read multiple different ways so I figured we should make sure the simplest option was covered :D – Tim B May 18 '17 at 15:31
  • 1
    @FrançoisBeaune Java also has the concept of "effectively final" that you may find interesting to read up on. – Tim B May 18 '17 at 15:39
2

Seems overkill, but you could use a Supplier:

final int x = new Supplier<Integer>() {
    public Integer get() {
        // Complexity here
        return result;
    }
}.get();

I'm sure it's my Java-fu being weak (I guess not), but the only way I could get the lambda version working is to have a reusable call utility function somewhere:

class Utils {
    public static <T> T call(Supplier<T> x) {
        return x.get();
    }
}

...and then:

final int x = Utils.call(() -> {
    // Complexity here
    return result;
});

Matthias points out in a comment (refined by Aominè) that you can avoid that intermediary function, but it isn't much prettier than the first solution above:

final int x = ((Supplier<Integer>) () -> {
    // Complexity here
    return result;
}).get();

...but at least it doesn't require generating a class.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    The lambda version of this doesn't looks better final Integer a = ((Supplier)(() -> { return 1; })).get(); – Matthias May 18 '17 at 15:09
  • @Matthias: Thanks. I was really hoping there was a tidier way than that or my `call` function above. – T.J. Crowder May 18 '17 at 15:12
  • Thanks T.J.Crowder and @Matthias, at least your answers show how this is done using lambdas, and that there isn't a nice solution to this problem in Java. – François Beaune May 18 '17 at 15:13
  • There are plenty of *nice* solutions, you just do not like them. That makes this entire question *opinion based*, if it were not, the answers would all be variation so the same approach and would all be upvoted. –  May 18 '17 at 15:19
0

You ca create your own Interface an create init method which take an init and return another int for example :

Init i = (x) -> {
    switch (x) {
        case 1:
            return 42;
        case 2:
            return 84;
        default:
            return 66;
    }
};
final int x = i.init(1);

...

interface Init {
    int init(int x);
}
Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140