Почему ActionListener не использует аннотацию @FunctionalInterface? [Дубликат]

== выполняет контрольную проверку равенства, ссылаясь на то, что 2 объекта (строки в этом случае) относятся к одному и тому же объекту в памяти.

Метод equals() будет проверять, будет ли содержимое или состояния двух объектов одинаковы.

Очевидно, что == работает быстрее, но во многих случаях может (может) давать ложные результаты, если вы просто хотите сказать, имеет ли 2 String s тот же текст.

Определенно рекомендуется использовать метод equals().

Не беспокойтесь о производительности. Некоторые способы поощрения использования String.equals():

  1. Реализация String.equals() сначала проверяет ссылочное равенство (используя ==), и если две строки одинаковы по ссылке, дальнейший расчет Выполняется!
  2. Если 2 ссылки на строки не совпадают, String.equals() будет проверять длину строк. Это также является быстрой операцией, поскольку класс String хранит длину строки, не нужно считать символы или кодовые точки. Если длины отличаются, дальнейшая проверка не выполняется, мы знаем, что они не могут быть равными.
  3. Только если мы доберемся до этого, будет фактически сопоставлено содержимое двух строк, и это будет короткий сравнение: не все символы будут сравниваться, если мы найдем несоответствующий символ (в том же положении в 2 строках), никакие другие символы не будут проверены.

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

15
задан candied_orange 12 November 2017 в 23:38
поделиться

3 ответа

Ну, аннотация, документирующая намерение, была бы бесполезной, если вы предполагаете, что всегда есть это намерение.

Вы назвали пример AutoCloseable, который, очевидно, не предназначен который будет реализован как функция, так как существует Runnable, что намного удобнее для функции с сигнатурой ()->void. Предполагается, что класс, реализующий AutoCloseable, управляет внешним ресурсом, который анонимные классы, реализованные с помощью лямбда-выражения, не выполняет.

Более ясным примером является Comparable, а interface не только не предназначено реализованный в виде лямбда-выражения, невозможно реализовать его правильно с использованием лямбда-выражения.


Возможные причины не отмечать interface с помощью @FunctionalInterface на примере:

  • interface имеет семантику языка программирования, например AutoClosable или Iterable (это вряд ли произойдет для ваших собственных интерфейсов)
  • Не ожидается, что interface имеет произвольные реализации и / или больше идентификатор, чем фактическая реализация, например. java.net.ProtocolFamily или java.lang.reflect.GenericArrayType (обратите внимание, что последний также наследует реализацию default для getTypeName(), которая бесполезна для лямбда-реализаций, полагаясь на toString())
  • . Случаи этого interface ] должны иметь личность, например java.net.ProtocolFamily, java.nio.file.WatchEvent.Modifier и т. д. Обратите внимание, что они обычно реализуются с помощью enum. Другим примером является java.time.chrono.Era, который имеет только один метод abstract, но его спецификация говорит: Экземпляры Era можно сравнить с помощью оператора ==. »
  • interface предназначен для изменения поведения операции, для которой реализация interface не наследует / реализует что-либо иначе не имеет смысла, например java.rmi.server.Unreferenced
  • Это абстракция общих операций классов, которые должны иметь не только эти операции, например. java.io.Closeable, java.io.Flushable, java.lang.Readable
  • Ожидаемое наследование является частью контракта и запрещает реализацию лямбда-выражения, например. в java.awt: ActiveEvent должен быть реализован с помощью AWTEvent, PrinterGraphics на Graphics, то же самое относится к java.awt.print.PrinterGraphics (эй, два interface s для точно такой же вещи ...), javax.print.FlavorException должен быть реализован подклассом javax.print.PrintException
  • Я не знаю, не связаны ли различные интерфейсы прослушивателя событий с @FunctionalInterface для симметрии с другим прослушивателем событий нескольких методов, t функциональные интерфейсы, но на самом деле прослушиватели событий являются хорошими кандидатами на лямбда-выражения. Если вы хотите удалить слушателя позднее, вы должны сохранить экземпляр, но это не отличается от, например, (g12)
  • У хранителя библиотеки есть большая база кода с более чем 200 типами кандидатов, а не ресурсы для обсуждения для каждого interface, следует ли ее аннотировать и, следовательно, сосредоточить внимание на основных кандидатах на то, чтобы быть используется в функциональном контексте. Я уверен, что, например, java.io.ObjectInputValidation, java.lang.reflect.InvocationHandler, juc RejectedExecutionHandler & amp; ThreadFactory не будет плохой как @FunctionalInterface, но я не знаю, будет ли, например. java.security.spec.ECField делает хорошего кандидата. Чем более общей является библиотека, тем более вероятным пользователям библиотеки будет возможность ответить на этот вопрос для конкретного interface, который им интересен, но было бы несправедливо настаивать на том, чтобы разработчик библиотеки ответил на него для все . В этом контексте имеет смысл видеть присутствие @FunctionalInterface в качестве сообщения о том, что interface определенно предназначено для использования вместе с лямбда-выражениями, чем рассматривать отсутствие аннотации в качестве индикатора того, что он не предназначен для использования таким образом. Это точно так же, как компилятор справляется с этим, вы можете реализовать каждый абстрактный метод interface с использованием лямбда-выражения, но когда присутствует аннотация, гарантирует , что вы можете использовать этот interface в этом путь.
19
ответ дан Holger 15 August 2018 в 14:25
поделиться
  • 1
    Эта. Разумеется, не «будущее расширение». – Boris the Spider 27 January 2015 в 09:48
  • 2
    Но компаратор может. Это связано с методами по умолчанию в компараторе? – candied_orange 27 January 2015 в 10:25
  • 3
    @CandiedOrange Comparator принимает два типа T и сравнивает их - это ToIntBiFunction<T,T> . Comparable сравнивает сам с каким-либо другим типом - у лямбды (почти) нет чувства самости, поэтому это невозможно реализовать в качестве лямбда. – Boris the Spider 27 January 2015 в 10:31
  • 4
    @CandiedOrange: контракт Comparable требует симметрии, т. Е. a.compareTo(b) == -b.compareTo(a), что невозможно гарантировать лямбда-выражение; вы даже не можете объявить лямбду реализовать Comparable<T>, когда T является классом лямбда, поскольку класс лямбда не указан. – Holger 27 January 2015 в 10:34
  • 5
    @CandiedOrange: не предназначается как функциональный интерфейс, не мешает вам реализовать этот интерфейс с помощью выражения лямбда или ссылки на метод. Я уже делал это с AutoClosable и Iterable, хотя я знаю, что это не входит в рамки намерений создателя интерфейса. Всегда есть намеренное использование и фактическое использование, и вы должны быть осторожны, чтобы не двигаться слишком далеко от предполагаемого использования, однако было бы странно, если бы мы все были всегда на пути, предвиденном основными разработчиками ... – Holger 27 January 2015 в 10:48

Планируемое расширение. Просто потому, что интерфейс соответствует требованиям SMI, теперь не означает, что расширение не понадобится позже.

2
ответ дан candied_orange 15 August 2018 в 14:25
поделиться
  • 1
    Добавление методов abstract к interface в любом случае нарушает совместимость. Он сомневается, что есть планы сделать это. – Holger 27 January 2015 в 09:45
  • 2
    А именно, набор всех функциональных интерфейсов является правильным подмножеством множества всех типов SAM. Различие заключается в намерении, а не в структуре. – Edwin Dalorzo 27 January 2015 в 22:41
  • 3
    @Holger, что вы говорите, верно для отдельно опубликованных библиотек (таких как JDK, Guava, Apache Commons и т. Д.), Но не относится ко всем кодам. Есть много кодовых баз, которые готовы внести изменения, которые могут быть несовместимыми с бинарными или исходными текстами, и могут уйти от него, потому что они имеют закрытую исходную базу и перекомпилируют все с нуля. В этот момент этот ответ применяется отлично. – Brian Goetz 28 January 2015 в 17:47
  • 4
    @Brian Goetz: но в этом случае вы также можете добавить @FunctionalInterface в interface и удалить его в более поздней версии, не нарушая ничего. Но это не отвечает на вопрос , который посвящен API JDK – Holger 28 January 2015 в 17:57

В java 8 функциональный интерфейс представляет собой интерфейс, имеющий только один абстрактный метод, называемый функциональным методом, к которому сопоставляются параметр и тип возвращаемого выражения lambda.

java.util.function содержит функциональные интерфейсы общего назначения, используемые JDK, а также для конечных пользователей. Хотя они не являются полным набором функциональных интерфейсов, к которым могут быть применены лямбда-выражения, но они обеспечивают достаточно для удовлетворения общих требований.

Существует множество таких интерфейсов, которые заслуживают того, чтобы их можно было назвать функциональным интерфейсом, но пакет java.util.function уже предоставляет функциональные интерфейсы для наших почти всех

Например, посмотрите на следующий код.

public interface Comparable<T> {
   public int compareTo(T o);
}

@FunctionalInterface
public interface ToIntFunction<T> {
   int applyAsInt(T value);
}

public static void main(String[] args){
   ToIntFunction<String> f = str -> Integer.parseInt(str);
   Comparable<String> c = str -> Integer.parseInt(str);
}

Comparable также может взять объект и получить некоторое значение типа int, но есть более общий выделенный интерфейс ToIntFunction для выполнения этой задачи. Нет такого жесткого правила, что все заслуживающие интерфейсы должны быть аннотированы с помощью @FunctionalInterface, но чтобы получить преимущество лямбда-функции, интерфейс должен выполнять все критерии, определенные FunctionalInterface.

0
ответ дан sanit 15 August 2018 в 14:25
поделиться
  • 1
    Речь идет не о том, какой из них более общий, чем другой - может быть полезно иметь более конкретный функциональный интерфейс для конкретных целей. Таким образом, речь идет о самой цели. Нет смысла реализовывать Comparable с выражением лямбда, и ваш пример просто показывает недопустимую реализацию, пытаясь это сделать. – Didier L 28 January 2018 в 14:02
Другие вопросы по тегам:

Похожие вопросы: