Спецификация Java 11: 9.9. Типы функций

Тип функции функционального интерфейса I - это тип метода (§8.2), который может использоваться для переопределения (§8.4.8) абстрактного метода(ов) I.

Пусть M будет набором абстрактных методов, определенных для I. Тип функции I состоит из следующего:

  • Параметры типа, типы формальных параметров и тип возвращаемого значения:

    Пусть m - метод в M с:

    1. сигнатурой, которая является субсигнатурой каждой сигнатуры метода в M; и
    2. тип возврата R (возможно, void), где либо R совпадает с типом возвращаемого значения каждого метода в M, либо R является ссылочным типом и является подтипом каждого типа возвращаемого значения метода в M (после адаптации для любых параметров типа (§8.4.4), если оба метода имеют одинаковую сигнатуру).

    Если такого метода не существует, пусть m будет методом в M с:

    1. сигнатурой, которая является субсигнатурой каждой сигнатуры метода в M; и
    2. тип возвращаемого значения, такой что m может быть заменен типом возвращаемого значения (§8.4.5) для каждого метода в M.

    Параметры типа типа функции, типы формальных параметров и тип возвращаемого значения указаны в m.

  • предложения throws:

    Предложение throws для типа функции является производным от предложений throws методов в M следующим образом:

    1. Если тип функции является универсальным, предложения throws сначала адаптируются к параметрам типа типа функции (§8.4.4).

      Если тип функции не является универсальным, но хотя бы один метод в M является универсальным, сначала удаляются предложения throws.

    2. Затем предложение throws для типа функции включает каждый тип E, который удовлетворяет следующим ограничениям:
      • E упоминается в одном из пунктов throws.
      • Для каждого предложения throws E является подтипом некоторого типа, указанного в этом предложении.

Когда некоторые возвращаемые типы в M являются необработанными, а другие - нет, определение типа функции пытается выбрать наиболее конкретный тип, если это возможно. Например, если возвращаемыми типами являются LinkedList и LinkedList<String>, то последний сразу выбирается в качестве возвращаемого типа функции. Когда нет наиболее конкретного типа, определение компенсирует поиск наиболее заменяемого возвращаемого типа. Например, если существует третий тип возвращаемого значения, List<?>, то это не тот случай, когда один из возвращаемых типов является подтипом любого другого (поскольку необработанный LinkedList не является подтипом List<?>); вместо этого LinkedList<String> выбран в качестве типа возвращаемого значения функции, поскольку он может быть заменен типом возвращаемого значения как для LinkedList, так и для List<?>.

Целью определения типов исключений типа функции является поддержка инварианта, согласно которому метод с результирующим предложением throws может переопределять каждый абстрактный метод функционального интерфейса. Согласно §8.4.6, это означает, что тип функции не может генерировать "больше" исключений, чем любой отдельный метод в наборе M, поэтому мы ищем как можно больше типов исключений, которые "покрываются" предложением throws каждого метода.

Тип функции функционального типа интерфейса определяется следующим образом:

  • Тип функции типа неуниверсального функционального интерфейса I - это просто тип функции функционального интерфейса I, как определено выше.
  • Тип функции параметризованного функционального интерфейса типа I<A1...An>, где A1...An - типы, а соответствующие параметры типа I - P1...Pn, получается путем применения подстановки [P1:=A1, ..., Pn:=An] к типу функции универсального функционального интерфейса I<P1...Pn>.
  • Тип функции параметризованного функционального типа интерфейса I<A1...An>, где один или несколько из A1...An является подстановочным знаком, является типом функции параметризации без подстановочного символа I, I<T1...Tn>. Параметризация без подстановочных знаков определяется следующим образом.

    Пусть P1...Pn - параметры типа I с соответствующими границами B1...Bn. Для всех i (1 ≤ i ≤ n), Ti выводится в соответствии с формой Ai:

    • Если Ai тип, то Ti = Ai.
    • Если Ai - это подстановочный знак, а в граничном параметре соответствующего типа, Bi, упоминается одно из P1...Pn, тогда Ti не определен и тип функции отсутствует.
    • Иначе:
      • Если Ai - это несвязанный подстановочный знак ?, тогда Ti = Bi.
      • Если Ai - это подстановочный знак с ограничением сверху ? расширяет Ui, тогда Ti = glb(Ui, Bi) (§5.1.10).
      • Если Ai - ограниченный снизу подстановочный знак ? super Li, тогда Ti = Li.
  • Тип функции исходного типа универсального функционального интерфейса I<...> - это стирание типа функции универсального функционального интерфейса I<...>.
  • Тип функции типа пересечения, который индуцирует условный функциональный интерфейс, является типом функции условного функционального интерфейса.

Пример. Типы функций

Даны следующие интерфейсы:

interface X { void m() throws IOException; }
interface Y { void m() throws EOFException; }
interface Z { void m() throws ClassNotFoundException; }

тип функции:

interface XY extends X, Y {}

является:

()->void throws EOFException

а тип функции:

interface XYZ extends X, Y, Z {}

является:

()->void (throws nothing)

Даны следующие интерфейсы:

interface A {
    List<String> foo(List<String> arg)
      throws IOException, SQLTransientException;
}
interface B {
    List foo(List<String> arg)
      throws EOFException, SQLException, TimeoutException;
}
interface C {
    List foo(List arg) throws Exception;
}

тип функции:

interface D extends A, B {}

является:

(List<String>)->List<String>
  throws EOFException, SQLTransientException

а тип функции:

interface E extends A, B, C {}

является:

(List)->List throws EOFException, SQLTransientException

Тип функции функционального интерфейса определяется недетерминированно: хотя сигнатуры в M являются "одинаковыми", они могут быть синтаксически разными (например, HashMap.Entry и Map.Entry); тип возвращаемого значения может быть подтипом любого другого типа возвращаемого значения, но могут быть и другие типы возвращаемого значения, которые также являются подтипами (например, List<?> и List<? extends Object>); и порядок выбрасываемых типов не указан. Эти различия тонкие, но иногда они могут быть важными. Однако типы функций не используются в языке программирования Java таким образом, что недетерминизм имеет значение. Обратите внимание, что тип возвращаемого значения и предложение throws "наиболее конкретного метода" также определены недетерминированно, когда существует несколько абстрактных методов (§15.12.2.5).

Когда универсальный функциональный интерфейс параметризуется подстановочными знаками, существует множество различных экземпляров, которые могут удовлетворять подстановочному знаку и создавать разные типы функций. Например, каждый из Predicate<Integer> (тип функции Integer -> boolean), Predicate<Number> (тип функции Number -> boolean) и Predicate<Object> (тип функции Object -> boolean) является Predicate<? super Integer>. Иногда из контекста, такого как типы параметров лямбда-выражения, можно узнать, какой тип функции предназначен (§15.27.3). В других случаях необходимо выбрать один; в этих обстоятельствах используются границы. (Эта простая стратегия не может гарантировать, что результирующий тип будет удовлетворять определенным сложным ограничениям, поэтому не все сложные случаи поддерживаются.)

Пример. Типы общих функций

Тип функции может быть универсальным, так как абстрактный метод функционального интерфейса может быть универсальным. Например, в следующей иерархии интерфейсов:

interface G1 {
    <E extends Exception> Object m() throws E;
}
interface G2 {
    <F extends Exception> String m() throws Exception;
}
interface G extends G1, G2 {}

тип функции G:

<F extends Exception> ()->String throws F

Тип универсальной функции для функционального интерфейса может быть реализован с помощью выражения ссылки на метод (§15.13), но не с помощью лямбда-выражения (§15.27), поскольку нет синтаксиса для общих лямбда-выражений.


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки