2015-03-18 6 views
1

У меня есть несколько методов, которые отображаются на запросы сервера. Запросы используют promises (из Play Framework), чтобы возвращать ответы в будущем. Вот пример одного из моих действий:Лямбда-нотация - попытка рефакторинга, но получение проблем

public static Promise<Result> someAction() { 
    MyBean data = new MyBean(getData(request().body())); 
    Promise<MyReq> promise = Promise.promise(() -> new MyReq(data)); 
    return promise.map((MyReq req) -> ok(req.getResponse())); 
} 

Обратите внимание, что MyReq расширяет MyAbstractReq<T>.

То, что я надеялся сделать, состоял в том, чтобы убрать весь общий код из всех методов действий и расслоить его на один общий метод handleRequest. Однако я стараюсь понять Лямбда-нотацию и не могу изменить код в соответствии с моими целями.

Я понимаю, что () -> new MyReq(data) в основном означает (arg1, arg2, ...) -> { body }, которое можно записать как (я думаю):

MyBean data = new MyBean(getData(request().body())); 

// Anonymous Functional Interface 
MyFunction f = new MyFunction() {  
    @Override 
    public void getReq(){ 
     return new MyReq(data); 
    } 
}; 

Или что-то подобное.

Но что я пытаюсь достичь это что-то вроде этого (не компилируется, но я надеюсь, что это дает достаточно идеи, что я пытаюсь добиться):

public static Promise<Result> handleRequest(MyAbstractReq<?> req) { 
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req); 
    return promise.map(() -> ok(req.getResponse())); 
} 

и каждый внешний вид действий как это:

public static Promise<Result> someAction() { 
    MyBean data = new MyBean(getData(request().body())); 
    return handleRequest(new MyReq(data)); 
} 

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

Update

Ошибки я получаю

Lambda expression's signature does not match the signature of the functional interface method apply(? super MyAbstractReq<?>)

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

Метод req.getResponse() не очень актуальны, поскольку это просто создает объект JSON (ObjectNode - Джексон быстрее XML), который может потребляться методом ok() создать Result

Update 2

С что касается использования handleRequest(MyAbstractReq<T> req) У меня на самом деле было это, но ошибка была в основном одинаковой.

Lambda expression's signature does not match the signature of the functional interface method apply(? super MyAbstractReq<T>)

Update 3

Я прошу прощения.Ошибка находится на линии return promise.map(() -> ok(req.getResponse()));

Update 4

я, вероятно, следовало бы отметить, что я знаю, как решить эту проблему путем изменения метода handleRequest() к:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) { 
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req); 
    return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse())); 
} 

Но он чувствует себя неправильно поскольку строка return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse())); принимает аргумент MyAbstractReq<?>, который никогда не используется.

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

+2

В чем проблема? Есть ли ошибка? Где определяется метод 'getResponse()'? –

+0

Я обновил вопрос, чтобы ответить на ваши комментарии. Что касается того, что он имеет отношение к выражениям лямбда, я пытаюсь реорганизовать лямбда-выражения, но я не знаю, как это сделать. Ошибки указывают на наличие ошибки в сигнатуре выражения Lambda. – Neilos

+0

Если мой вопрос непонятен, то я был бы признателен, если бы вы могли сказать мне, какие части вы не понимаете, чтобы я мог прояснить. – Neilos

ответ

2

В вашем исходного кода

public static Promise<Result> someAction() { 
    MyBean data = new MyBean(getData(request().body())); 
    Promise<MyReq> promise = Promise.promise(() -> new MyReq(data)); 
    return promise.map((MyReq req) -> ok(req.getResponse())); 
} 

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

public static Promise<Result> handleRequest(MyAbstractReq<?> req) { 
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req); 
    // the following function refers to handleRequest’s parameter instead of its argument 
    return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse())); 
} 

Это работает в этом особом случае, но это действительно так неправильно, как ваше чувство говорит вам.

Просто остаться с оригинальной логикой здесь:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) { 
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req); 
    // arg is unrelated to req here though both variables happen to have to same contents 
    return promise.map(arg -> ok(arg.getResponse())); 
} 

, но это все еще немного странно, как обещание строится вокруг уже существующего объекта, а не его построения. Может быть, вы хотите

public static Promise<Result> handleRequest(Function0<MyAbstractReq<?>> supplier) { 
    Promise<MyAbstractReq<?>> promise = Promise.promise(supplier); 
    return promise.map(arg -> ok(arg.getResponse())); 
} 

так что вы можете назвать это как

handleRequest(()-> new MyReq(new MyBean(getData(request().body())))); 

, как тогда Promise действительно покрывает всю операцию.

+0

«arg не связан с req здесь, хотя обе переменные имеют одинаковое содержимое». Я не уверен, что понимаю, почему это так. Это потому, что я передаю 'req', чтобы пообещать, а затем, когда вызывается' prom.map', он использует значение 'req' и передает его в качестве аргумента функции? Но это создало бы тот же объект. Это копия или что-то еще? – Neilos

+0

", как тогда обещание действительно будет охватывать всю операцию« Я действительно задавался вопросом, должно ли создание объекта быть в обещании, а не раньше. Я думаю, что этот момент на самом деле является причиной того, что вся проблема возникла для меня, когда я изменил ее, чтобы произойти раньше (я действительно не знал, как это сделать в противном случае). Спасибо что подметил это. – Neilos

+1

Аргумент функции сопоставления будет содержать * копию ссылки *, возвращаемую функцией поставщика, поэтому он указывает на тот же экземпляр объекта. Таким образом, это один и тот же объект, но выбор переменной делает огромную семантическую разницу, поскольку «arg -> ok (arg.getResponse()) - это функция, которая работает над своим аргументом, а' notUsed -> ok (req.getResponse()) '- функция, которая работает с несвязанным объектом, захваченным при создании экземпляра лямбда. – Holger

2

Теперь после обновления 2, вы придумали следующий метод:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) {= 
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req); 
    return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse())); 
} 

Прежде чем продолжить, позвольте мне объяснить, что map() делает. При заданном Iterable, когда применяется, map() просто преобразует каждый элемент в нечто другое (которое может быть извлечено из элемента). Для этого мы передаем Function методу map(), который принимает вход и возвращает выход.

В этом случае (MyAbstractReq<?> notUsed) -> ok(req.getResponse()) - это функция. Берет notUsed в качестве аргумента (который один элемент из promise и вызвать метод ok() по реакции этого объекта.

Но вы видите, что вы не используете аргумент, который вы передаёте, но другой объект (тот, который вы прошли в качестве аргумента handleRequest() метода. это не так. вы должны использовать notUsed.getResponse() там.

Кроме того, вам не нужно давать тип notUsed там. Java может определить тип.Итак, измените свой метод на:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) {= 
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req); 
    return promise.map(promReq -> ok(promReq.getResponse())); 
} 
+0

Что я не понимаю, так это то, как 'req' и' promReq' содержат одни и те же данные ... являются ли они тем же самым объектом, который только что хранится как ссылка внутри обещания? – Neilos

+1

@Neilos Это будет зависеть от метода 'Promise.promise()'. Он принимает функцию, которая просто возвращает 'req', который вы передали. Теперь, что он делает с 'req', я не знаю. Если он не создает новый объект, то да и ссылки 'req' и' promReq' указывают на тот же объект. –

+0

Если бы я мог принять два ответа, я бы тоже принял это. – Neilos

Смежные вопросы