Можно ли рассматривать Java MethodHandles так же, как функции первого класса? - PullRequest
9 голосов
/ 13 декабря 2011

Java Метод Класс и 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 ]

3 голосов
/ 13 декабря 2011

Помимо любых аргументов производительности, передавая методы или методы:

  • теряет любую безопасность во время компиляции:
    • количество аргументов;
    • типы аргументов;
    • существование самого метода (вы используете строковое имя, чтобы найти его).
  • теряет все объявленные проверенные исключения;
  • делает автоматизированнымрефакторинг сложнее.

Кроме того, как показывает ваш код, использование 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);
    }
}

По общему признанию, он не так хорош, как настоящий лямбда-синтаксис, но безопасность типов, преимущества рефакторинга и простота объяснения делают вывод этих пяти строк наименее худшим вариантом в большинстве случаев.

0 голосов
/ 13 декабря 2011

MethodHandles используют отражение, поэтому они медленны и не легко поддаются рефакторингу.Более того, Java получит лямбда-версии в своей версии 8, и это решит проблему функций первого класса в Java, поэтому я предполагаю, что разработчики библиотек предпочитают ждать Java 8, а не использовать какой-то обходной путь.

0 голосов
/ 13 декабря 2011

Метод класс имеет свое место, когда нужно использовать отражение, которое намного медленнее, чем обычный вызов метода.

MethodHandler является частью JSR292 .Он нацелен на людей, которые реализуют динамические языки для JVM.Вы можете прочитать больше об этом здесь .Это также не означает замену обычного вызова метода.

0 голосов
/ 13 декабря 2011

Используйте отражение только тогда, когда вам действительно нужно. Как вы можете видеть, вызовите throws Throwable, что означает, что вы не получите никакой хорошей обработки исключений. Также другие проверки времени компиляции будут отброшены.

...