5 ms·
Fortunately, that mistake isn't possible in Java with lambda expressions or anonymous classes. It is a compile error if any captured variables are not "effectiv
by electrum 10y ago
Fortunately, that mistake isn't possible in Java with lambda expressions or anonymous classes. It is a compile error if any captured variables are not "effectively final".
Prior to Java 8, which introduced lambdas, variables used with anonymous classes were required to be final. That restriction is now relaxed as the compiler can infer it.
Interestingly, the for-each loop variable is effectively final, unless you explicitly modify it, so this code is legal (and correct):
for (String v : values) {
executor.execute(() -> System.out.println(v));
}
- sgift 10y agoI can never decide if enforcing (effectively) final is a good feature or a bad one. Sure, you cannot shoot yourself in the foot with these limits, on the other hand you loose all the power of real closures.
- twblalock 10y agoYou can easily modify variables outside of the stream. For example, to increment a counter declared outside of the lambda, use a final AtomicInteger or similar class instead of an int. For any other value, use a final class that wraps it. The point of enforcing final variables is to prevent programmers from accidentally modifying things they don't want to. It does not prevent programmers from modifying variables intentionally.
- sgift 10y agoI know very well that I can use inner mutability to work around that restriction, that doesn't change the fact that it is a workaround, nothing more.
- twblalock 10y agoIt's not a workaround. It was designed to work that way on purpose. The people who developed this feature could have easily prevented programmers from using any variables outside of the stream, final or not, but they chose not to because they wanted to allow programmers to use final variables in this way. Furthermore, it does not cause you to lose "all the power of real closures" like you said it does. All you lose is the ability to use a closure around non-final variables, which is a trivial drawback in any use case I've ever come across. You lose only a little bit of the power of closures.
- dkersten 10y agoI like that in C++11, you specify what should be captured and how it should be captured (by value or by reference).
- masklinn 10y agoRust is the same, though it's less flexible[0]: it doesn't have capture lists, only [&] and [=], and they're very slightly different: * the default is similar to [&] but will infer the capture mode and use the "simplest" possible one (reference, mutable reference or value) depending on use on a per-value basis. * `move` closures are similar to [=] but will use Rust ownership semantics, so they will copy Copy values and move non-Copy values, it can capture external references (mutable or not) by value so if you needed to explicitly tweak your capture that's the one you'd use. [0] OTOH it's more readable
- steveklabnik 10y agoI'm not sure that "less flexible" is accurate; we can accomplish the same things, but through different means.
- masklinn 10y agoIt might have been unclear, but I meant the closure syntax/capture itself is less flexible. You can get the same result e.g. using a move closure and declaring references outside the closure then capturing that by value, but I'm sure you could also do that in C++.
- steveklabnik 10y agoAh, yes. Cool :)
- camus2 10y agoThere are no final variables in Go. Anybody who pretend Go has a good type system is a liar. Go type system is broken. It doesn't make the language bad, it makes it a missed opportunity.
- dispose13432 10y ago>There are no final variables in Go. const?
- camus2 10y agoconst aren't final variables, you can't have a const pointer or a const array with Go.