Does Java Support Inner/Local/Sub Methods

Does Java support inner / local / sub methods?

Update 2014-02-09:

JDK 8 introduced lambdas (anonymous function expressions) which allow you to solve it like this:

Function<String, String> trible = s -> s+s+s;
System.out.println(trible.apply("X")); // prints XXX

(JDK 7 and below)

No, Java does not support "directly" nested methods. (Most functional languages do though, including some JVM languages such as Scala and Clojure!)

Just for reference though; You can define local classes (classes within methods) so this does compile

class SubFunction {
private String drawTribleX(){

// *** move trible(t) inside drawTribleX() ***
class Trible {
private String trible(String t){
return t + t + t;
}
}

return new Trible().trible("X");
}
public static void main(String[] args){
SubFunction o = new SubFunction();
System.out.println(o.drawTribleX());
}
}

Note though that there are some restrictions on local classes

3.11.2. Restrictions on Local Classes

Local classes are subject to the following restrictions:

  • A local class is visible only within the block that defines it; it can never be used outside that block.

  • Local classes cannot be declared public, protected, private, or static. These modifiers are for members of classes; they are not allowed with local variable declarations or local class declarations.

  • Like member classes, and for the same reasons, local classes cannot contain static fields, methods, or classes. The only exception is for constants that are declared both static and final.

  • Interfaces cannot be defined locally.

  • A local class, like a member class, cannot have the same name as any of its enclosing classes.

  • As noted earlier, a local class can use the local variables, method parameters, and even exception parameters that are in its scope, but only if those variables or parameters are declared final. This is because the lifetime of an instance of a local class can be much longer than the execution of the method in which the class is defined. For this reason, a local class must have a private internal copy of all local variables it uses (these copies are automatically generated by the compiler). The only way to ensure that the local variable and the private copy are always the same is to insist that the local variable is final.

So, as you can see, your first option (without nested methods) is preferable in these situations.

Can methods in java be nested and what is the effect?

UPDATE
Since Java 8 methods can be nested using lambdas, see this other question.

This answer is valid for Java versions prior to Java 8

Original answer follow:

Can methods in java be nested[...]?

No, that's not possible.

The closest thing you can get is:

class Name {
void methodOne() {
class InnerClass {
void methodTwo() {
}
}
}
}

That is, a second method defined in a inner class defined in a method.

You can declare the method static inside the inner class, so you do not have to call new

Nested functions in Java

Java 8 introduces lambdas.

java.util.function.BiConsumer<Integer, Integer> times = (i, num) -> {
i *= num;
System.out.println(i);
};
for (int i = 1; i < 100; i++) {
times.accept(i, 2); //multiply i by 2 and print i
times.accept(i, i); //square i and then print the result
}

The () -> syntax works on any interface that defines exactly one method. So you can use it with Runnable but it doesn't work with List.

BiConsumer is one of many functional interfaces provided by java.util.function.

It's worth noting that under the hood, this defines an anonymous class and instantiates it. times is a reference to the instance.

Access methods within local inner classes in Java

As ILikeTau's comment says, you can't access a class that you define in a method. You could define it outside the method, but another possibility is to define an interface (or abstract class). Then the code would still be inside your method, and could access final variables and parameters defined in the method (which you couldn't do if you moved the whole class outside). Something like:

class Outer {
int a = 100;

public interface AnInterface {
void mInner(); // automatically "public"
}

AnInterface mOuter() { // note that the return type is no longer Object
class Inner implements AnInterface {
@Override
public void mInner() { // must be public
int y = 200;
System.out.println("mInner..");
System.out.println("y : " + y);
}
}
Inner iob = new Inner();
return iob;
}
}

class Demo {
public static void main(String[] args) { // the preferred syntax
Outer t = new Outer();
Outer.AnInterface ob = t.mOuter();
ob.mInner();
}
}

Note: not tested

Note that the return type, and the type of ob, have been changed from Object. That's because in Java, if you declare something to be an Object, you can only access the methods defined for Object. The compiler has to know, at compile time (not at run time) that your object ob has an mInner method, and it can't tell that if the only thing it knows is that it's an Object. By changing it to AnInterface, the compiler now knows that it has an mInner() method.

Can we have an inner class inside a method?

Yes you can.

public final class Test {
// In this method.
private void test() {
// With this local variable.
final List<String> localList = new LinkedList<String>();
// We can define a class
class InnerTest {
// Yes you can!!
void method () {
// You can even access local variables but only if they are final.
for ( String s : localList ) {
// Like this.
}
}
}
}

}

Java inner class and static nested class

From the Java Tutorial:

Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are simply called static nested classes. Non-static nested classes are called inner classes.

Static nested classes are accessed using the enclosing class name:

OuterClass.StaticNestedClass

For example, to create an object for the static nested class, use this syntax:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Objects that are instances of an inner class exist within an instance of the outer class. Consider the following classes:

class OuterClass {
...
class InnerClass {
...
}
}

An instance of InnerClass can exist only within an instance of OuterClass and has direct access to the methods and fields of its enclosing instance.

To instantiate an inner class, you must first instantiate the outer class. Then, create the inner object within the outer object with this syntax:

OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

see: Java Tutorial - Nested Classes

For completeness note that there is also such a thing as an inner class without an enclosing instance:

class A {
int t() { return 1; }
static A a = new A() { int t() { return 2; } };
}

Here, new A() { ... } is an inner class defined in a static context and does not have an enclosing instance.

Local Variable in Static Inner Class

Local variables are never shared with other threads in Java. It doesn't matter whether we are talking about ordinary methods, or lambdas. It doesn't matter whether the method is declared in a top level class, an inner class, a nested class, an anonymous class or a local classes.

So in your example, the two threads will have their own copies of the local variable, but they may be updating a shared a variable ... depending on which SharedClass instance they are calling the method on.

Or, to put it another way, you don't need to worry about thread safety for local = 0; and local++, but you do for access to a and the a=local; assignment.


There some scenario where local variables appear to be shared. However, it is an illusion. Consider this:

public void test() {
final int arg = 42;
new Thread(new Runnable(){
public void run() {
System.out.println(arg);
}
}).start();
}

It looks like the arg variable is accessed by the child thread. But in fact, what the child thread is actually accessing will be a synthetic variable in the Runnable instance whose value has been initialized to the value of arg; i.e. 42.

(If you compile the above code and use javap to examine the bytecodes, you will see how it works.)

Note that this is only allowed by the Java compiler when arg is final or effectively final. If was not final or effectively final, the trick of using a synthetic variable would not work.

Java code showing error: inner class can't be public?

In Java, you can write a class within a method. These are called method-local inner classes and they will be of local types (pretty much like local variables), the scope of the inner class is restricted within the method, so it can't be public (more details here and here).

Here is a complete example:

public class MethodLocalInnerClassExample {
private int x = 10;

void printFromInner(final int a) {
final int y = 10;

class MethodLocalInnerClass {
int w = 5;

public void print(int z) {
System.out.println("x + y - z + w + a = " + (x+y-z+w+a));
}
}

MethodLocalInnerClass innerClass = new MethodLocalInnerClass(); // must come after the class' definition
innerClass.print(5);
}
}

Java Local Inner Class in a METHOD, how is it handled by the JVM?

The JVM doesn't compile classes, javac does.

And, in fact, the JVM knows essentially nothing about any form of inner class -- they are compiled as separate classes and the JVM treats them that way. All of the inner class functionality is done with compiler-generated swizzles (unless this has changed since Java 5). (And I've always suspected that there are several security holes as a result of this, but never bothered to try to find them.)

If you include the exact same class in more than one method, I don't know if the compiler somehow figures out that they are the same, to only generate one copy, or if it generates multiple copies. A few simple tests would tell you.

Inner methods could no doubt have been (relatively easily) implemented in Java, but the designers chose to avoid that complexity with Java 1 (especially given that their model was C) and then invested all their energy in inner classes later. No real reason, other that it didn't become anyone's pet idea, I suspect.

[Actually, there is a reason for not implementing inner classes, but not an insurmountable one. The original Java execution stack model would not have supported it without a "display" and some extra opcodes, and, since that original design, the Java designers have been remarkably reluctant to add even obviously needed new features to the JVM (as witnessed by the implementation of inner classes with no JVM mods). (Though, oddly, they implemented the highly incompatible and pervasive (and probably unnecessary) change to verification in 5.)]

What's the use of a method-local inner class?

Using method-local classes can increase the readability of your code by keeping related parts together. As a contrived example, suppose you have a method that needs to create a thread to do something in the background:

class Test {
void f() {
// Method local inner class
class InnerClass {
private String myThreadName;
// InnerClass constructor
public InnerClass(String myThreadName) {
this.myThreadName = myThreadName;
}
// InnerClass method
public void run() {
Thread thread = new Thread(
// Anonymous inner class inside method local inner class
new Runnable() {
public void run() {
doSomethingBackgroundish();
}
}
);
thread.setName(myThreadName);
thread.start();
}
}
InnerClass anInnerClass = new InnerClass(aThreadName);
anInnerClass.run();
}
}

Without method-local classes, you would have to either:

  • create a new named class inside Test to do the background processing, or
  • create a new named class in a separate source file to do the background processing.

Both these options can reduce the readability of the code by moving the related processing somewhere else in your source tree (maybe in the same source file, maybe in another source file entirely). Using a method-local class keeps the processing logic right where it is used.

This is certainly not applicable for all situations, but it can be very useful in a number of common situations. Such code is commonly used for GUI action listeners, which are very small classes that usually just relay action method calls from one place to another.



Related Topics



Leave a reply



Submit