问题
Following JEP 286: Local-Variable Type Inference description
I am wondering, what the reason is for introducing such a restriction, as:
Main.java:199: error: cannot infer type for local variable k var k = { 1 , 2 }; ^ (array initializer needs an explicit target-type)
So for me logically it should be:
var k = {1, 2}; // Infers int[]
var l = {1, 2L, 3}; // Infers long[]
Because Java compiler can already infer properly the type of an array:
void decide() {
arr(1, 2, 3); // call void arr(int ...arr)
arr(1, 2L, 3); // call void arr(long ...arr)
}
void arr(int ...arr) {
}
void arr(long ...arr) {
}
So what is the impediment?
回答1:
Every time we improve the reach of type inference in Java, we get a spate of "but you could also infer this too, why don't you?" (Or sometimes, less politely.)
Some general observations on designing type inference schemes:
- Inference schemes will always have limits; there are always cases at the margin where we cannot infer an answer, or end up inferring something surprising. The harder we try to infer everything, the more likely we will infer surprising things. This is not always the best tradeoff.
- It's easy to cherry-pick examples of "but surely you can infer in this case." But if such cases are very similar to other cases that do not have an obvious answer, we've just moved the problem around -- "why does it work for X but not Y where X and Y are both Z?"
- An inference scheme can always be made to handle incremental cases, but there is almost always collateral damage, either in the form of getting a worse result in other cases, increased instability (where seemingly unrelated changes can change the inferred type), or more complexity. You don't want to optimize just for number of cases you can infer; you want to optimize also for an educated user's ability to predict what will work and what will not. Drawing simpler lines (e.g., don't bother to try to infer the type of array initializers) often is a win here.
- Given that there are always limits, its often better to choose a smaller but better-defined target, because that simplifies the user model. (See related questions on "why can't I use type inference for the return type of private methods. The answer is we could have done this, but the result would be a more complicated user model for small expressive benefit. We call this "poor return-on-complexity.")
回答2:
From the mailing list platform-jep-discuss, message Reader Mail Bag for Thursday (Thu Mar 10 15:07:54 UTC 2016) by Brian Goetz:
Why is it not possible to use var when the initializer is an array initializer, as in:
var ints = { 1, 2, 3 }
The rule is: we derive the type of the variable by treating the initializer as a standalone expression, and deriving its type. However, array initializers, like lambdas and method refs, are poly expressions -- they need a target type in order to compute their type. So they are rejected.
Could we make this work? We probably could. But it would add a lot of complexity to the feature, for the benefit of a mostly corner case. We'd like for this to be a simple feature.
The short-hand array initializer takes its type information from the declaration, but as the declaration here is var
it must be specified explicitly.
You will need to choose between:
var k = new int[]{ 1 , 2 };
or
int[] k = { 1 , 2 };
Allowing var k = { 1 , 2 }
would change the semantics of something that is already syntactic sugar. In the case of int[] n = { 1, 2 }
the type is determined by the declaration. If you allow var n = { 1, 2 }
the type is suddenly determined by the initializer itself. This might lead to (easier to create) compiler bugs or ambiguities.
来源:https://stackoverflow.com/questions/49134118/array-initializer-needs-an-explicit-target-type-why