Java MethodHandles 是否可以被视为与一等函数相同?
Java Method 类和 Java 7 MethodHandle 类均引用与方法关联的对象,但它们仍然很少使用,并且当需要将一个函数传递给另一个函数时,最好使用实现包含一个方法的接口的匿名类。
(注意:MethodHandles 应该比旧的方法更快。)
为什么这些构造没有更频繁地用于将函数传递给函数?是因为它们仍然冗长吗?
代码示例:
public final class HigherOrder {
public static final List<?> map(final List<?> list, final MethodHandle mh) throws Throwable {
if (list == null) return null;
List<Object> ret = new ArrayList<>(list.size());
for (Object element : list) {
ret.add(mh.invoke(element));
}
return ret;
}
public static final Object reduce(final List<?> list, final MethodHandle mh) throws Throwable {
if (list == null) return null;
Object tmp = list.get(0);
for (int i = 1; i < list.size(); i++) {
tmp = mh.invoke(tmp, list.get(i));
}
return tmp;
}
public static final Integer doubleNumber(final Integer number) {
return number * 2;
}
public static final Integer sum(final Integer number1, final Integer number2) {
return number1 + number2;
}
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle doubleNumber = lookup.unreflect(HigherOrder.class.getMethod("doubleNumber", Integer.class));
MethodHandle sum = lookup.findStatic(HigherOrder.class, "sum", MethodType.methodType(Integer.class, Integer.class, Integer.class));
List<?> list = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(list);
list = map(list, doubleNumber);
System.out.println(list);
System.out.println(reduce(list, sum));
}
}
UPDATE
在进行了一些基准测试之后,我注意到 MethodHandle 比 Reflection 的方法更快,但仍然远不及常规方法调用快。也许对于方法调用,JVM 可以应用一些句柄无法实现的优化。
Java Method Class and Java 7's MethodHandle Class both refer to objects that are associated to methods, but still they are rarely used and when a function needs to be passed to another, it is preferred to use an anonymous class that implements an interface that contains one method.
(Note: MethodHandles are supposed to be faster than the old Methods.)
Why aren't these constructs used more often to pass functions to functions? Is it because they are still verbose?
Code example:
public final class HigherOrder {
public static final List<?> map(final List<?> list, final MethodHandle mh) throws Throwable {
if (list == null) return null;
List<Object> ret = new ArrayList<>(list.size());
for (Object element : list) {
ret.add(mh.invoke(element));
}
return ret;
}
public static final Object reduce(final List<?> list, final MethodHandle mh) throws Throwable {
if (list == null) return null;
Object tmp = list.get(0);
for (int i = 1; i < list.size(); i++) {
tmp = mh.invoke(tmp, list.get(i));
}
return tmp;
}
public static final Integer doubleNumber(final Integer number) {
return number * 2;
}
public static final Integer sum(final Integer number1, final Integer number2) {
return number1 + number2;
}
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle doubleNumber = lookup.unreflect(HigherOrder.class.getMethod("doubleNumber", Integer.class));
MethodHandle sum = lookup.findStatic(HigherOrder.class, "sum", MethodType.methodType(Integer.class, Integer.class, Integer.class));
List<?> list = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(list);
list = map(list, doubleNumber);
System.out.println(list);
System.out.println(reduce(list, sum));
}
}
UPDATE
After doing some benchmarking, I noticed that MethodHandle is faster than Reflection's method, but still nowhere near as fast as a regular method call. Maybe for the method call the JVM can apply some optimizations that are not possible with the handles.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
仅在确实需要时才使用反射。
正如您所看到的,invoke throws Throwable 这意味着您没有得到真正好的异常处理。
其他编译时检查也将被丢弃。
Only use reflection when you really need to.
As you can see invoke throws Throwable which means you get no real good exception handling.
Also other compile time checks will be discarded.
Method 类有其一席之地需要使用反射,这比常规方法调用慢得多。
MethodHandler 是 JSR 292。它针对为 JVM 实现动态语言的人员。您可以在此处阅读有关它的更多信息。它也不意味着取代常规方法调用。
Method class has its place when one needs to use reflection, which is much slower than regular method call.
MethodHandler is part of JSR 292. It targets people who implement dynamic languages for JVM. You can read more about it here. It doesn't mean to replace regular method call either.
MethodHandles 使用反射,因此速度很慢并且不易重构。此外,Java 将在版本 8 中获得 lambda,这将解决 Java 中的一流函数的问题,因此我认为库编写者更喜欢等待 Java 8,而不是使用某种解决方法。
MethodHandles use reflection, so they're slow and not easily refactorable. Moreover, Java will get lambdas in it version 8 and this will solve the problem of first class functions in Java, so I suppose library writers prefer waiting for Java 8 than using some kind of workaround.
除了任何性能参数之外,传递Methods或MethodHandles:
此外,正如您的代码所示,使用Methods或MethodHandles并不会特别减少声明近似第一类函数的对象所需的代码量:
诚然,它不如真正的lambda语法那么好,但类型安全,重构的好处和易于解释使得键入这五行在大多数时候是最不糟糕的选择。
Aside from any performance arguments, passing around Methods or MethodHandles:
Also, as your code demonstrates, using Methods or MethodHandles doesn't particularly cut down on the amount of code required to declare an object approximating a first-class function:
Admittedly it's not as nice as a real lambda syntax, but the type-safety, refactoring benefits and ease of explanation make typing out those five lines the least-worst option much of the time.