Reputation: 12762
Java allows me to define local abstract classes, like in this example:
public class Foo {
public void foo() {
abstract class Bar { // Bar is a local class in foo() ...
abstract void bar();
}
new Bar() { // ... and can be anonymously instantiated
void bar() {
System.out.println("Bar!");
}
}.bar();
}
}
For some reason, when I try to define a "local interface" instead of the local class, like this:
public class Foo {
public void foo() {
interface Bar { // Bar was supposed to be a local interface...
void bar();
}
new Bar() { // ... to be anonymously instantiated
void bar() {
System.out.println("Bar!");
}
}.bar();
}
}
Java complains that "The member interface Bar can only be defined inside a top-level class or interface". Is there a reason for this? Or am I missing a mistake I made?
Upvotes: 3
Views: 2705
Reputation: 79580
Is there such a thing as a "local interface" in Java?
Short answer: Yes
Below is an excerpt from section 14.3 of the JDK 16 Java Language Specification:
A local interface may be a normal interface (§9.1), but not an annotation interface (§9.6)
So, the below code fails to compile with Java 16+
class Foo {
void foo() {
@interface Bar {}
}
}
But the following is a valid code with Java 16+
class Foo {
public void foo() {
interface Bar {
void bar();
}
new Bar() {
public void bar() {
System.out.println("Bar!");
}
}.bar();
}
}
Demo:
class Foo {
public void foo() {
interface Bar {
void bar();
}
new Bar() {
public void bar() {
System.out.println("Bar!");
}
}.bar();
}
}
class Main {
public static void main(String[] args) {
new Foo().foo();
}
}
Output:
Bar!
Upvotes: 1
Reputation: 2047
Java now (starting from 16) supports local interface.
A local interface is a nested interface (§9 (Interfaces)) whose declaration is immediately contained by a block.
And your (slightly corrected because bar
implmentation must be public) code compiles just fine.
public class Foo {
public void foo() {
interface Bar { // Bar was supposed to be a local interface...
void bar();
}
new Bar() { // ... to be anonymously instantiated
public void bar() {
System.out.println("Bar!");
}
}.bar();
}
}
Compilation:
~/tmp $ /usr/local/opt/java/bin/javac -version
javac 17
~/tmp $ /usr/local/opt/java/bin/javac Foo.java
Upvotes: 0
Reputation: 304
Local interfaces (and enums) have been introduced along record classes feature:
Unfortunately this feature is a little bit obscured in the documentation - but it works.
Both versions allow to write code like below:
public class Main {
public int foo() {
interface Experimentable {
int bar();
}
Experimentable e = new Experimentable() {
@Override
public int bar() {
return 0;
}
};
return e.bar();
}
public static void main(String[] args) {
System.out.println(new Main().foo());
}
}
Upvotes: 3
Reputation: 37875
There simply isn't a definition for it in the JLS. It just doesn't exist.
As for a weak reason, according to the JLS 14.3:
All local classes are inner classes (§8.1.3).
An interface can't be inner (JLS 8.1.3):
Member interfaces (§8.5) are implicitly static so they are never considered to be inner classes.
So we can't have a local interface.
This is, I guess, in addition to what @SotiriosDelimanolis has found that InterfaceDeclaration is not a BlockStatement.
Upvotes: 6
Reputation: 280178
The Java Language Specification doesn't tell you why it was designed the way it was, but it does describe what is and what isn't allowed.
A method body has the following form
MethodBody:
Block
;
Block:
{ BlockStatementsopt }
BlockStatements:
BlockStatement
BlockStatements BlockStatement
BlockStatement:
LocalVariableDeclarationStatement
ClassDeclaration
Statement
So a class declaration is allowed, but an interface isn't.
We can argue that having a local interface is not very useful from a caller point of view. It doesn't serve any purpose. An interface is meant to describe behavior, but since the interface would be local, no caller could make use of it. You could just as well define and implement the behavior in a class.
Upvotes: 5