Приведение объектов функционального интерфейса

Я столкнулся со следующим кодом в проекте Java, и я не уверен, что с ним делать:

public Function<CustomEnum,String> foo(SomeObject someObject) {
    return ((Function<CustomEnum,String>) (someObject::toString)).andThen(r -> someObject::getSomethingWithEnumParameter);
}

Я действительно не понимаю, как вы можете передать что-то функциональному интерфейсу. Что это хотя бы значит?

Разве результирующий тип возвращаемого значения не будет любым значением someObject.

Разве Function<CustomEnum, String> не определяет анонимную функцию, которая принимает тип CustomEnum и возвращает String?

Я прочитал документацию по Java для Function<T,R>, и, честно говоря, это не имеет большего смысла, чем до того, как я прочитал документ.

Это то, что я считаю, происходит.

  1. foo возвращает анонимную функцию, которая применяется к некоторому CustomEnum для возврата строки

  2. анонимная функция внутри foo (которая каким-то образом приводится к someObject::toString, чего я не понимаю) применяется к CustomEnum, которая будет передана из начального вызова foo(someObject).apply(customEnum).

  3. andThen возьмет результирующую строку из анонимной функции внутри foo (которая была приведена каким-то образом, я до сих пор не понимаю), а затем вернет значение someObject::getSomethingWithEnumParameter. Почему возвращаемый тип не является просто типом someObject::getSomethingWithEnumParameter, который мы будем называть Map<R,T>, ради обсуждения.

Если бы кто-нибудь мог помочь мне понять этот поток, я был бы очень признателен.


person george_curious    schedule 09.01.2017    source источник
comment
Этот код отвратительный, и если бы этот разработчик был в моей команде, я бы серьезно поговорил с ним/ней. Правильный способ добиться этого — создать отдельный метод с телом return someObject.getSomethingWithEnumParam(someObject.toString());, чтобы простая ссылка на этот метод могла использоваться как функция.   -  person VGR    schedule 10.01.2017


Ответы (1)


В идеальном мире это сработает:

public Function<CustomEnum,String> foo(SomeObject someObject) {
    return (someObject::toString).andThen(...);
}

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

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

Разбивая это:

someObject::toString — это ссылка на метод с подразумеваемым типом Function<CustomEnum, String>. т.е. toString — это метод для SomeObject, который принимает параметр типа CustomEnum и возвращает String.

Однако r -> someObject::getSomethingWithEnumParameter имеет неправильный тип — это функция, которая возвращает функцию. Если вы избавитесь от части "r ->", тогда она действительна, пока someObject::getSomethingWithEnumParameter является методом для SomeObject, который принимает String и возвращает String. В качестве альтернативы тип возвращаемого значения foo необходимо изменить на Function<CustomEnum, Function<String, String>>.

Если вы объедините эти два с andThen, тогда у вас будет Function, который принимает CustomEnum и возвращает String, как pr возвращаемый тип foo.

person jon-hanson    schedule 09.01.2017