Java 中的嵌套函数

发布于 2024-12-03 17:35:19 字数 400 浏览 0 评论 0原文

Java 编程语言是否有任何扩展可以创建嵌套函数?

在很多情况下,我需要创建仅在另一个方法或 for 循环的上下文中使用一次的方法。到目前为止,我还无法在 Java 中完成此任务,尽管可以在 JavaScript 中轻松完成。

例如,这不能在标准 Java 中完成:

for(int i = 1; i < 100; i++){
    times(2); // Multiply i by 2 and print i
    times(i); // Square i and then print the result

    public void times(int num){

        i *= num;
        System.out.println(i);
    }
}

Are there any extensions for the Java programming language that make it possible to create nested functions?

There are many situations where I need to create methods that are only used once in the context of another method or for-loop. I've been unable to accomplish this in Java so far, even though it can be done easily in JavaScript.

For example, this can't be done in standard Java:

for(int i = 1; i < 100; i++){
    times(2); // Multiply i by 2 and print i
    times(i); // Square i and then print the result

    public void times(int num){

        i *= num;
        System.out.println(i);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

各空 2024-12-10 17:35:19

Java 8 引入了 lambda。

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
}

() -> 语法适用于仅定义一个方法的任何接口。因此,您可以将其与 Runnable 一起使用,但不能与 List 一起使用。

BiConsumerjava.util.function

值得注意的是,在底层,这定义了一个匿名类并实例化它。 times 是对实例的引用。

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.

温柔戏命师 2024-12-10 17:35:19

下面的答案讨论的是 Java 8 之前的 Java 中最接近嵌套函数的情况。这不一定是我处理 JavaScript 中嵌套函数可能处理的相同任务的方式。通常,私有帮助器方法也能起到同样的作用 - 甚至可能是私有帮助器类型,您可以在方法中创建它的实例,但它可用于所有方法。

当然,在 Java 8 中,有 lambda 表达式,这是一个更简单的解决方案。


您可以轻松实现的最接近的是匿名内部类。这与 Java 目前最接近闭包的情况相同,尽管希望 Java 8 能提供更多支持。

匿名内部类有各种限制 - 与 JavaScript 示例(或任何使用 lambda 的内容)及其它们的示例相比,它们显然相当冗长。对封闭环境的访问仅限于最终变量。

所以(可怕地)扭曲你的例子:

interface Foo {
    void bar(int x);
}

public class Test {
    public static void main(String[] args) {
        // Hack to give us a mutable variable we can
        // change from the closure.
        final int[] mutableWrapper = { 0 };

        Foo times = new Foo() {
            @Override public void bar(int num) {
                mutableWrapper[0] *= num;
                System.out.println(mutableWrapper[0]);
            }
        };

        for (int i = 1; i < 100; i++) {
            mutableWrapper[0] = i;
            times.bar(2);
            i = mutableWrapper[0];

            times.bar(i);
            i = mutableWrapper[0];
        }
    }
}

输出:

2
4
10
100

这是你从 JavaScript 代码中得到的输出吗?

The answer below is talking about the closest you can get to having nested functions in Java before Java 8. It's not necessarily the way I'd handle the same tasks which might be handled with nested functions in JavaScript. Often a private helper method will do just as well - possibly even a private helper type, which you create an instance of within the method, but which is available to all methods.

In Java 8 of course, there are lambda expressions which are a much simpler solution.


The closest you can easily come is with an anonymous inner class. That's as close as Java comes to closures at the moment, although hopefully there'll be more support in Java 8.

Anonymous inner classes have various limitations - they're obviously rather wordy compared with your JavaScript example (or anything using lambdas) and their access to the enclosing environment is limited to final variables.

So to (horribly) pervert your example:

interface Foo {
    void bar(int x);
}

public class Test {
    public static void main(String[] args) {
        // Hack to give us a mutable variable we can
        // change from the closure.
        final int[] mutableWrapper = { 0 };

        Foo times = new Foo() {
            @Override public void bar(int num) {
                mutableWrapper[0] *= num;
                System.out.println(mutableWrapper[0]);
            }
        };

        for (int i = 1; i < 100; i++) {
            mutableWrapper[0] = i;
            times.bar(2);
            i = mutableWrapper[0];

            times.bar(i);
            i = mutableWrapper[0];
        }
    }
}

Output:

2
4
10
100

Is that the output you get from the JavaScript code?

池予 2024-12-10 17:35:19

我认为在 Java 7 中最接近嵌套函数的不是使用匿名内部类 (Jon Skeet 的回答),但是通过使用其他很少使用的本地类。这样,即使是嵌套类的接口在其预期范围之外也不可见,而且也少了一些冗长。

Jon Skeet 的使用本地类实现的示例如下所示:

public class Test {
    public static void main(String[] args) {
        // Hack to give us a mutable variable we can
        // change from the closure.
        final int[] mutableWrapper = { 0 };

        class Foo {
            public void bar(int num) {
                mutableWrapper[0] *= num;
                System.out.println(mutableWrapper[0]);
            }
        };

        Foo times = new Foo();

        for (int i = 1; i < 100; i++) {
            mutableWrapper[0] = i;
            times.bar(2);
            i = mutableWrapper[0];

            times.bar(i);
            i = mutableWrapper[0];
        }
    }
}

输出:

2
4
10
100

I think that the closest you can get to having nested functions in Java 7 is not by using an anonymous inner class (Jon Skeet's answer), but by using the otherwise very rarely used local classes. This way, not even the interface of the nested class is visible outside its intended scope and it's a little less wordy too.

Jon Skeet's example implemented with a local class would look as follows:

public class Test {
    public static void main(String[] args) {
        // Hack to give us a mutable variable we can
        // change from the closure.
        final int[] mutableWrapper = { 0 };

        class Foo {
            public void bar(int num) {
                mutableWrapper[0] *= num;
                System.out.println(mutableWrapper[0]);
            }
        };

        Foo times = new Foo();

        for (int i = 1; i < 100; i++) {
            mutableWrapper[0] = i;
            times.bar(2);
            i = mutableWrapper[0];

            times.bar(i);
            i = mutableWrapper[0];
        }
    }
}

Output:

2
4
10
100
惜醉颜 2024-12-10 17:35:19

此类方法有时称为闭包。看看Groovy——也许你会更喜欢它而不是Java。在 Java 8 中也可能存在闭包(请参阅 JSR335 和 < a href="http://openjdk.java.net/projects/jdk7/features/#deferred" rel="nofollow">延迟列表)。

Such methods are sometimes called closures. Have a look at Groovy – perhaps you will prefer it to Java. In Java 8 there will probably be closures as well (see JSR335 and deferred list).

追星践月 2024-12-10 17:35:19

对于无参数方法,您可以创建 Runnable 对象

private static void methodInsideMethod(){
    Runnable runnable = new Runnable(){
        @Override
        public void run(){
            System.out.println("Execute something");
        }
    };

    for(int i = 0; i < 10; i++){
        runnable.run();
    }
}

For non-argument method you can create Runnable object

private static void methodInsideMethod(){
    Runnable runnable = new Runnable(){
        @Override
        public void run(){
            System.out.println("Execute something");
        }
    };

    for(int i = 0; i < 10; i++){
        runnable.run();
    }
}
樱桃奶球 2024-12-10 17:35:19

我不知道其他人是否已经弄清楚了这一点,但显然您可以使用 Java 10 及更高版本附带的 var 关键字来变魔术。如果您没有适合您的接口,这可以使您不必声明接口。

public class MyClass {
    public static void main(String args[]) {
        var magic = new Object(){
            public void magic(){
                System.out.println("Hello World!");
            }
        };
        magic.magic();
    }
}

我已经测试过它并且有效。我还没有找到可以让您进行简单共享的 Java 编译器。

I don't know if anyone else has figured this out, but apparently you can do magic with the var keyword that comes with Java 10 and above. This saves you from having to declare an interface if you don't have one that will work for you.

public class MyClass {
    public static void main(String args[]) {
        var magic = new Object(){
            public void magic(){
                System.out.println("Hello World!");
            }
        };
        magic.magic();
    }
}

I have tested it and it works. I haven't found a Java compiler that lets you do a simple share yet.

╭ゆ眷念 2024-12-10 17:35:19

考虑创建一个匿名本地类并使用其初始化块来完成工作:

public class LocalFunctionExample {
    public static void main(final String[] args) {
        for (final int i[] = new int[] { 1 }; i[0] < 100; i[0]++) {
            new Object() {
                {
                    times(2); //multiply i by 2 and print i
                    times(i[0]); //square i and then print the result
                }

                public void times(final int num) {
                    i[0] *= num;
                    System.out.println(i[0]);
                }
            };
        }
    }
}

输出:(

2
4
10
100

此技术并不自动需要“最终包装器技巧”,但此处需要处理突变要求。)

这几乎是与 lambda 版本一样简洁,但您可以使用您想要的任何方法签名,它们可以拥有真正的参数名称,并且可以直接通过它们的名称调用方法 - 无需 .apply()或者诸如此类的。 (这种事情有时也会让 IDE 工具工作得更好一些。)

Consider making an anonymous local class and using its initializer block to do the work:

public class LocalFunctionExample {
    public static void main(final String[] args) {
        for (final int i[] = new int[] { 1 }; i[0] < 100; i[0]++) {
            new Object() {
                {
                    times(2); //multiply i by 2 and print i
                    times(i[0]); //square i and then print the result
                }

                public void times(final int num) {
                    i[0] *= num;
                    System.out.println(i[0]);
                }
            };
        }
    }
}

Output:

2
4
10
100

(The "final wrapper trick" is not automatically required with this technique, but was needed here to handle the mutation requirement.)

This works out to be almost as concise as the lambda version, but you get to use whatever method signatures you want, they get to have real parameter names, and the methods are called directly by their names - no need to .apply() or whatnot. (This kind of thing sometimes makes IDE tooling work a little better too.)

初心未许 2024-12-10 17:35:19

我讨厌使用禁用词,但您可以使用 goto 语句在方法内创建一个有效的子例程。它丑陋且危险,但比之前的答案中显示的要容易得多。尽管在第一个方法内部进行调用的私有方法要好得多,并且可以很好地满足您的需求。我不知道为什么您想要使用嵌套方法来完成如此简单的事情。

I hate to use the forbidden word but you could use a goto statement to create an an effective subroutine inside the method. It is ugly and dangerous but much easier than what was shown in previous answers. Although the private method with a call inside of the first method is much better, and serves you needs just fine. I don't know why you would want to use a nested method for something as simple as this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文