Ответ 1
Этот вопрос может быть истолкован относительно спецификации или реализации. Очевидно, реализации могут измениться, но вы можете захотеть переписать свой код, когда это произойдет, поэтому я отвечу на обоих.
Это также зависит от того, что вы хотите сделать. Вы хотите оптимизировать или ищете надежные гарантии того, что два экземпляра (или не являются) одной и той же функцией? (Если последнее, вы столкнетесь с вычислительной физикой, в том, что даже проблемы, столь же простые, как вопрос о том, могут ли две функции вычислять одно и то же, неразрешимы.)
С точки зрения спецификации спецификация языка promises состоит только в том, что результат вычисления (не вызова) лямбда-выражения является экземпляром класса, реализующего целевой функциональный интерфейс. Он не делает promises об идентичности или степени сглаживания результата. Это по дизайну, чтобы обеспечить максимальную гибкость реализации, чтобы обеспечить лучшую производительность (так как lambdas может быть быстрее, чем внутренние классы, мы не привязаны к ограничению "необходимо создать уникальный экземпляр", который содержит внутренние классы.)
В принципе, спецификация не дает вам многого, кроме, очевидно, что две lambdas, которые являются ссылочными (==), собираются вычислить одну и ту же функцию.
С точки зрения реализации вы можете сделать еще несколько. Существует (в настоящее время может измениться) соотношение 1:1 между синтетическими классами, которые реализуют лямбда, и местами захвата в программе. Таким образом, два отдельных бита кода, которые захватывают "x → x + 1", могут быть сопоставлены с разными классами. Но если вы оцениваете одну и ту же лямбду на том же участке захвата и что лямбда не захватывает, вы получаете тот же экземпляр, который можно сравнить с эталонным равенством.
Если ваши лямбды являются сериализуемыми, они с легкостью откажутся от своего состояния в обмен на жертву какой-то производительности и безопасности (без бесплатного обеда.)
Одна из областей, где было бы целесообразно настроить определение равенства, - это ссылки на методы, поскольку это позволит им использоваться в качестве слушателей и быть должным образом незарегистрированным. Это рассматривается.
Я думаю, что вы пытаетесь понять: если два лямбда преобразуются в один и тот же функциональный интерфейс, они представлены одной и той же функцией поведения и имеют одинаковые захваченные аргументы, они одинаковы
К сожалению, это трудно сделать (для несериализуемых lambdas, вы не можете получить на всех его компонентах) и недостаточно (поскольку два отдельно скомпилированных файла могут преобразовывать один и тот же лямбда в один и тот же тип функционального интерфейса, и вы не сможете сказать.)
EG обсудила вопрос о том, следует ли предоставлять достаточную информацию, чтобы иметь возможность делать эти суждения, а также обсуждать, следует ли lambdas применять более выборочные equals/hashCode или более описательные toString. Вывод состоял в том, что мы не желали платить что-либо по стоимости исполнения, чтобы сделать эту информацию доступной для вызывающего абонента (плохой компромисс, наказывая 99,99% пользователей за то, что выгодно 0,01%).
Окончательный вывод о toString не был достигнут, но остался открытым для пересмотра в будущем. Однако по этому вопросу были высказаны хорошие аргументы в пользу обеих сторон; это не шлепанье.