Есть ли способ сравнить lambda?

Скажем, у меня есть список объектов, которые были определены с использованием lambda-выражений (замыканий). Есть ли способ проверить их, чтобы их можно было сравнить?

Код, который меня больше всего интересует, это

List strategies = getStrategies(); Strategy a = (Strategy) this::a; if (strategies.contains(a)) { // ... 

Полный код

 import java.util.Arrays; import java.util.List; public class ClosureEqualsMain { interface Strategy { void invoke(/*args*/); default boolean equals(Object o) { // doesn't compile return Closures.equals(this, o); } } public void a() { } public void b() { } public void c() { } public List getStrategies() { return Arrays.asList(this::a, this::b, this::c); } private void testStrategies() { List strategies = getStrategies(); System.out.println(strategies); Strategy a = (Strategy) this::a; // prints false System.out.println("strategies.contains(this::a) is " + strategies.contains(a)); } public static void main(String... ignored) { new ClosureEqualsMain().testStrategies(); } enum Closures {; public static  boolean equals(Closure c1, Closure c2) { // This doesn't compare the contents // like others immutables eg String return c1.equals(c2); } public static  int hashCode(Closure c) { return // a hashCode which can detect duplicates for a Set } public static  String asString(Closure c) { return // something better than Object.toString(); } } public String toString() { return "my-ClosureEqualsMain"; } } 

Кажется, единственное решение – определить каждую лямбду как поле и использовать только эти поля. Если вы хотите распечатать вызванный метод, вам лучше использовать Method . Есть ли лучший способ с lambda-выражениями?

Кроме того, можно ли распечатать лямбду и получить что-то читаемое человеком? Если вы напечатаете this::a вместо

 ClosureEqualsMain$$Lambda$1/821270929@3f99bd52 

получить что-то вроде

 ClosureEqualsMain.a() 

или даже использовать this.toString и метод.

 my-ClosureEqualsMain.a(); 

3 Solutions collect form web for “Есть ли способ сравнить lambda?”

Этот вопрос может быть истолкован относительно спецификации или реализации. Очевидно, реализации могут измениться, но вы можете захотеть переписать свой код, когда это произойдет, поэтому я отвечу на обоих.

Это также зависит от того, что вы хотите сделать. Вы хотите оптимизировать или ищете надежные гарантии того, что два экземпляра (или не являются) одной и той же функцией? (Если последнее, вы столкнетесь с вычислительной физикой, в том, что даже проблемы, столь же простые, как вопрос о том, могут ли две функции вычислять одну и ту же вещь, неразрешимы.)

С точки зрения спецификации языковая спецификация обещает только, что результат вычисления (не вызывая) lambda-выражения является экземпляром classа, реализующего целевой функциональный интерфейс. Он не дает никаких обещаний относительно идентичности или степени сглаживания результата. Это по дизайну, чтобы обеспечить максимальную гибкость реализации, чтобы предлагать лучшую производительность (так как lambdas может быть быстрее, чем внутренние classы, мы не привязаны к ограничению «должен создать уникальный экземпляр», что и внутренние classы).

Так что в принципе, спецификация не дает вам многого, кроме, очевидно, что два lambdas, которые являются ссылочными (==), собираются вычислить одну и ту же функцию.

С точки зрения реализации вы можете сделать еще немного. Существует (в настоящее время может измениться) соотношение 1: 1 между синтетическими classами, которые реализуют lambda, и местами захвата в программе. Таким образом, два отдельных бита кода, которые захватывают «x -> x + 1», могут быть сопоставлены с разными classами. Но если вы оцениваете одну и ту же лямбду на том же участке захвата и что lambda не захватывает, вы получаете тот же экземпляр, который можно сравнить с эталонным равенством.

Если ваши лямбды становятся сериализуемыми, они легче сдадут свое состояние в обмен на жертву какой-то производительности и безопасности (без бесплатного обеда).

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

Я думаю, что вы пытаетесь добиться: если два lambda преобразуются в один и тот же функциональный интерфейс, они представлены одной и той же функцией поведения и имеют одинаковые захваченные аргументы, они одинаковы

К сожалению, это трудно сделать (для несериализуемых lambdas, вы не можете получить на всех его компонентах) и недостаточно (потому что два отдельно скомпилированных файла могут преобразовать одну и ту же лямбду в один и тот же тип функционального интерфейса, и вы бы не могу сказать.)

EG обсудила вопрос о том, следует ли предоставлять достаточную информацию для принятия этих суждений, а также обсуждать, следует ли lambdas применять более выборочные equals / hashCode или более описательные toString. Вывод состоял в том, что мы не желали платить что-либо по стоимости исполнения, чтобы сделать эту информацию доступной для вызывающего абонента (плохой компромисс, наказывая 99,99% пользователей за то, что выгодно 0,01%).

Окончательный вывод о toString не был достигнут, но остался открытым для пересмотра в будущем. Однако по этому вопросу были высказаны хорошие аргументы в пользу обеих сторон; это не шлепанье.

Я не вижу возможности, чтобы получить информацию от самого закрытия. Закрытие не обеспечивает состояние.

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

Для сравнения labmdas я обычно позволяю интерфейсу расширять Serializable а затем сравнивать сериализованные байты. Не очень приятно, но работает в большинстве случаев.

  • Что такое lambda?
  • Как произносится «=>» как используется в lambda-выражениях в .Net
  • Необязательный orElse Необязательный в Java
  • ключевое слово delegate или lambda
  • Comparator.reversed () не компилируется с использованием lambda
  • Перечислить сложную сортировку
  • Java8 Lambdas против анонимных classов
  • MVC HTML Helpers и выражения lambda
  • Когда фигурные скобки необязательны в синтаксисе lambda Java 8?
  • Использование переменной iteratorа цикла foreach в выражении lambda - почему не удается?
  • Construct LambdaExpression для вложенного свойства из строки
  • Interesting Posts

    Как провайдер определяет правильную скорость моего интернет-плана?

    Gdb печатать в файл вместо stdout

    Изменение разрешения экрана гостевого экрана MacOS X для VirtualBox

    Как я могу реализовать пользовательскую атомную функцию с несколькими переменными?

    Как загрузить файл в Angular2

    Как получить список файлов и размеров, которые учитываются в моем аккаунте в Dropbox?

    Уменьшение переключения режима видео во время загрузки Linux

    Как добавить элемент в ListBox в C # и WinForms?

    Каково теоретическое максимальное количество открытых TCP-соединений, которые может иметь современный ящик Linux

    css трансформировать, зубчатые края в хроме

    Как я могу запретить Windows запрашивать перезагрузку моего компьютера после обновления?

    Скрипт Vim, который проверяет заглавные буквы и вносит необходимые исправления

    Android: setSelection не влияет на Spinner

    Каковы недостатки (если они есть) доступа к Интернету через два или более «цепных» маршрутизатора?

    (Устаревший) Фрагмент onOptionsItemSelected не вызывается

    Давайте будем гением компьютера.