Variable is already defined in method lambda

后端 未结 5 895
执念已碎
执念已碎 2020-11-30 08:59

Consider the following almost compilable Java 8 code:

public static void main(String[] args) {

    LinkedList users = null;
    users.a         


        
相关标签:
5条回答
  • 2020-11-30 09:35

    The question is pretty old, but i thought my answer can add better clarity to the already given answers. Particularly to that of @Sotirios Delimanolis . The lambda assignment in

        User user = users.stream().filter((user) -> user.getId() == 1).findAny().get();
    

    fails for the same reason the following code fails.

        Object e = null;
        try{
          throw new Exception();
        } catch(Exception e) { // compilation fails because of duplicate declaration
          //do nothing
        }
    

    A local variable (§14.4), formal parameter (§8.4.1, §15.27.1), exception parameter (§14.20), and local class (§14.3) can only be referred to using a simple name, not a qualified name (§6.2).

    Some declarations are not permitted within the scope of a local variable, formal parameter, exception parameter, or local class declaration because it would be impossible to distinguish between the declared entities using only simple names.

    Because lambdas have the same scope of all the things mentioned above, this fails.

    0 讨论(0)
  • 2020-11-30 09:36

    Note, this limitation is going to be removed in the future releases. Quote from JEP-302:

    Lambda parameters are not allowed to shadow variables in the enclosing scopes. (In other words, a lambda behaves like a for statement - see JLS) This often causes problems, as in the following (very common) case:

    Map<String, Integer> msi = ...
    ...
    String key = computeSomeKey();
    msi.computeIfAbsent(key, key -> key.length()) //error
    

    Here, the attempt to reuse the name key as a lambda parameter in the computeIfAbsent call fails, as a variable with the same name was already defined in the enclosing context.

    It would be desirable to lift this restriction, and allow lambda parameters (and locals declared with a lambda) to shadow variables defined in enclosing scopes. (One possible argument against is readability: if lambda parameters are allowed to shadow, then in the above example, the identifier 'key' means two different things in the two places where it is used, and there seem to be no syntactic barrier to separate the two usages.)

    0 讨论(0)
  • 2020-11-30 09:41

    look at the code

    User user = users.stream().filter((user) -> user.getId() == 1).findAny().get();
    

    The variable name is user and the variable inside the lambda is also user

    try changing it to be something like this

    User user = users.stream().filter((otherUser) -> otherUser.getId() == 1).findAny().get();
    
    0 讨论(0)
  • 2020-11-30 09:42

    Let's go to the Java Language Specification on names and their scopes

    The scope of a formal parameter of a method (§8.4.1), constructor (§8.8.1), or lambda expression (§15.27) is the entire body of the method, constructor, or lambda expression.

    The scope of a local variable declaration in a block (§14.4) is the rest of the block in which the declaration appears, starting with its own initializer and including any further declarators to the right in the local variable declaration statement.

    Then, on the subject of shadowing and obscuring

    A local variable (§14.4), formal parameter (§8.4.1, §15.27.1), exception parameter (§14.20), and local class (§14.3) can only be referred to using a simple name, not a qualified name (§6.2).

    Some declarations are not permitted within the scope of a local variable, formal parameter, exception parameter, or local class declaration because it would be impossible to distinguish between the declared entities using only simple names.

    It is a compile-time error if the name of a local variable v is used to declare a new variable within the scope of v, unless the new variable is declared within a class whose declaration is within the scope of v.

    So, in

    User user = users.stream().filter((user) -> user.getId() == 1).findAny().get();
    

    , the scope of the variable user is everything after it in that block. Now you are trying to use the name of that variable to declare a new variable within the scope, but not

    within a class whose declaration is within the scope of v.

    so a compile time error occurs. (It's declared in a lambda expression, not in a class.)

    0 讨论(0)
  • 2020-11-30 09:45

    It is the same as with any other local variables: you're not allowed to shadow them in more inner {} blocks.

    0 讨论(0)
提交回复
热议问题