Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid constructor reference when using local class?

Given the following code:

package com.gmail.oksandum.test;  import java.util.ArrayList; import java.util.List;  public class Test {      public static void main(String[] args) {     }      public void foo() {         class LocalFoo {              LocalFoo(String in) {                 //Some logic             }          }          List<String> ls = new ArrayList<>();         ls.stream().map(LocalFoo::new); //Line 21     }  } 

my IDE gives me no errors. That is, until I try to build the project and run it. When I do that it gives me a compiler error that looks like this:

Error:(21, 24) java: incompatible types: cannot infer type-variable(s) R     (argument mismatch; invalid constructor reference       cannot access constructor LocalFoo(java.lang.String)         an enclosing instance of type com.gmail.oksandum.test.Test is not in scope) 

Now, I figured, given the error message, that this wouldn't happen if foo() were static. And quite right, this only happens if foo() is an instance method. And it only happens if LocalFoo is a local class in the instance method, and only if a constructor reference is used (i.e never a regular method reference).

What's more, if I change line 21 into

ls.stream().map(str -> new LocalFoo(str)); 

the compiler suddenly gives no error.

So to recap. If I try to use a constructor reference on a local class declared within an instance method, the compiler complains about not being able to access the constructor, about which I am confused.

If someone could shed some light on why this happens it would be appreciated. Thanks.

like image 336
Rocoty Avatar asked Oct 08 '14 13:10

Rocoty


People also ask

Which statement is invalid for a constructor in Java?

Explanation: The constructor cannot have a return type.

How do you access a Java class constructor using method reference?

A method reference can also be applicable to constructors in Java 8. A constructor reference can be created using the class name and a new keyword. The constructor reference can be assigned to any functional interface reference that defines a method compatible with the constructor.

Can we declare a static member interface in a local class?

Local classes are non-static because they have access to instance members of the enclosing block. Consequently, they cannot contain most kinds of static declarations.

How do you declare a local class in Java?

A local class is declared locally within a block of Java code, rather than as a member of a class. Typically, a local class is defined within a method, but it can also be defined within a static initializer or instance initializer of a class.


1 Answers

It looks like LocalFoo is treated somehow like a non-static class. That's why it claims no instance of Test is in scope.

From the tutorial:

Local classes are non-static because they have access to instance members of the enclosing block. Consequently, they cannot contain most kinds of static declarations.

https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html

The method foo() or the class LocalFoo must be static for this to work. But a class inside a method can't be declared as static. So you'd have to move it out of the method if foo() should remain nonstatic (as an inner, static class). Another option is to just use this:
ls.stream().map(s -> new LocalFoo(s));

There should be a way to just say Test.this.LocalFoo, but that doesn't work. And if it did the compiler should also just accept LocalFoo::new.

There is a bug report now: https://bugs.openjdk.java.net/browse/JDK-8144673
(See comment by Brian Goetz)

like image 197
Claude Martin Avatar answered Sep 25 '22 02:09

Claude Martin