Java MethodHandles可以被认为与第一类函数相同吗?

时间:2011-12-13 02:27:10

标签: java java-7 higher-order-functions

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));
}
}

更新

在做了一些基准测试之后,我注意到MethodHandle比Reflection的方法更快,但仍然远不如常规方法调用快。也许对于方法调用,JVM可以应用一些句柄无法实现的优化。

4 个答案:

答案 0 :(得分:3)

除了任何性能参数,传递方法或方法手柄:

  • 失去编译时的安全性:
    • 参数数量;
    • 参数类型;
    • 方法本身的存在(使用字符串名称来查找它)。
  • 丢失任何已声明的已检查异常;
  • 使自动重构变得更加困难。

此外,正如您的代码所示,使用Methods或MethodHandles并没有特别减少声明一个接近一等函数的对象所需的代码量:

// you could even use the Function types from Guava...
interface Func<In, Out> {
    Out apply(In in);
}

// create a new "function" object in 5 lines of code:
Func<String, Integer> parseInt = new Func<String, Integer> {
    public Integer apply(String in) {
        return Integer.parseInt(in);
    }
}

不可否认,它不如真正的lambda语法那么好,但是类型安全,重构的好处和易于解释使得在这五行中输入最不可能的选项。

答案 1 :(得分:0)

只在您真正需要时才使用反射。 正如你所看到的,调用thrrow Throwable意味着你没有真正好的异常处理。 其他编译时间检查也将被丢弃。

答案 2 :(得分:0)

当需要使用反射时,

Method类有它的位置,这比常规方法调用要慢得多。

MethodHandlerJSR 292的一部分。它针对为JVM实现动态语言的人员。您可以阅读更多相关信息here。它并不意味着要替换常规方法调用。

答案 3 :(得分:0)

MethodHandles使用反射,因此它们变慢并且不易重构。此外,Java将在其版本8中获得lambdas,这将解决Java中的第一类函数的问题,因此我认为库编写者更喜欢等待Java 8而不是使用某种解决方法。