Java中的嵌套函数
Java编程语言是否有扩展可以创build嵌套函数? 在很多情况下,我需要创build在另一个方法或for循环中只使用一次的方法。 到目前为止,我一直无法用Java来完成这个任务,尽pipe它可以在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); } }
Java 8引入了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 }
() ->
语法适用于任何定义了一个方法的接口。 所以你可以将它与Runnable
一起使用,但它不适用于List
。
BiConsumer
是java.util.function提供的许多function接口之一。
值得注意的是,在这种情况下,它定义了一个匿名类并实例化它。 times
是对实例的引用。
下面的答案是关于在Java 8之前最接近于Java的嵌套函数。这不一定是我处理可能用Javascript中的嵌套函数处理的相同任务的方式。 通常一个私人助手方法也可以做到 – 甚至可能是一个私人助手types ,你可以在方法中创build一个实例,但是所有方法都可以使用它。
在Java 8当然,有lambdaexpression式,这是一个更简单的解决scheme。
最近你可以很容易地来到一个匿名的内部类。 尽pipe目前Java正在closures,但希望在Java 8中有更多的支持。
匿名内部类有各种限制 – 与Javascript示例(或使用lambdaexpression式的任何内容)相比,它们显然相当罗嗦,并且它们对封闭环境的访问仅限于最终variables。
所以(可怕地)歪曲你的例子:
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获得的输出吗?
我认为在Java 7中最接近嵌套的函数不是通过使用匿名内部类(Jon Skeet上面的答案),而是通过使用非常less用的本地类。 这样一来,甚至连嵌套类的接口都不能在其预期范围之外看到,也不会太罗嗦。
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
这种方法有时被称为闭包。 看看Groovy – 也许你会更喜欢Java。 在Java 8中也可能会有closures(参见JSR335和延期列表 )。
考虑创build一个匿名的本地类并使用它的初始化块来完成这项工作:
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工具更好一些。)
我讨厌使用禁止的单词,但可以使用goto
语句在方法内部创build一个有效的子例程。 这是丑陋的,危险的,但比以前的答案更容易。 尽pipe在第一种方法中调用私有方法好得多,并且服务于您需要很好。 我不知道为什么你会想要使用一个嵌套的方法这样简单的事情。